Completed
Branch BUG/11442/session-lifespan (892d24)
by
unknown
60:04 queued 47:13
created
modules/ticket_sales_monitor/EED_Ticket_Sales_Monitor.module.php 2 patches
Indentation   +1050 added lines, -1050 removed lines patch added patch discarded remove patch
@@ -24,1057 +24,1057 @@
 block discarded – undo
24 24
 class EED_Ticket_Sales_Monitor extends EED_Module
25 25
 {
26 26
 
27
-    const debug = false;    //	true false
28
-
29
-    /**
30
-     * an array of raw ticket data from EED_Ticket_Selector
31
-     *
32
-     * @var array $ticket_selections
33
-     */
34
-    protected $ticket_selections = array();
35
-
36
-    /**
37
-     * the raw ticket data from EED_Ticket_Selector is organized in rows
38
-     * according to how they are displayed in the actual Ticket_Selector
39
-     * this tracks the current row being processed
40
-     *
41
-     * @var int $current_row
42
-     */
43
-    protected $current_row = 0;
44
-
45
-    /**
46
-     * an array for tracking names of tickets that have sold out
47
-     *
48
-     * @var array $sold_out_tickets
49
-     */
50
-    protected $sold_out_tickets = array();
51
-
52
-    /**
53
-     * an array for tracking names of tickets that have had their quantities reduced
54
-     *
55
-     * @var array $decremented_tickets
56
-     */
57
-    protected $decremented_tickets = array();
58
-
59
-
60
-
61
-    /**
62
-     * set_hooks - for hooking into EE Core, other modules, etc
63
-     *
64
-     * @return    void
65
-     */
66
-    public static function set_hooks()
67
-    {
68
-        // release tickets for expired carts
69
-        add_action(
70
-            'EED_Ticket_Selector__process_ticket_selections__before',
71
-            array('EED_Ticket_Sales_Monitor', 'release_tickets_for_expired_carts'),
72
-            1
73
-        );
74
-        // check ticket reserves AFTER MER does it's check (hence priority 20)
75
-        add_filter(
76
-            'FHEE__EE_Ticket_Selector___add_ticket_to_cart__ticket_qty',
77
-            array('EED_Ticket_Sales_Monitor', 'validate_ticket_sale'),
78
-            20,
79
-            3
80
-        );
81
-        // add notices for sold out tickets
82
-        add_action(
83
-            'AHEE__EE_Ticket_Selector__process_ticket_selections__after_tickets_added_to_cart',
84
-            array('EED_Ticket_Sales_Monitor', 'post_notices'),
85
-            10
86
-        );
87
-        // handle ticket quantities adjusted in cart
88
-        //add_action(
89
-        //	'FHEE__EED_Multi_Event_Registration__adjust_line_item_quantity__line_item_quantity_updated',
90
-        //	array( 'EED_Ticket_Sales_Monitor', 'ticket_quantity_updated' ),
91
-        //	10, 2
92
-        //);
93
-        // handle tickets deleted from cart
94
-        add_action(
95
-            'FHEE__EED_Multi_Event_Registration__delete_ticket__ticket_removed_from_cart',
96
-            array('EED_Ticket_Sales_Monitor', 'ticket_removed_from_cart'),
97
-            10,
98
-            2
99
-        );
100
-        // handle emptied carts
101
-        add_action(
102
-            'AHEE__EE_Session__reset_cart__before_reset',
103
-            array('EED_Ticket_Sales_Monitor', 'session_cart_reset'),
104
-            10,
105
-            1
106
-        );
107
-        add_action(
108
-            'AHEE__EED_Multi_Event_Registration__empty_event_cart__before_delete_cart',
109
-            array('EED_Ticket_Sales_Monitor', 'session_cart_reset'),
110
-            10,
111
-            1
112
-        );
113
-        // handle cancelled registrations
114
-        add_action(
115
-            'AHEE__EE_Session__reset_checkout__before_reset',
116
-            array('EED_Ticket_Sales_Monitor', 'session_checkout_reset'),
117
-            10,
118
-            1
119
-        );
120
-        // cron tasks
121
-        add_action(
122
-            'AHEE__EE_Cron_Tasks__process_expired_transactions__abandoned_transaction',
123
-            array('EED_Ticket_Sales_Monitor', 'process_abandoned_transactions'),
124
-            10,
125
-            1
126
-        );
127
-        add_action(
128
-            'AHEE__EE_Cron_Tasks__process_expired_transactions__incomplete_transaction',
129
-            array('EED_Ticket_Sales_Monitor', 'process_abandoned_transactions'),
130
-            10,
131
-            1
132
-        );
133
-        add_action(
134
-            'AHEE__EE_Cron_Tasks__process_expired_transactions__failed_transaction',
135
-            array('EED_Ticket_Sales_Monitor', 'process_failed_transactions'),
136
-            10,
137
-            1
138
-        );
139
-    }
140
-
141
-
142
-
143
-    /**
144
-     * set_hooks_admin - for hooking into EE Admin Core, other modules, etc
145
-     *
146
-     * @return void
147
-     */
148
-    public static function set_hooks_admin()
149
-    {
150
-        EED_Ticket_Sales_Monitor::set_hooks();
151
-    }
152
-
153
-
154
-
155
-    /**
156
-     * @return EED_Ticket_Sales_Monitor|EED_Module
157
-     */
158
-    public static function instance()
159
-    {
160
-        return parent::get_instance(__CLASS__);
161
-    }
162
-
163
-
164
-
165
-    /**
166
-     * @param WP_Query $WP_Query
167
-     * @return    void
168
-     */
169
-    public function run($WP_Query)
170
-    {
171
-    }
172
-
173
-
174
-
175
-    /********************************** PRE_TICKET_SALES  **********************************/
176
-
177
-
178
-
179
-    /**
180
-     * Retrieves grand totals from the line items that have no TXN ID
181
-     * and timestamps less than the current time minus the session lifespan.
182
-     * These are carts that have been abandoned before the "registrant" even attempted to checkout.
183
-     * We're going to release the tickets for these line items before attempting to add more to the cart.
184
-     *
185
-     * @return void
186
-     * @throws DomainException
187
-     * @throws EE_Error
188
-     * @throws InvalidArgumentException
189
-     * @throws InvalidDataTypeException
190
-     * @throws InvalidInterfaceException
191
-     * @throws UnexpectedEntityException
192
-     */
193
-    public static function release_tickets_for_expired_carts()
194
-    {
195
-        do_action('AHEE__EED_Ticket_Sales_Monitor__release_tickets_for_expired_carts__begin');
196
-        $expired_ticket_IDs      = array();
197
-        $valid_ticket_line_items = array();
198
-        $total_line_items        = EEM_Line_Item::instance()->get_total_line_items_with_no_transaction();
199
-        if (empty($total_line_items)) {
200
-            do_action(
201
-                'AHEE__EED_Ticket_Sales_Monitor__release_tickets_for_expired_carts__end',
202
-                $total_line_items,
203
-                $valid_ticket_line_items,
204
-                $expired_ticket_IDs
205
-            );
206
-            return;
207
-        }
208
-        /** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */
209
-        $session_lifespan = LoaderFactory::getLoader()->getShared(
210
-            'EventEspresso\core\domain\values\session\SessionLifespan'
211
-        );
212
-        foreach ($total_line_items as $total_line_item) {
213
-            /** @var EE_Line_Item $total_line_item */
214
-            $ticket_line_items = EED_Ticket_Sales_Monitor::get_ticket_line_items_for_grand_total($total_line_item);
215
-            foreach ($ticket_line_items as $ticket_line_item) {
216
-                if (! $ticket_line_item instanceof EE_Line_Item) {
217
-                    continue;
218
-                }
219
-                if ($total_line_item->timestamp(true) <= $session_lifespan->expiration()) {
220
-                    $expired_ticket_IDs[ $ticket_line_item->OBJ_ID() ] = $ticket_line_item->OBJ_ID();
221
-                } else {
222
-                    $valid_ticket_line_items[ $ticket_line_item->OBJ_ID() ] = $ticket_line_item;
223
-                }
224
-            }
225
-        }
226
-        if (! empty($expired_ticket_IDs)) {
227
-            EED_Ticket_Sales_Monitor::release_reservations_for_tickets(
228
-                \EEM_Ticket::instance()->get_tickets_with_IDs($expired_ticket_IDs),
229
-                $valid_ticket_line_items,
230
-                __FUNCTION__
231
-            );
232
-            // let's get rid of expired line items so that they can't interfere with tracking
233
-            add_action(
234
-                'shutdown',
235
-                array('EED_Ticket_Sales_Monitor', 'clear_expired_line_items_with_no_transaction'),
236
-                999
237
-            );
238
-        }
239
-        do_action(
240
-            'AHEE__EED_Ticket_Sales_Monitor__release_tickets_for_expired_carts__end',
241
-            $total_line_items,
242
-            $valid_ticket_line_items,
243
-            $expired_ticket_IDs
244
-        );
245
-    }
246
-
247
-
248
-
249
-    /********************************** VALIDATE_TICKET_SALE  **********************************/
250
-
251
-
252
-
253
-    /**
254
-     * callback for 'FHEE__EED_Ticket_Selector__process_ticket_selections__valid_post_data'
255
-     *
256
-     * @param int       $qty
257
-     * @param EE_Ticket $ticket
258
-     * @return bool
259
-     * @throws UnexpectedEntityException
260
-     * @throws EE_Error
261
-     */
262
-    public static function validate_ticket_sale($qty = 1, EE_Ticket $ticket)
263
-    {
264
-        $qty = absint($qty);
265
-        if ($qty > 0) {
266
-            $qty = EED_Ticket_Sales_Monitor::instance()->_validate_ticket_sale($ticket, $qty);
267
-        }
268
-        if (self::debug) {
269
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '()';
270
-            echo '<br /><br /><b> RETURNED QTY: ' . $qty . '</b>';
271
-        }
272
-        return $qty;
273
-    }
274
-
275
-
276
-
277
-    /**
278
-     * checks whether an individual ticket is available for purchase based on datetime, and ticket details
279
-     *
280
-     * @param   EE_Ticket $ticket
281
-     * @param int         $qty
282
-     * @return int
283
-     * @throws UnexpectedEntityException
284
-     * @throws EE_Error
285
-     */
286
-    protected function _validate_ticket_sale(EE_Ticket $ticket, $qty = 1)
287
-    {
288
-        if (self::debug) {
289
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
290
-        }
291
-        if (! $ticket instanceof EE_Ticket) {
292
-            return 0;
293
-        }
294
-        if (self::debug) {
295
-            echo '<br /><b> . ticket->ID: ' . $ticket->ID() . '</b>';
296
-            echo '<br /> . original ticket->reserved: ' . $ticket->reserved();
297
-        }
298
-        $ticket->refresh_from_db();
299
-        // first let's determine the ticket availability based on sales
300
-        $available = $ticket->qty('saleable');
301
-        if (self::debug) {
302
-            echo '<br /> . . . ticket->qty: ' . $ticket->qty();
303
-            echo '<br /> . . . ticket->sold: ' . $ticket->sold();
304
-            echo '<br /> . . . ticket->reserved: ' . $ticket->reserved();
305
-            echo '<br /> . . . ticket->qty(saleable): ' . $ticket->qty('saleable');
306
-            echo '<br /> . . . available: ' . $available;
307
-        }
308
-        if ($available < 1) {
309
-            $this->_ticket_sold_out($ticket);
310
-            return 0;
311
-        }
312
-        if (self::debug) {
313
-            echo '<br /> . . . qty: ' . $qty;
314
-        }
315
-        if ($available < $qty) {
316
-            $qty = $available;
317
-            if (self::debug) {
318
-                echo '<br /> . . . QTY ADJUSTED: ' . $qty;
319
-            }
320
-            $this->_ticket_quantity_decremented($ticket);
321
-        }
322
-        $this->_reserve_ticket($ticket, $qty);
323
-        return $qty;
324
-    }
325
-
326
-
327
-
328
-    /**
329
-     * increments ticket reserved based on quantity passed
330
-     *
331
-     * @param    EE_Ticket $ticket
332
-     * @param int          $quantity
333
-     * @return bool
334
-     * @throws EE_Error
335
-     */
336
-    protected function _reserve_ticket(EE_Ticket $ticket, $quantity = 1)
337
-    {
338
-        if (self::debug) {
339
-            echo '<br /><br /> . . . INCREASE RESERVED: ' . $quantity;
340
-        }
341
-        $ticket->increase_reserved($quantity, 'TicketSalesMonitor:'. __LINE__);
342
-        return $ticket->save();
343
-    }
344
-
345
-
346
-
347
-    /**
348
-     * @param  EE_Ticket $ticket
349
-     * @param  int       $quantity
350
-     * @return bool
351
-     * @throws EE_Error
352
-     */
353
-    protected function _release_reserved_ticket(EE_Ticket $ticket, $quantity = 1)
354
-    {
355
-        if (self::debug) {
356
-            echo '<br /> . . . ticket->ID: ' . $ticket->ID();
357
-            echo '<br /> . . . ticket->reserved: ' . $ticket->reserved();
358
-        }
359
-        $ticket->decrease_reserved($quantity, true, 'TicketSalesMonitor:'. __LINE__);
360
-        if (self::debug) {
361
-            echo '<br /> . . . ticket->reserved: ' . $ticket->reserved();
362
-        }
363
-        return $ticket->save() ? 1 : 0;
364
-    }
365
-
366
-
367
-
368
-    /**
369
-     * removes quantities within the ticket selector based on zero ticket availability
370
-     *
371
-     * @param    EE_Ticket $ticket
372
-     * @return    void
373
-     * @throws UnexpectedEntityException
374
-     * @throws EE_Error
375
-     */
376
-    protected function _ticket_sold_out(EE_Ticket $ticket)
377
-    {
378
-        if (self::debug) {
379
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
380
-            echo '<br /> . . ticket->name: ' . $this->_get_ticket_and_event_name($ticket);
381
-        }
382
-        $this->sold_out_tickets[] = $this->_get_ticket_and_event_name($ticket);
383
-    }
384
-
385
-
386
-
387
-    /**
388
-     * adjusts quantities within the ticket selector based on decreased ticket availability
389
-     *
390
-     * @param    EE_Ticket $ticket
391
-     * @return void
392
-     * @throws UnexpectedEntityException
393
-     * @throws EE_Error
394
-     */
395
-    protected function _ticket_quantity_decremented(EE_Ticket $ticket)
396
-    {
397
-        if (self::debug) {
398
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
399
-            echo '<br /> . . ticket->name: ' . $this->_get_ticket_and_event_name($ticket);
400
-        }
401
-        $this->decremented_tickets[] = $this->_get_ticket_and_event_name($ticket);
402
-    }
403
-
404
-
405
-
406
-    /**
407
-     * builds string out of ticket and event name
408
-     *
409
-     * @param    EE_Ticket $ticket
410
-     * @return string
411
-     * @throws UnexpectedEntityException
412
-     * @throws EE_Error
413
-     */
414
-    protected function _get_ticket_and_event_name(EE_Ticket $ticket)
415
-    {
416
-        $event = $ticket->get_related_event();
417
-        if ($event instanceof EE_Event) {
418
-            $ticket_name = sprintf(
419
-                _x('%1$s for %2$s', 'ticket name for event name', 'event_espresso'),
420
-                $ticket->name(),
421
-                $event->name()
422
-            );
423
-        } else {
424
-            $ticket_name = $ticket->name();
425
-        }
426
-        return $ticket_name;
427
-    }
428
-
429
-
430
-
431
-    /********************************** EVENT CART  **********************************/
432
-
433
-
434
-
435
-    /**
436
-     * releases or reserves ticket(s) based on quantity passed
437
-     *
438
-     * @param  EE_Line_Item $line_item
439
-     * @param  int          $quantity
440
-     * @return void
441
-     * @throws EE_Error
442
-     * @throws InvalidArgumentException
443
-     * @throws InvalidDataTypeException
444
-     * @throws InvalidInterfaceException
445
-     */
446
-    public static function ticket_quantity_updated(EE_Line_Item $line_item, $quantity = 1)
447
-    {
448
-        $ticket = EEM_Ticket::instance()->get_one_by_ID(absint($line_item->OBJ_ID()));
449
-        if ($ticket instanceof EE_Ticket) {
450
-            $ticket->add_extra_meta(
451
-                EE_Ticket::META_KEY_TICKET_RESERVATIONS,
452
-                __LINE__ . ') ' . __METHOD__ . '()'
453
-            );
454
-            if ($quantity > 0) {
455
-                EED_Ticket_Sales_Monitor::instance()->_reserve_ticket($ticket, $quantity);
456
-            } else {
457
-                EED_Ticket_Sales_Monitor::instance()->_release_reserved_ticket($ticket, $quantity);
458
-            }
459
-        }
460
-    }
461
-
462
-
463
-
464
-    /**
465
-     * releases reserved ticket(s) based on quantity passed
466
-     *
467
-     * @param  EE_Ticket $ticket
468
-     * @param  int       $quantity
469
-     * @return void
470
-     * @throws EE_Error
471
-     */
472
-    public static function ticket_removed_from_cart(EE_Ticket $ticket, $quantity = 1)
473
-    {
474
-        $ticket->add_extra_meta(
475
-            EE_Ticket::META_KEY_TICKET_RESERVATIONS,
476
-            __LINE__ . ') ' . __METHOD__ . '()'
477
-        );
478
-        EED_Ticket_Sales_Monitor::instance()->_release_reserved_ticket($ticket, $quantity);
479
-    }
480
-
481
-
482
-
483
-    /********************************** POST_NOTICES  **********************************/
484
-
485
-
486
-
487
-    /**
488
-     * @return void
489
-     * @throws EE_Error
490
-     * @throws InvalidArgumentException
491
-     * @throws ReflectionException
492
-     * @throws InvalidDataTypeException
493
-     * @throws InvalidInterfaceException
494
-     */
495
-    public static function post_notices()
496
-    {
497
-        EED_Ticket_Sales_Monitor::instance()->_post_notices();
498
-    }
499
-
500
-
501
-
502
-    /**
503
-     * @return void
504
-     * @throws EE_Error
505
-     * @throws InvalidArgumentException
506
-     * @throws ReflectionException
507
-     * @throws InvalidDataTypeException
508
-     * @throws InvalidInterfaceException
509
-     */
510
-    protected function _post_notices()
511
-    {
512
-        if (self::debug) {
513
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
514
-        }
515
-        $refresh_msg    = '';
516
-        $none_added_msg = '';
517
-        if (defined('DOING_AJAX') && DOING_AJAX) {
518
-            $refresh_msg    = __(
519
-                'Please refresh the page to view updated ticket quantities.',
520
-                'event_espresso'
521
-            );
522
-            $none_added_msg = __('No tickets were added for the event.', 'event_espresso');
523
-        }
524
-        if (! empty($this->sold_out_tickets)) {
525
-            EE_Error::add_attention(
526
-                sprintf(
527
-                    apply_filters(
528
-                        'FHEE__EED_Ticket_Sales_Monitor___post_notices__sold_out_tickets_notice',
529
-                        __(
530
-                            'We\'re sorry...%1$sThe following items have sold out since you first viewed this page, and can no longer be registered for:%1$s%1$s%2$s%1$s%1$sPlease note that availability can change at any time due to cancellations, so please check back again later if registration for this event(s) is important to you.%1$s%1$s%3$s%1$s%4$s%1$s',
531
-                            'event_espresso'
532
-                        )
533
-                    ),
534
-                    '<br />',
535
-                    implode('<br />', $this->sold_out_tickets),
536
-                    $none_added_msg,
537
-                    $refresh_msg
538
-                )
539
-            );
540
-            // alter code flow in the Ticket Selector for better UX
541
-            add_filter('FHEE__EED_Ticket_Selector__process_ticket_selections__tckts_slctd', '__return_true');
542
-            add_filter('FHEE__EED_Ticket_Selector__process_ticket_selections__success', '__return_false');
543
-            $this->sold_out_tickets = array();
544
-            // and reset the cart
545
-            EED_Ticket_Sales_Monitor::session_cart_reset(EE_Registry::instance()->SSN);
546
-        }
547
-        if (! empty($this->decremented_tickets)) {
548
-            EE_Error::add_attention(
549
-                sprintf(
550
-                    apply_filters(
551
-                        'FHEE__EED_Ticket_Sales_Monitor___ticket_quantity_decremented__notice',
552
-                        __(
553
-                            'We\'re sorry...%1$sDue to sales that have occurred since you first viewed the last page, the following items have had their quantities adjusted to match the current available amount:%1$s%1$s%2$s%1$s%1$sPlease note that availability can change at any time due to cancellations, so please check back again later if registration for this event(s) is important to you.%1$s%1$s%3$s%1$s%4$s%1$s',
554
-                            'event_espresso'
555
-                        )
556
-                    ),
557
-                    '<br />',
558
-                    implode('<br />', $this->decremented_tickets),
559
-                    $none_added_msg,
560
-                    $refresh_msg
561
-                )
562
-            );
563
-            $this->decremented_tickets = array();
564
-        }
565
-    }
566
-
567
-
568
-
569
-    /********************************** RELEASE_ALL_RESERVED_TICKETS_FOR_TRANSACTION  **********************************/
570
-
571
-
572
-
573
-    /**
574
-     * releases reserved tickets for all registrations of an EE_Transaction
575
-     * by default, will NOT release tickets for finalized transactions
576
-     *
577
-     * @param    EE_Transaction $transaction
578
-     * @return int
579
-     * @throws EE_Error
580
-     * @throws InvalidSessionDataException
581
-     */
582
-    protected function _release_all_reserved_tickets_for_transaction(EE_Transaction $transaction)
583
-    {
584
-        if (self::debug) {
585
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
586
-            echo '<br /> . transaction->ID: ' . $transaction->ID();
587
-            echo '<br /> . TXN status_ID: ' . $transaction->status_ID();
588
-        }
589
-        // check if 'finalize_registration' step has been completed...
590
-        $finalized = $transaction->reg_step_completed('finalize_registration');
591
-        if (self::debug) {
592
-            // DEBUG LOG
593
-            EEH_Debug_Tools::log(
594
-                __CLASS__,
595
-                __FUNCTION__,
596
-                __LINE__,
597
-                array('finalized' => $finalized),
598
-                false,
599
-                'EE_Transaction: ' . $transaction->ID()
600
-            );
601
-        }
602
-        // how many tickets were released
603
-        $count = 0;
604
-        if (self::debug) {
605
-            echo '<br /> . . . TXN finalized: ' . $finalized;
606
-        }
607
-        $release_tickets_with_TXN_status = array(
608
-            EEM_Transaction::failed_status_code,
609
-            EEM_Transaction::abandoned_status_code,
610
-            EEM_Transaction::incomplete_status_code,
611
-        );
612
-        $events = array();
613
-        // if the session is getting cleared BEFORE the TXN has been finalized or the transaction is not completed
614
-        if (! $finalized || in_array($transaction->status_ID(), $release_tickets_with_TXN_status, true)) {
615
-            // cancel any reserved tickets for registrations that were not approved
616
-            $registrations = $transaction->registrations();
617
-            if (self::debug) {
618
-                echo '<br /> . . . # registrations: ' . count($registrations);
619
-                $reg    = reset($registrations);
620
-                $ticket = $reg->ticket();
621
-                if ($ticket instanceof EE_Ticket) {
622
-                    $ticket->add_extra_meta(
623
-                        EE_Ticket::META_KEY_TICKET_RESERVATIONS,
624
-                        __LINE__ . ') Release All Tickets TXN:' . $transaction->ID()
625
-                    );
626
-                }
627
-            }
628
-            if (! empty($registrations)) {
629
-                foreach ($registrations as $registration) {
630
-                    if (
631
-                        $registration instanceof EE_Registration
632
-                        && $this->_release_reserved_ticket_for_registration($registration, $transaction)
633
-                    ) {
634
-                        $count++;
635
-                        $events[ $registration->event_ID() ] = $registration->event();
636
-                    }
637
-                }
638
-            }
639
-        }
640
-        if ($events !== array()) {
641
-            foreach ($events as $event) {
642
-                /** @var EE_Event $event */
643
-                $event->perform_sold_out_status_check();
644
-            }
645
-        }
646
-        return $count;
647
-    }
648
-
649
-
650
-
651
-    /**
652
-     * releases reserved tickets for an EE_Registration
653
-     * by default, will NOT release tickets for APPROVED registrations
654
-     *
655
-     * @param EE_Registration $registration
656
-     * @param EE_Transaction  $transaction
657
-     * @return int
658
-     * @throws EE_Error
659
-     */
660
-    protected function _release_reserved_ticket_for_registration(
661
-        EE_Registration $registration,
662
-        EE_Transaction $transaction
663
-    ) {
664
-        $STS_ID = $transaction->status_ID();
665
-        if (self::debug) {
666
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
667
-            echo '<br /> . . registration->ID: ' . $registration->ID();
668
-            echo '<br /> . . registration->status_ID: ' . $registration->status_ID();
669
-            echo '<br /> . . transaction->status_ID(): ' . $STS_ID;
670
-        }
671
-        if (
672
-            // release Tickets for Failed Transactions and Abandoned Transactions
673
-            $STS_ID === EEM_Transaction::failed_status_code
674
-            || $STS_ID === EEM_Transaction::abandoned_status_code
675
-            || (
676
-                // also release Tickets for Incomplete Transactions, but ONLY if the Registrations are NOT Approved
677
-                $STS_ID === EEM_Transaction::incomplete_status_code
678
-                && $registration->status_ID() !== EEM_Registration::status_id_approved
679
-            )
680
-        ) {
681
-            if (self::debug) {
682
-                echo '<br /><br /> . . RELEASE RESERVED TICKET';
683
-                $rsrvd = $registration->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true);
684
-                echo '<br /> . . . registration HAS_RESERVED_TICKET_KEY: ';
685
-                var_dump($rsrvd);
686
-            }
687
-            $registration->release_reserved_ticket(true, 'TicketSalesMonitor:'. __LINE__);
688
-            return 1;
689
-        }
690
-        return 0;
691
-    }
692
-
693
-
694
-
695
-    /********************************** SESSION_CART_RESET  **********************************/
696
-
697
-
698
-
699
-    /**
700
-     * callback hooked into 'AHEE__EE_Session__reset_cart__before_reset'
701
-     *
702
-     * @param EE_Session $session
703
-     * @return void
704
-     * @throws EE_Error
705
-     * @throws InvalidArgumentException
706
-     * @throws ReflectionException
707
-     * @throws InvalidDataTypeException
708
-     * @throws InvalidInterfaceException
709
-     */
710
-    public static function session_cart_reset(EE_Session $session)
711
-    {
712
-        if (self::debug) {
713
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
714
-        }
715
-        // first check of the session has a valid Checkout object
716
-        $checkout = $session->checkout();
717
-        if ($checkout instanceof EE_Checkout) {
718
-            // and use that to clear ticket reservations because it will update the associated registration meta data
719
-            EED_Ticket_Sales_Monitor::instance()->_session_checkout_reset($checkout);
720
-            return;
721
-        }
722
-        $cart = $session->cart();
723
-        if ($cart instanceof EE_Cart) {
724
-            if (self::debug) {
725
-                echo '<br /><br /> cart instance of EE_Cart: ';
726
-            }
727
-            EED_Ticket_Sales_Monitor::instance()->_session_cart_reset($cart, $session);
728
-        } else {
729
-            if (self::debug) {
730
-                echo '<br /><br /> invalid EE_Cart: ';
731
-                var_export($cart, true);
732
-            }
733
-        }
734
-    }
735
-
736
-
737
-
738
-    /**
739
-     * releases reserved tickets in the EE_Cart
740
-     *
741
-     * @param EE_Cart $cart
742
-     * @return void
743
-     * @throws EE_Error
744
-     * @throws InvalidArgumentException
745
-     * @throws ReflectionException
746
-     * @throws InvalidDataTypeException
747
-     * @throws InvalidInterfaceException
748
-     */
749
-    protected function _session_cart_reset(EE_Cart $cart, EE_Session $session)
750
-    {
751
-        if (self::debug) {
752
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
753
-        }
754
-        EE_Registry::instance()->load_helper('Line_Item');
755
-        $ticket_line_items = $cart->get_tickets();
756
-        if (empty($ticket_line_items)) {
757
-            return;
758
-        }
759
-        foreach ($ticket_line_items as $ticket_line_item) {
760
-            if (self::debug) {
761
-                echo '<br /> . ticket_line_item->ID(): ' . $ticket_line_item->ID();
762
-            }
763
-            if ($ticket_line_item instanceof EE_Line_Item && $ticket_line_item->OBJ_type() === 'Ticket') {
764
-                if (self::debug) {
765
-                    echo '<br /> . . ticket_line_item->OBJ_ID(): ' . $ticket_line_item->OBJ_ID();
766
-                }
767
-                $ticket = EEM_Ticket::instance()->get_one_by_ID($ticket_line_item->OBJ_ID());
768
-                if ($ticket instanceof EE_Ticket) {
769
-                    if (self::debug) {
770
-                        echo '<br /> . . ticket->ID(): ' . $ticket->ID();
771
-                        echo '<br /> . . ticket_line_item->quantity(): ' . $ticket_line_item->quantity();
772
-                    }
773
-                    $ticket->add_extra_meta(
774
-                        EE_Ticket::META_KEY_TICKET_RESERVATIONS,
775
-                        __LINE__ . ') ' . __METHOD__ . '() SID = ' . $session->id()
776
-                    );
777
-                    $this->_release_reserved_ticket($ticket, $ticket_line_item->quantity());
778
-                }
779
-            }
780
-        }
781
-        if (self::debug) {
782
-            echo '<br /><br /> RESET COMPLETED ';
783
-        }
784
-    }
785
-
786
-
787
-
788
-    /********************************** SESSION_CHECKOUT_RESET  **********************************/
789
-
790
-
791
-
792
-    /**
793
-     * callback hooked into 'AHEE__EE_Session__reset_checkout__before_reset'
794
-     *
795
-     * @param EE_Session $session
796
-     * @return void
797
-     * @throws EE_Error
798
-     * @throws InvalidSessionDataException
799
-     */
800
-    public static function session_checkout_reset(EE_Session $session)
801
-    {
802
-        $checkout = $session->checkout();
803
-        if ($checkout instanceof EE_Checkout) {
804
-            EED_Ticket_Sales_Monitor::instance()->_session_checkout_reset($checkout);
805
-        }
806
-    }
807
-
808
-
809
-
810
-    /**
811
-     * releases reserved tickets for the EE_Checkout->transaction
812
-     *
813
-     * @param EE_Checkout $checkout
814
-     * @return void
815
-     * @throws EE_Error
816
-     * @throws InvalidSessionDataException
817
-     */
818
-    protected function _session_checkout_reset(EE_Checkout $checkout)
819
-    {
820
-        if (self::debug) {
821
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
822
-        }
823
-        // we want to release the each registration's reserved tickets if the session was cleared, but not if this is a revisit
824
-        if ($checkout->revisit || ! $checkout->transaction instanceof EE_Transaction) {
825
-            return;
826
-        }
827
-        $this->_release_all_reserved_tickets_for_transaction($checkout->transaction);
828
-    }
829
-
830
-
831
-
832
-    /********************************** SESSION_EXPIRED_RESET  **********************************/
833
-
834
-
835
-
836
-    /**
837
-     * @param    EE_Session $session
838
-     * @return    void
839
-     */
840
-    public static function session_expired_reset(EE_Session $session)
841
-    {
842
-    }
843
-
844
-
845
-
846
-    /********************************** PROCESS_ABANDONED_TRANSACTIONS  **********************************/
847
-
848
-
849
-
850
-    /**
851
-     * releases reserved tickets for all registrations of an ABANDONED EE_Transaction
852
-     * by default, will NOT release tickets for free transactions, or any that have received a payment
853
-     *
854
-     * @param EE_Transaction $transaction
855
-     * @return void
856
-     * @throws EE_Error
857
-     * @throws InvalidSessionDataException
858
-     */
859
-    public static function process_abandoned_transactions(EE_Transaction $transaction)
860
-    {
861
-        // is this TXN free or has any money been paid towards this TXN? If so, then leave it alone
862
-        if ($transaction->is_free() || $transaction->paid() > 0) {
863
-            if (self::debug) {
864
-                // DEBUG LOG
865
-                EEH_Debug_Tools::log(
866
-                    __CLASS__,
867
-                    __FUNCTION__,
868
-                    __LINE__,
869
-                    array($transaction),
870
-                    false,
871
-                    'EE_Transaction: ' . $transaction->ID()
872
-                );
873
-            }
874
-            return;
875
-        }
876
-        // have their been any successful payments made ?
877
-        $payments = $transaction->payments();
878
-        foreach ($payments as $payment) {
879
-            if ($payment instanceof EE_Payment && $payment->status() === EEM_Payment::status_id_approved) {
880
-                if (self::debug) {
881
-                    // DEBUG LOG
882
-                    EEH_Debug_Tools::log(
883
-                        __CLASS__,
884
-                        __FUNCTION__,
885
-                        __LINE__,
886
-                        array($payment),
887
-                        false,
888
-                        'EE_Transaction: ' . $transaction->ID()
889
-                    );
890
-                }
891
-                return;
892
-            }
893
-        }
894
-        // since you haven't even attempted to pay for your ticket...
895
-        EED_Ticket_Sales_Monitor::instance()->_release_all_reserved_tickets_for_transaction($transaction);
896
-    }
897
-
898
-
899
-
900
-    /********************************** PROCESS_FAILED_TRANSACTIONS  **********************************/
901
-
902
-
903
-
904
-    /**
905
-     * releases reserved tickets for absolutely ALL registrations of a FAILED EE_Transaction
906
-     *
907
-     * @param EE_Transaction $transaction
908
-     * @return void
909
-     * @throws EE_Error
910
-     * @throws InvalidSessionDataException
911
-     */
912
-    public static function process_failed_transactions(EE_Transaction $transaction)
913
-    {
914
-        // since you haven't even attempted to pay for your ticket...
915
-        EED_Ticket_Sales_Monitor::instance()->_release_all_reserved_tickets_for_transaction($transaction);
916
-    }
917
-
918
-
919
-
920
-    /********************************** RESET RESERVATION COUNTS  *********************************/
921
-
922
-
923
-
924
-    /**
925
-     * Resets all ticket and datetime reserved counts to zero
926
-     * Tickets that are currently associated with a Transaction that is in progress
927
-     *
928
-     * @throws EE_Error
929
-     * @throws DomainException
930
-     * @throws InvalidDataTypeException
931
-     * @throws InvalidInterfaceException
932
-     * @throws InvalidArgumentException
933
-     * @throws UnexpectedEntityException
934
-     */
935
-    public static function reset_reservation_counts()
936
-    {
937
-        /** @var EE_Line_Item[] $valid_reserved_tickets */
938
-        $valid_reserved_tickets = array();
939
-        /** @var EE_Transaction[] $transactions_not_in_progress */
940
-        $transactions_not_in_progress = EEM_Transaction::instance()->get_transactions_not_in_progress();
941
-        foreach ($transactions_not_in_progress as $transaction) {
942
-            // if this TXN has been fully completed, then skip it
943
-            if ($transaction->reg_step_completed('finalize_registration')) {
944
-                continue;
945
-            }
946
-            $total_line_item = $transaction->total_line_item();
947
-            // $transaction_in_progress->line
948
-            if (! $total_line_item instanceof EE_Line_Item) {
949
-                throw new DomainException(
950
-                    esc_html__(
951
-                        'Transaction does not have a valid Total Line Item associated with it.',
952
-                        'event_espresso'
953
-                    )
954
-                );
955
-            }
956
-            $valid_reserved_tickets += EED_Ticket_Sales_Monitor::get_ticket_line_items_for_grand_total(
957
-                $total_line_item
958
-            );
959
-        }
960
-        $total_line_items = EEM_Line_Item::instance()->get_total_line_items_for_active_carts();
961
-        foreach ($total_line_items as $total_line_item) {
962
-            $valid_reserved_tickets += EED_Ticket_Sales_Monitor::get_ticket_line_items_for_grand_total(
963
-                $total_line_item
964
-            );
965
-        }
966
-        $tickets_with_reservations = EEM_Ticket::instance()->get_tickets_with_reservations();
967
-        return EED_Ticket_Sales_Monitor::release_reservations_for_tickets(
968
-            $tickets_with_reservations,
969
-            $valid_reserved_tickets,
970
-            __FUNCTION__
971
-        );
972
-    }
973
-
974
-
975
-
976
-    /**
977
-     * @param EE_Line_Item $total_line_item
978
-     * @return EE_Line_Item[]
979
-     */
980
-    private static function get_ticket_line_items_for_grand_total(EE_Line_Item $total_line_item)
981
-    {
982
-        /** @var EE_Line_Item[] $valid_reserved_tickets */
983
-        $valid_reserved_tickets = array();
984
-        $ticket_line_items      = EEH_Line_Item::get_ticket_line_items($total_line_item);
985
-        foreach ($ticket_line_items as $ticket_line_item) {
986
-            if ($ticket_line_item instanceof EE_Line_Item) {
987
-                $valid_reserved_tickets[] = $ticket_line_item;
988
-            }
989
-        }
990
-        return $valid_reserved_tickets;
991
-    }
992
-
993
-
994
-
995
-    /**
996
-     * @param EE_Ticket[]    $tickets_with_reservations
997
-     * @param EE_Line_Item[] $valid_reserved_ticket_line_items
998
-     * @return int
999
-     * @throws UnexpectedEntityException
1000
-     * @throws DomainException
1001
-     * @throws EE_Error
1002
-     */
1003
-    private static function release_reservations_for_tickets(
1004
-        array $tickets_with_reservations,
1005
-        array $valid_reserved_ticket_line_items = array(),
1006
-        $source
1007
-    ) {
1008
-        $total_tickets_released = 0;
1009
-        $sold_out_events = array();
1010
-        foreach ($tickets_with_reservations as $ticket_with_reservations) {
1011
-            if (! $ticket_with_reservations instanceof EE_Ticket) {
1012
-                continue;
1013
-            }
1014
-            $reserved_qty = $ticket_with_reservations->reserved();
1015
-            foreach ($valid_reserved_ticket_line_items as $valid_reserved_ticket_line_item) {
1016
-                if (
1017
-                    $valid_reserved_ticket_line_item instanceof EE_Line_Item
1018
-                    && $valid_reserved_ticket_line_item->OBJ_ID() === $ticket_with_reservations->ID()
1019
-                ) {
1020
-                    $reserved_qty -= $valid_reserved_ticket_line_item->quantity();
1021
-                }
1022
-            }
1023
-            if ($reserved_qty > 0) {
1024
-                $ticket_with_reservations->add_extra_meta(
1025
-                    EE_Ticket::META_KEY_TICKET_RESERVATIONS,
1026
-                    __LINE__ . ') ' . $source . '()'
1027
-                );
1028
-                $ticket_with_reservations->decrease_reserved($reserved_qty, true, 'TicketSalesMonitor:'. __LINE__);
1029
-                $ticket_with_reservations->save();
1030
-                $total_tickets_released += $reserved_qty;
1031
-                $event = $ticket_with_reservations->get_related_event();
1032
-                // track sold out events
1033
-                if ($event instanceof EE_Event && $event->is_sold_out()) {
1034
-                    $sold_out_events[] = $event;
1035
-                }
1036
-            }
1037
-        }
1038
-        // double check whether sold out events should remain sold out after releasing tickets
1039
-        if($sold_out_events !== array()){
1040
-            foreach ($sold_out_events as $sold_out_event) {
1041
-                /** @var EE_Event $sold_out_event */
1042
-                $sold_out_event->perform_sold_out_status_check();
1043
-            }
1044
-        }
1045
-        return $total_tickets_released;
1046
-    }
1047
-
1048
-
1049
-
1050
-    /********************************** SHUTDOWN  **********************************/
1051
-
1052
-
1053
-
1054
-    /**
1055
-     * @return false|int
1056
-     * @throws EE_Error
1057
-     * @throws InvalidArgumentException
1058
-     * @throws InvalidDataTypeException
1059
-     * @throws InvalidInterfaceException
1060
-     */
1061
-    public static function clear_expired_line_items_with_no_transaction()
1062
-    {
1063
-        /** @type WPDB $wpdb */
1064
-        global $wpdb;
1065
-        /** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */
1066
-        $session_lifespan = LoaderFactory::getLoader()->getShared(
1067
-            'EventEspresso\core\domain\values\session\SessionLifespan'
1068
-        );
1069
-        return $wpdb->query(
1070
-            $wpdb->prepare(
1071
-                'DELETE FROM ' . EEM_Line_Item::instance()->table() . '
27
+	const debug = false;    //	true false
28
+
29
+	/**
30
+	 * an array of raw ticket data from EED_Ticket_Selector
31
+	 *
32
+	 * @var array $ticket_selections
33
+	 */
34
+	protected $ticket_selections = array();
35
+
36
+	/**
37
+	 * the raw ticket data from EED_Ticket_Selector is organized in rows
38
+	 * according to how they are displayed in the actual Ticket_Selector
39
+	 * this tracks the current row being processed
40
+	 *
41
+	 * @var int $current_row
42
+	 */
43
+	protected $current_row = 0;
44
+
45
+	/**
46
+	 * an array for tracking names of tickets that have sold out
47
+	 *
48
+	 * @var array $sold_out_tickets
49
+	 */
50
+	protected $sold_out_tickets = array();
51
+
52
+	/**
53
+	 * an array for tracking names of tickets that have had their quantities reduced
54
+	 *
55
+	 * @var array $decremented_tickets
56
+	 */
57
+	protected $decremented_tickets = array();
58
+
59
+
60
+
61
+	/**
62
+	 * set_hooks - for hooking into EE Core, other modules, etc
63
+	 *
64
+	 * @return    void
65
+	 */
66
+	public static function set_hooks()
67
+	{
68
+		// release tickets for expired carts
69
+		add_action(
70
+			'EED_Ticket_Selector__process_ticket_selections__before',
71
+			array('EED_Ticket_Sales_Monitor', 'release_tickets_for_expired_carts'),
72
+			1
73
+		);
74
+		// check ticket reserves AFTER MER does it's check (hence priority 20)
75
+		add_filter(
76
+			'FHEE__EE_Ticket_Selector___add_ticket_to_cart__ticket_qty',
77
+			array('EED_Ticket_Sales_Monitor', 'validate_ticket_sale'),
78
+			20,
79
+			3
80
+		);
81
+		// add notices for sold out tickets
82
+		add_action(
83
+			'AHEE__EE_Ticket_Selector__process_ticket_selections__after_tickets_added_to_cart',
84
+			array('EED_Ticket_Sales_Monitor', 'post_notices'),
85
+			10
86
+		);
87
+		// handle ticket quantities adjusted in cart
88
+		//add_action(
89
+		//	'FHEE__EED_Multi_Event_Registration__adjust_line_item_quantity__line_item_quantity_updated',
90
+		//	array( 'EED_Ticket_Sales_Monitor', 'ticket_quantity_updated' ),
91
+		//	10, 2
92
+		//);
93
+		// handle tickets deleted from cart
94
+		add_action(
95
+			'FHEE__EED_Multi_Event_Registration__delete_ticket__ticket_removed_from_cart',
96
+			array('EED_Ticket_Sales_Monitor', 'ticket_removed_from_cart'),
97
+			10,
98
+			2
99
+		);
100
+		// handle emptied carts
101
+		add_action(
102
+			'AHEE__EE_Session__reset_cart__before_reset',
103
+			array('EED_Ticket_Sales_Monitor', 'session_cart_reset'),
104
+			10,
105
+			1
106
+		);
107
+		add_action(
108
+			'AHEE__EED_Multi_Event_Registration__empty_event_cart__before_delete_cart',
109
+			array('EED_Ticket_Sales_Monitor', 'session_cart_reset'),
110
+			10,
111
+			1
112
+		);
113
+		// handle cancelled registrations
114
+		add_action(
115
+			'AHEE__EE_Session__reset_checkout__before_reset',
116
+			array('EED_Ticket_Sales_Monitor', 'session_checkout_reset'),
117
+			10,
118
+			1
119
+		);
120
+		// cron tasks
121
+		add_action(
122
+			'AHEE__EE_Cron_Tasks__process_expired_transactions__abandoned_transaction',
123
+			array('EED_Ticket_Sales_Monitor', 'process_abandoned_transactions'),
124
+			10,
125
+			1
126
+		);
127
+		add_action(
128
+			'AHEE__EE_Cron_Tasks__process_expired_transactions__incomplete_transaction',
129
+			array('EED_Ticket_Sales_Monitor', 'process_abandoned_transactions'),
130
+			10,
131
+			1
132
+		);
133
+		add_action(
134
+			'AHEE__EE_Cron_Tasks__process_expired_transactions__failed_transaction',
135
+			array('EED_Ticket_Sales_Monitor', 'process_failed_transactions'),
136
+			10,
137
+			1
138
+		);
139
+	}
140
+
141
+
142
+
143
+	/**
144
+	 * set_hooks_admin - for hooking into EE Admin Core, other modules, etc
145
+	 *
146
+	 * @return void
147
+	 */
148
+	public static function set_hooks_admin()
149
+	{
150
+		EED_Ticket_Sales_Monitor::set_hooks();
151
+	}
152
+
153
+
154
+
155
+	/**
156
+	 * @return EED_Ticket_Sales_Monitor|EED_Module
157
+	 */
158
+	public static function instance()
159
+	{
160
+		return parent::get_instance(__CLASS__);
161
+	}
162
+
163
+
164
+
165
+	/**
166
+	 * @param WP_Query $WP_Query
167
+	 * @return    void
168
+	 */
169
+	public function run($WP_Query)
170
+	{
171
+	}
172
+
173
+
174
+
175
+	/********************************** PRE_TICKET_SALES  **********************************/
176
+
177
+
178
+
179
+	/**
180
+	 * Retrieves grand totals from the line items that have no TXN ID
181
+	 * and timestamps less than the current time minus the session lifespan.
182
+	 * These are carts that have been abandoned before the "registrant" even attempted to checkout.
183
+	 * We're going to release the tickets for these line items before attempting to add more to the cart.
184
+	 *
185
+	 * @return void
186
+	 * @throws DomainException
187
+	 * @throws EE_Error
188
+	 * @throws InvalidArgumentException
189
+	 * @throws InvalidDataTypeException
190
+	 * @throws InvalidInterfaceException
191
+	 * @throws UnexpectedEntityException
192
+	 */
193
+	public static function release_tickets_for_expired_carts()
194
+	{
195
+		do_action('AHEE__EED_Ticket_Sales_Monitor__release_tickets_for_expired_carts__begin');
196
+		$expired_ticket_IDs      = array();
197
+		$valid_ticket_line_items = array();
198
+		$total_line_items        = EEM_Line_Item::instance()->get_total_line_items_with_no_transaction();
199
+		if (empty($total_line_items)) {
200
+			do_action(
201
+				'AHEE__EED_Ticket_Sales_Monitor__release_tickets_for_expired_carts__end',
202
+				$total_line_items,
203
+				$valid_ticket_line_items,
204
+				$expired_ticket_IDs
205
+			);
206
+			return;
207
+		}
208
+		/** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */
209
+		$session_lifespan = LoaderFactory::getLoader()->getShared(
210
+			'EventEspresso\core\domain\values\session\SessionLifespan'
211
+		);
212
+		foreach ($total_line_items as $total_line_item) {
213
+			/** @var EE_Line_Item $total_line_item */
214
+			$ticket_line_items = EED_Ticket_Sales_Monitor::get_ticket_line_items_for_grand_total($total_line_item);
215
+			foreach ($ticket_line_items as $ticket_line_item) {
216
+				if (! $ticket_line_item instanceof EE_Line_Item) {
217
+					continue;
218
+				}
219
+				if ($total_line_item->timestamp(true) <= $session_lifespan->expiration()) {
220
+					$expired_ticket_IDs[ $ticket_line_item->OBJ_ID() ] = $ticket_line_item->OBJ_ID();
221
+				} else {
222
+					$valid_ticket_line_items[ $ticket_line_item->OBJ_ID() ] = $ticket_line_item;
223
+				}
224
+			}
225
+		}
226
+		if (! empty($expired_ticket_IDs)) {
227
+			EED_Ticket_Sales_Monitor::release_reservations_for_tickets(
228
+				\EEM_Ticket::instance()->get_tickets_with_IDs($expired_ticket_IDs),
229
+				$valid_ticket_line_items,
230
+				__FUNCTION__
231
+			);
232
+			// let's get rid of expired line items so that they can't interfere with tracking
233
+			add_action(
234
+				'shutdown',
235
+				array('EED_Ticket_Sales_Monitor', 'clear_expired_line_items_with_no_transaction'),
236
+				999
237
+			);
238
+		}
239
+		do_action(
240
+			'AHEE__EED_Ticket_Sales_Monitor__release_tickets_for_expired_carts__end',
241
+			$total_line_items,
242
+			$valid_ticket_line_items,
243
+			$expired_ticket_IDs
244
+		);
245
+	}
246
+
247
+
248
+
249
+	/********************************** VALIDATE_TICKET_SALE  **********************************/
250
+
251
+
252
+
253
+	/**
254
+	 * callback for 'FHEE__EED_Ticket_Selector__process_ticket_selections__valid_post_data'
255
+	 *
256
+	 * @param int       $qty
257
+	 * @param EE_Ticket $ticket
258
+	 * @return bool
259
+	 * @throws UnexpectedEntityException
260
+	 * @throws EE_Error
261
+	 */
262
+	public static function validate_ticket_sale($qty = 1, EE_Ticket $ticket)
263
+	{
264
+		$qty = absint($qty);
265
+		if ($qty > 0) {
266
+			$qty = EED_Ticket_Sales_Monitor::instance()->_validate_ticket_sale($ticket, $qty);
267
+		}
268
+		if (self::debug) {
269
+			echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '()';
270
+			echo '<br /><br /><b> RETURNED QTY: ' . $qty . '</b>';
271
+		}
272
+		return $qty;
273
+	}
274
+
275
+
276
+
277
+	/**
278
+	 * checks whether an individual ticket is available for purchase based on datetime, and ticket details
279
+	 *
280
+	 * @param   EE_Ticket $ticket
281
+	 * @param int         $qty
282
+	 * @return int
283
+	 * @throws UnexpectedEntityException
284
+	 * @throws EE_Error
285
+	 */
286
+	protected function _validate_ticket_sale(EE_Ticket $ticket, $qty = 1)
287
+	{
288
+		if (self::debug) {
289
+			echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
290
+		}
291
+		if (! $ticket instanceof EE_Ticket) {
292
+			return 0;
293
+		}
294
+		if (self::debug) {
295
+			echo '<br /><b> . ticket->ID: ' . $ticket->ID() . '</b>';
296
+			echo '<br /> . original ticket->reserved: ' . $ticket->reserved();
297
+		}
298
+		$ticket->refresh_from_db();
299
+		// first let's determine the ticket availability based on sales
300
+		$available = $ticket->qty('saleable');
301
+		if (self::debug) {
302
+			echo '<br /> . . . ticket->qty: ' . $ticket->qty();
303
+			echo '<br /> . . . ticket->sold: ' . $ticket->sold();
304
+			echo '<br /> . . . ticket->reserved: ' . $ticket->reserved();
305
+			echo '<br /> . . . ticket->qty(saleable): ' . $ticket->qty('saleable');
306
+			echo '<br /> . . . available: ' . $available;
307
+		}
308
+		if ($available < 1) {
309
+			$this->_ticket_sold_out($ticket);
310
+			return 0;
311
+		}
312
+		if (self::debug) {
313
+			echo '<br /> . . . qty: ' . $qty;
314
+		}
315
+		if ($available < $qty) {
316
+			$qty = $available;
317
+			if (self::debug) {
318
+				echo '<br /> . . . QTY ADJUSTED: ' . $qty;
319
+			}
320
+			$this->_ticket_quantity_decremented($ticket);
321
+		}
322
+		$this->_reserve_ticket($ticket, $qty);
323
+		return $qty;
324
+	}
325
+
326
+
327
+
328
+	/**
329
+	 * increments ticket reserved based on quantity passed
330
+	 *
331
+	 * @param    EE_Ticket $ticket
332
+	 * @param int          $quantity
333
+	 * @return bool
334
+	 * @throws EE_Error
335
+	 */
336
+	protected function _reserve_ticket(EE_Ticket $ticket, $quantity = 1)
337
+	{
338
+		if (self::debug) {
339
+			echo '<br /><br /> . . . INCREASE RESERVED: ' . $quantity;
340
+		}
341
+		$ticket->increase_reserved($quantity, 'TicketSalesMonitor:'. __LINE__);
342
+		return $ticket->save();
343
+	}
344
+
345
+
346
+
347
+	/**
348
+	 * @param  EE_Ticket $ticket
349
+	 * @param  int       $quantity
350
+	 * @return bool
351
+	 * @throws EE_Error
352
+	 */
353
+	protected function _release_reserved_ticket(EE_Ticket $ticket, $quantity = 1)
354
+	{
355
+		if (self::debug) {
356
+			echo '<br /> . . . ticket->ID: ' . $ticket->ID();
357
+			echo '<br /> . . . ticket->reserved: ' . $ticket->reserved();
358
+		}
359
+		$ticket->decrease_reserved($quantity, true, 'TicketSalesMonitor:'. __LINE__);
360
+		if (self::debug) {
361
+			echo '<br /> . . . ticket->reserved: ' . $ticket->reserved();
362
+		}
363
+		return $ticket->save() ? 1 : 0;
364
+	}
365
+
366
+
367
+
368
+	/**
369
+	 * removes quantities within the ticket selector based on zero ticket availability
370
+	 *
371
+	 * @param    EE_Ticket $ticket
372
+	 * @return    void
373
+	 * @throws UnexpectedEntityException
374
+	 * @throws EE_Error
375
+	 */
376
+	protected function _ticket_sold_out(EE_Ticket $ticket)
377
+	{
378
+		if (self::debug) {
379
+			echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
380
+			echo '<br /> . . ticket->name: ' . $this->_get_ticket_and_event_name($ticket);
381
+		}
382
+		$this->sold_out_tickets[] = $this->_get_ticket_and_event_name($ticket);
383
+	}
384
+
385
+
386
+
387
+	/**
388
+	 * adjusts quantities within the ticket selector based on decreased ticket availability
389
+	 *
390
+	 * @param    EE_Ticket $ticket
391
+	 * @return void
392
+	 * @throws UnexpectedEntityException
393
+	 * @throws EE_Error
394
+	 */
395
+	protected function _ticket_quantity_decremented(EE_Ticket $ticket)
396
+	{
397
+		if (self::debug) {
398
+			echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
399
+			echo '<br /> . . ticket->name: ' . $this->_get_ticket_and_event_name($ticket);
400
+		}
401
+		$this->decremented_tickets[] = $this->_get_ticket_and_event_name($ticket);
402
+	}
403
+
404
+
405
+
406
+	/**
407
+	 * builds string out of ticket and event name
408
+	 *
409
+	 * @param    EE_Ticket $ticket
410
+	 * @return string
411
+	 * @throws UnexpectedEntityException
412
+	 * @throws EE_Error
413
+	 */
414
+	protected function _get_ticket_and_event_name(EE_Ticket $ticket)
415
+	{
416
+		$event = $ticket->get_related_event();
417
+		if ($event instanceof EE_Event) {
418
+			$ticket_name = sprintf(
419
+				_x('%1$s for %2$s', 'ticket name for event name', 'event_espresso'),
420
+				$ticket->name(),
421
+				$event->name()
422
+			);
423
+		} else {
424
+			$ticket_name = $ticket->name();
425
+		}
426
+		return $ticket_name;
427
+	}
428
+
429
+
430
+
431
+	/********************************** EVENT CART  **********************************/
432
+
433
+
434
+
435
+	/**
436
+	 * releases or reserves ticket(s) based on quantity passed
437
+	 *
438
+	 * @param  EE_Line_Item $line_item
439
+	 * @param  int          $quantity
440
+	 * @return void
441
+	 * @throws EE_Error
442
+	 * @throws InvalidArgumentException
443
+	 * @throws InvalidDataTypeException
444
+	 * @throws InvalidInterfaceException
445
+	 */
446
+	public static function ticket_quantity_updated(EE_Line_Item $line_item, $quantity = 1)
447
+	{
448
+		$ticket = EEM_Ticket::instance()->get_one_by_ID(absint($line_item->OBJ_ID()));
449
+		if ($ticket instanceof EE_Ticket) {
450
+			$ticket->add_extra_meta(
451
+				EE_Ticket::META_KEY_TICKET_RESERVATIONS,
452
+				__LINE__ . ') ' . __METHOD__ . '()'
453
+			);
454
+			if ($quantity > 0) {
455
+				EED_Ticket_Sales_Monitor::instance()->_reserve_ticket($ticket, $quantity);
456
+			} else {
457
+				EED_Ticket_Sales_Monitor::instance()->_release_reserved_ticket($ticket, $quantity);
458
+			}
459
+		}
460
+	}
461
+
462
+
463
+
464
+	/**
465
+	 * releases reserved ticket(s) based on quantity passed
466
+	 *
467
+	 * @param  EE_Ticket $ticket
468
+	 * @param  int       $quantity
469
+	 * @return void
470
+	 * @throws EE_Error
471
+	 */
472
+	public static function ticket_removed_from_cart(EE_Ticket $ticket, $quantity = 1)
473
+	{
474
+		$ticket->add_extra_meta(
475
+			EE_Ticket::META_KEY_TICKET_RESERVATIONS,
476
+			__LINE__ . ') ' . __METHOD__ . '()'
477
+		);
478
+		EED_Ticket_Sales_Monitor::instance()->_release_reserved_ticket($ticket, $quantity);
479
+	}
480
+
481
+
482
+
483
+	/********************************** POST_NOTICES  **********************************/
484
+
485
+
486
+
487
+	/**
488
+	 * @return void
489
+	 * @throws EE_Error
490
+	 * @throws InvalidArgumentException
491
+	 * @throws ReflectionException
492
+	 * @throws InvalidDataTypeException
493
+	 * @throws InvalidInterfaceException
494
+	 */
495
+	public static function post_notices()
496
+	{
497
+		EED_Ticket_Sales_Monitor::instance()->_post_notices();
498
+	}
499
+
500
+
501
+
502
+	/**
503
+	 * @return void
504
+	 * @throws EE_Error
505
+	 * @throws InvalidArgumentException
506
+	 * @throws ReflectionException
507
+	 * @throws InvalidDataTypeException
508
+	 * @throws InvalidInterfaceException
509
+	 */
510
+	protected function _post_notices()
511
+	{
512
+		if (self::debug) {
513
+			echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
514
+		}
515
+		$refresh_msg    = '';
516
+		$none_added_msg = '';
517
+		if (defined('DOING_AJAX') && DOING_AJAX) {
518
+			$refresh_msg    = __(
519
+				'Please refresh the page to view updated ticket quantities.',
520
+				'event_espresso'
521
+			);
522
+			$none_added_msg = __('No tickets were added for the event.', 'event_espresso');
523
+		}
524
+		if (! empty($this->sold_out_tickets)) {
525
+			EE_Error::add_attention(
526
+				sprintf(
527
+					apply_filters(
528
+						'FHEE__EED_Ticket_Sales_Monitor___post_notices__sold_out_tickets_notice',
529
+						__(
530
+							'We\'re sorry...%1$sThe following items have sold out since you first viewed this page, and can no longer be registered for:%1$s%1$s%2$s%1$s%1$sPlease note that availability can change at any time due to cancellations, so please check back again later if registration for this event(s) is important to you.%1$s%1$s%3$s%1$s%4$s%1$s',
531
+							'event_espresso'
532
+						)
533
+					),
534
+					'<br />',
535
+					implode('<br />', $this->sold_out_tickets),
536
+					$none_added_msg,
537
+					$refresh_msg
538
+				)
539
+			);
540
+			// alter code flow in the Ticket Selector for better UX
541
+			add_filter('FHEE__EED_Ticket_Selector__process_ticket_selections__tckts_slctd', '__return_true');
542
+			add_filter('FHEE__EED_Ticket_Selector__process_ticket_selections__success', '__return_false');
543
+			$this->sold_out_tickets = array();
544
+			// and reset the cart
545
+			EED_Ticket_Sales_Monitor::session_cart_reset(EE_Registry::instance()->SSN);
546
+		}
547
+		if (! empty($this->decremented_tickets)) {
548
+			EE_Error::add_attention(
549
+				sprintf(
550
+					apply_filters(
551
+						'FHEE__EED_Ticket_Sales_Monitor___ticket_quantity_decremented__notice',
552
+						__(
553
+							'We\'re sorry...%1$sDue to sales that have occurred since you first viewed the last page, the following items have had their quantities adjusted to match the current available amount:%1$s%1$s%2$s%1$s%1$sPlease note that availability can change at any time due to cancellations, so please check back again later if registration for this event(s) is important to you.%1$s%1$s%3$s%1$s%4$s%1$s',
554
+							'event_espresso'
555
+						)
556
+					),
557
+					'<br />',
558
+					implode('<br />', $this->decremented_tickets),
559
+					$none_added_msg,
560
+					$refresh_msg
561
+				)
562
+			);
563
+			$this->decremented_tickets = array();
564
+		}
565
+	}
566
+
567
+
568
+
569
+	/********************************** RELEASE_ALL_RESERVED_TICKETS_FOR_TRANSACTION  **********************************/
570
+
571
+
572
+
573
+	/**
574
+	 * releases reserved tickets for all registrations of an EE_Transaction
575
+	 * by default, will NOT release tickets for finalized transactions
576
+	 *
577
+	 * @param    EE_Transaction $transaction
578
+	 * @return int
579
+	 * @throws EE_Error
580
+	 * @throws InvalidSessionDataException
581
+	 */
582
+	protected function _release_all_reserved_tickets_for_transaction(EE_Transaction $transaction)
583
+	{
584
+		if (self::debug) {
585
+			echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
586
+			echo '<br /> . transaction->ID: ' . $transaction->ID();
587
+			echo '<br /> . TXN status_ID: ' . $transaction->status_ID();
588
+		}
589
+		// check if 'finalize_registration' step has been completed...
590
+		$finalized = $transaction->reg_step_completed('finalize_registration');
591
+		if (self::debug) {
592
+			// DEBUG LOG
593
+			EEH_Debug_Tools::log(
594
+				__CLASS__,
595
+				__FUNCTION__,
596
+				__LINE__,
597
+				array('finalized' => $finalized),
598
+				false,
599
+				'EE_Transaction: ' . $transaction->ID()
600
+			);
601
+		}
602
+		// how many tickets were released
603
+		$count = 0;
604
+		if (self::debug) {
605
+			echo '<br /> . . . TXN finalized: ' . $finalized;
606
+		}
607
+		$release_tickets_with_TXN_status = array(
608
+			EEM_Transaction::failed_status_code,
609
+			EEM_Transaction::abandoned_status_code,
610
+			EEM_Transaction::incomplete_status_code,
611
+		);
612
+		$events = array();
613
+		// if the session is getting cleared BEFORE the TXN has been finalized or the transaction is not completed
614
+		if (! $finalized || in_array($transaction->status_ID(), $release_tickets_with_TXN_status, true)) {
615
+			// cancel any reserved tickets for registrations that were not approved
616
+			$registrations = $transaction->registrations();
617
+			if (self::debug) {
618
+				echo '<br /> . . . # registrations: ' . count($registrations);
619
+				$reg    = reset($registrations);
620
+				$ticket = $reg->ticket();
621
+				if ($ticket instanceof EE_Ticket) {
622
+					$ticket->add_extra_meta(
623
+						EE_Ticket::META_KEY_TICKET_RESERVATIONS,
624
+						__LINE__ . ') Release All Tickets TXN:' . $transaction->ID()
625
+					);
626
+				}
627
+			}
628
+			if (! empty($registrations)) {
629
+				foreach ($registrations as $registration) {
630
+					if (
631
+						$registration instanceof EE_Registration
632
+						&& $this->_release_reserved_ticket_for_registration($registration, $transaction)
633
+					) {
634
+						$count++;
635
+						$events[ $registration->event_ID() ] = $registration->event();
636
+					}
637
+				}
638
+			}
639
+		}
640
+		if ($events !== array()) {
641
+			foreach ($events as $event) {
642
+				/** @var EE_Event $event */
643
+				$event->perform_sold_out_status_check();
644
+			}
645
+		}
646
+		return $count;
647
+	}
648
+
649
+
650
+
651
+	/**
652
+	 * releases reserved tickets for an EE_Registration
653
+	 * by default, will NOT release tickets for APPROVED registrations
654
+	 *
655
+	 * @param EE_Registration $registration
656
+	 * @param EE_Transaction  $transaction
657
+	 * @return int
658
+	 * @throws EE_Error
659
+	 */
660
+	protected function _release_reserved_ticket_for_registration(
661
+		EE_Registration $registration,
662
+		EE_Transaction $transaction
663
+	) {
664
+		$STS_ID = $transaction->status_ID();
665
+		if (self::debug) {
666
+			echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
667
+			echo '<br /> . . registration->ID: ' . $registration->ID();
668
+			echo '<br /> . . registration->status_ID: ' . $registration->status_ID();
669
+			echo '<br /> . . transaction->status_ID(): ' . $STS_ID;
670
+		}
671
+		if (
672
+			// release Tickets for Failed Transactions and Abandoned Transactions
673
+			$STS_ID === EEM_Transaction::failed_status_code
674
+			|| $STS_ID === EEM_Transaction::abandoned_status_code
675
+			|| (
676
+				// also release Tickets for Incomplete Transactions, but ONLY if the Registrations are NOT Approved
677
+				$STS_ID === EEM_Transaction::incomplete_status_code
678
+				&& $registration->status_ID() !== EEM_Registration::status_id_approved
679
+			)
680
+		) {
681
+			if (self::debug) {
682
+				echo '<br /><br /> . . RELEASE RESERVED TICKET';
683
+				$rsrvd = $registration->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true);
684
+				echo '<br /> . . . registration HAS_RESERVED_TICKET_KEY: ';
685
+				var_dump($rsrvd);
686
+			}
687
+			$registration->release_reserved_ticket(true, 'TicketSalesMonitor:'. __LINE__);
688
+			return 1;
689
+		}
690
+		return 0;
691
+	}
692
+
693
+
694
+
695
+	/********************************** SESSION_CART_RESET  **********************************/
696
+
697
+
698
+
699
+	/**
700
+	 * callback hooked into 'AHEE__EE_Session__reset_cart__before_reset'
701
+	 *
702
+	 * @param EE_Session $session
703
+	 * @return void
704
+	 * @throws EE_Error
705
+	 * @throws InvalidArgumentException
706
+	 * @throws ReflectionException
707
+	 * @throws InvalidDataTypeException
708
+	 * @throws InvalidInterfaceException
709
+	 */
710
+	public static function session_cart_reset(EE_Session $session)
711
+	{
712
+		if (self::debug) {
713
+			echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
714
+		}
715
+		// first check of the session has a valid Checkout object
716
+		$checkout = $session->checkout();
717
+		if ($checkout instanceof EE_Checkout) {
718
+			// and use that to clear ticket reservations because it will update the associated registration meta data
719
+			EED_Ticket_Sales_Monitor::instance()->_session_checkout_reset($checkout);
720
+			return;
721
+		}
722
+		$cart = $session->cart();
723
+		if ($cart instanceof EE_Cart) {
724
+			if (self::debug) {
725
+				echo '<br /><br /> cart instance of EE_Cart: ';
726
+			}
727
+			EED_Ticket_Sales_Monitor::instance()->_session_cart_reset($cart, $session);
728
+		} else {
729
+			if (self::debug) {
730
+				echo '<br /><br /> invalid EE_Cart: ';
731
+				var_export($cart, true);
732
+			}
733
+		}
734
+	}
735
+
736
+
737
+
738
+	/**
739
+	 * releases reserved tickets in the EE_Cart
740
+	 *
741
+	 * @param EE_Cart $cart
742
+	 * @return void
743
+	 * @throws EE_Error
744
+	 * @throws InvalidArgumentException
745
+	 * @throws ReflectionException
746
+	 * @throws InvalidDataTypeException
747
+	 * @throws InvalidInterfaceException
748
+	 */
749
+	protected function _session_cart_reset(EE_Cart $cart, EE_Session $session)
750
+	{
751
+		if (self::debug) {
752
+			echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
753
+		}
754
+		EE_Registry::instance()->load_helper('Line_Item');
755
+		$ticket_line_items = $cart->get_tickets();
756
+		if (empty($ticket_line_items)) {
757
+			return;
758
+		}
759
+		foreach ($ticket_line_items as $ticket_line_item) {
760
+			if (self::debug) {
761
+				echo '<br /> . ticket_line_item->ID(): ' . $ticket_line_item->ID();
762
+			}
763
+			if ($ticket_line_item instanceof EE_Line_Item && $ticket_line_item->OBJ_type() === 'Ticket') {
764
+				if (self::debug) {
765
+					echo '<br /> . . ticket_line_item->OBJ_ID(): ' . $ticket_line_item->OBJ_ID();
766
+				}
767
+				$ticket = EEM_Ticket::instance()->get_one_by_ID($ticket_line_item->OBJ_ID());
768
+				if ($ticket instanceof EE_Ticket) {
769
+					if (self::debug) {
770
+						echo '<br /> . . ticket->ID(): ' . $ticket->ID();
771
+						echo '<br /> . . ticket_line_item->quantity(): ' . $ticket_line_item->quantity();
772
+					}
773
+					$ticket->add_extra_meta(
774
+						EE_Ticket::META_KEY_TICKET_RESERVATIONS,
775
+						__LINE__ . ') ' . __METHOD__ . '() SID = ' . $session->id()
776
+					);
777
+					$this->_release_reserved_ticket($ticket, $ticket_line_item->quantity());
778
+				}
779
+			}
780
+		}
781
+		if (self::debug) {
782
+			echo '<br /><br /> RESET COMPLETED ';
783
+		}
784
+	}
785
+
786
+
787
+
788
+	/********************************** SESSION_CHECKOUT_RESET  **********************************/
789
+
790
+
791
+
792
+	/**
793
+	 * callback hooked into 'AHEE__EE_Session__reset_checkout__before_reset'
794
+	 *
795
+	 * @param EE_Session $session
796
+	 * @return void
797
+	 * @throws EE_Error
798
+	 * @throws InvalidSessionDataException
799
+	 */
800
+	public static function session_checkout_reset(EE_Session $session)
801
+	{
802
+		$checkout = $session->checkout();
803
+		if ($checkout instanceof EE_Checkout) {
804
+			EED_Ticket_Sales_Monitor::instance()->_session_checkout_reset($checkout);
805
+		}
806
+	}
807
+
808
+
809
+
810
+	/**
811
+	 * releases reserved tickets for the EE_Checkout->transaction
812
+	 *
813
+	 * @param EE_Checkout $checkout
814
+	 * @return void
815
+	 * @throws EE_Error
816
+	 * @throws InvalidSessionDataException
817
+	 */
818
+	protected function _session_checkout_reset(EE_Checkout $checkout)
819
+	{
820
+		if (self::debug) {
821
+			echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
822
+		}
823
+		// we want to release the each registration's reserved tickets if the session was cleared, but not if this is a revisit
824
+		if ($checkout->revisit || ! $checkout->transaction instanceof EE_Transaction) {
825
+			return;
826
+		}
827
+		$this->_release_all_reserved_tickets_for_transaction($checkout->transaction);
828
+	}
829
+
830
+
831
+
832
+	/********************************** SESSION_EXPIRED_RESET  **********************************/
833
+
834
+
835
+
836
+	/**
837
+	 * @param    EE_Session $session
838
+	 * @return    void
839
+	 */
840
+	public static function session_expired_reset(EE_Session $session)
841
+	{
842
+	}
843
+
844
+
845
+
846
+	/********************************** PROCESS_ABANDONED_TRANSACTIONS  **********************************/
847
+
848
+
849
+
850
+	/**
851
+	 * releases reserved tickets for all registrations of an ABANDONED EE_Transaction
852
+	 * by default, will NOT release tickets for free transactions, or any that have received a payment
853
+	 *
854
+	 * @param EE_Transaction $transaction
855
+	 * @return void
856
+	 * @throws EE_Error
857
+	 * @throws InvalidSessionDataException
858
+	 */
859
+	public static function process_abandoned_transactions(EE_Transaction $transaction)
860
+	{
861
+		// is this TXN free or has any money been paid towards this TXN? If so, then leave it alone
862
+		if ($transaction->is_free() || $transaction->paid() > 0) {
863
+			if (self::debug) {
864
+				// DEBUG LOG
865
+				EEH_Debug_Tools::log(
866
+					__CLASS__,
867
+					__FUNCTION__,
868
+					__LINE__,
869
+					array($transaction),
870
+					false,
871
+					'EE_Transaction: ' . $transaction->ID()
872
+				);
873
+			}
874
+			return;
875
+		}
876
+		// have their been any successful payments made ?
877
+		$payments = $transaction->payments();
878
+		foreach ($payments as $payment) {
879
+			if ($payment instanceof EE_Payment && $payment->status() === EEM_Payment::status_id_approved) {
880
+				if (self::debug) {
881
+					// DEBUG LOG
882
+					EEH_Debug_Tools::log(
883
+						__CLASS__,
884
+						__FUNCTION__,
885
+						__LINE__,
886
+						array($payment),
887
+						false,
888
+						'EE_Transaction: ' . $transaction->ID()
889
+					);
890
+				}
891
+				return;
892
+			}
893
+		}
894
+		// since you haven't even attempted to pay for your ticket...
895
+		EED_Ticket_Sales_Monitor::instance()->_release_all_reserved_tickets_for_transaction($transaction);
896
+	}
897
+
898
+
899
+
900
+	/********************************** PROCESS_FAILED_TRANSACTIONS  **********************************/
901
+
902
+
903
+
904
+	/**
905
+	 * releases reserved tickets for absolutely ALL registrations of a FAILED EE_Transaction
906
+	 *
907
+	 * @param EE_Transaction $transaction
908
+	 * @return void
909
+	 * @throws EE_Error
910
+	 * @throws InvalidSessionDataException
911
+	 */
912
+	public static function process_failed_transactions(EE_Transaction $transaction)
913
+	{
914
+		// since you haven't even attempted to pay for your ticket...
915
+		EED_Ticket_Sales_Monitor::instance()->_release_all_reserved_tickets_for_transaction($transaction);
916
+	}
917
+
918
+
919
+
920
+	/********************************** RESET RESERVATION COUNTS  *********************************/
921
+
922
+
923
+
924
+	/**
925
+	 * Resets all ticket and datetime reserved counts to zero
926
+	 * Tickets that are currently associated with a Transaction that is in progress
927
+	 *
928
+	 * @throws EE_Error
929
+	 * @throws DomainException
930
+	 * @throws InvalidDataTypeException
931
+	 * @throws InvalidInterfaceException
932
+	 * @throws InvalidArgumentException
933
+	 * @throws UnexpectedEntityException
934
+	 */
935
+	public static function reset_reservation_counts()
936
+	{
937
+		/** @var EE_Line_Item[] $valid_reserved_tickets */
938
+		$valid_reserved_tickets = array();
939
+		/** @var EE_Transaction[] $transactions_not_in_progress */
940
+		$transactions_not_in_progress = EEM_Transaction::instance()->get_transactions_not_in_progress();
941
+		foreach ($transactions_not_in_progress as $transaction) {
942
+			// if this TXN has been fully completed, then skip it
943
+			if ($transaction->reg_step_completed('finalize_registration')) {
944
+				continue;
945
+			}
946
+			$total_line_item = $transaction->total_line_item();
947
+			// $transaction_in_progress->line
948
+			if (! $total_line_item instanceof EE_Line_Item) {
949
+				throw new DomainException(
950
+					esc_html__(
951
+						'Transaction does not have a valid Total Line Item associated with it.',
952
+						'event_espresso'
953
+					)
954
+				);
955
+			}
956
+			$valid_reserved_tickets += EED_Ticket_Sales_Monitor::get_ticket_line_items_for_grand_total(
957
+				$total_line_item
958
+			);
959
+		}
960
+		$total_line_items = EEM_Line_Item::instance()->get_total_line_items_for_active_carts();
961
+		foreach ($total_line_items as $total_line_item) {
962
+			$valid_reserved_tickets += EED_Ticket_Sales_Monitor::get_ticket_line_items_for_grand_total(
963
+				$total_line_item
964
+			);
965
+		}
966
+		$tickets_with_reservations = EEM_Ticket::instance()->get_tickets_with_reservations();
967
+		return EED_Ticket_Sales_Monitor::release_reservations_for_tickets(
968
+			$tickets_with_reservations,
969
+			$valid_reserved_tickets,
970
+			__FUNCTION__
971
+		);
972
+	}
973
+
974
+
975
+
976
+	/**
977
+	 * @param EE_Line_Item $total_line_item
978
+	 * @return EE_Line_Item[]
979
+	 */
980
+	private static function get_ticket_line_items_for_grand_total(EE_Line_Item $total_line_item)
981
+	{
982
+		/** @var EE_Line_Item[] $valid_reserved_tickets */
983
+		$valid_reserved_tickets = array();
984
+		$ticket_line_items      = EEH_Line_Item::get_ticket_line_items($total_line_item);
985
+		foreach ($ticket_line_items as $ticket_line_item) {
986
+			if ($ticket_line_item instanceof EE_Line_Item) {
987
+				$valid_reserved_tickets[] = $ticket_line_item;
988
+			}
989
+		}
990
+		return $valid_reserved_tickets;
991
+	}
992
+
993
+
994
+
995
+	/**
996
+	 * @param EE_Ticket[]    $tickets_with_reservations
997
+	 * @param EE_Line_Item[] $valid_reserved_ticket_line_items
998
+	 * @return int
999
+	 * @throws UnexpectedEntityException
1000
+	 * @throws DomainException
1001
+	 * @throws EE_Error
1002
+	 */
1003
+	private static function release_reservations_for_tickets(
1004
+		array $tickets_with_reservations,
1005
+		array $valid_reserved_ticket_line_items = array(),
1006
+		$source
1007
+	) {
1008
+		$total_tickets_released = 0;
1009
+		$sold_out_events = array();
1010
+		foreach ($tickets_with_reservations as $ticket_with_reservations) {
1011
+			if (! $ticket_with_reservations instanceof EE_Ticket) {
1012
+				continue;
1013
+			}
1014
+			$reserved_qty = $ticket_with_reservations->reserved();
1015
+			foreach ($valid_reserved_ticket_line_items as $valid_reserved_ticket_line_item) {
1016
+				if (
1017
+					$valid_reserved_ticket_line_item instanceof EE_Line_Item
1018
+					&& $valid_reserved_ticket_line_item->OBJ_ID() === $ticket_with_reservations->ID()
1019
+				) {
1020
+					$reserved_qty -= $valid_reserved_ticket_line_item->quantity();
1021
+				}
1022
+			}
1023
+			if ($reserved_qty > 0) {
1024
+				$ticket_with_reservations->add_extra_meta(
1025
+					EE_Ticket::META_KEY_TICKET_RESERVATIONS,
1026
+					__LINE__ . ') ' . $source . '()'
1027
+				);
1028
+				$ticket_with_reservations->decrease_reserved($reserved_qty, true, 'TicketSalesMonitor:'. __LINE__);
1029
+				$ticket_with_reservations->save();
1030
+				$total_tickets_released += $reserved_qty;
1031
+				$event = $ticket_with_reservations->get_related_event();
1032
+				// track sold out events
1033
+				if ($event instanceof EE_Event && $event->is_sold_out()) {
1034
+					$sold_out_events[] = $event;
1035
+				}
1036
+			}
1037
+		}
1038
+		// double check whether sold out events should remain sold out after releasing tickets
1039
+		if($sold_out_events !== array()){
1040
+			foreach ($sold_out_events as $sold_out_event) {
1041
+				/** @var EE_Event $sold_out_event */
1042
+				$sold_out_event->perform_sold_out_status_check();
1043
+			}
1044
+		}
1045
+		return $total_tickets_released;
1046
+	}
1047
+
1048
+
1049
+
1050
+	/********************************** SHUTDOWN  **********************************/
1051
+
1052
+
1053
+
1054
+	/**
1055
+	 * @return false|int
1056
+	 * @throws EE_Error
1057
+	 * @throws InvalidArgumentException
1058
+	 * @throws InvalidDataTypeException
1059
+	 * @throws InvalidInterfaceException
1060
+	 */
1061
+	public static function clear_expired_line_items_with_no_transaction()
1062
+	{
1063
+		/** @type WPDB $wpdb */
1064
+		global $wpdb;
1065
+		/** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */
1066
+		$session_lifespan = LoaderFactory::getLoader()->getShared(
1067
+			'EventEspresso\core\domain\values\session\SessionLifespan'
1068
+		);
1069
+		return $wpdb->query(
1070
+			$wpdb->prepare(
1071
+				'DELETE FROM ' . EEM_Line_Item::instance()->table() . '
1072 1072
                 WHERE TXN_ID = 0 AND LIN_timestamp <= %s',
1073
-                // use GMT time because that's what LIN_timestamps are in
1074
-                date('Y-m-d H:i:s', $session_lifespan->expiration())
1075
-            )
1076
-        );
1077
-    }
1073
+				// use GMT time because that's what LIN_timestamps are in
1074
+				date('Y-m-d H:i:s', $session_lifespan->expiration())
1075
+			)
1076
+		);
1077
+	}
1078 1078
 
1079 1079
 }
1080 1080
 // End of file EED_Ticket_Sales_Monitor.module.php
Please login to merge, or discard this patch.
Spacing   +65 added lines, -65 removed lines patch added patch discarded remove patch
@@ -24,7 +24,7 @@  discard block
 block discarded – undo
24 24
 class EED_Ticket_Sales_Monitor extends EED_Module
25 25
 {
26 26
 
27
-    const debug = false;    //	true false
27
+    const debug = false; //	true false
28 28
 
29 29
     /**
30 30
      * an array of raw ticket data from EED_Ticket_Selector
@@ -213,17 +213,17 @@  discard block
 block discarded – undo
213 213
             /** @var EE_Line_Item $total_line_item */
214 214
             $ticket_line_items = EED_Ticket_Sales_Monitor::get_ticket_line_items_for_grand_total($total_line_item);
215 215
             foreach ($ticket_line_items as $ticket_line_item) {
216
-                if (! $ticket_line_item instanceof EE_Line_Item) {
216
+                if ( ! $ticket_line_item instanceof EE_Line_Item) {
217 217
                     continue;
218 218
                 }
219 219
                 if ($total_line_item->timestamp(true) <= $session_lifespan->expiration()) {
220
-                    $expired_ticket_IDs[ $ticket_line_item->OBJ_ID() ] = $ticket_line_item->OBJ_ID();
220
+                    $expired_ticket_IDs[$ticket_line_item->OBJ_ID()] = $ticket_line_item->OBJ_ID();
221 221
                 } else {
222
-                    $valid_ticket_line_items[ $ticket_line_item->OBJ_ID() ] = $ticket_line_item;
222
+                    $valid_ticket_line_items[$ticket_line_item->OBJ_ID()] = $ticket_line_item;
223 223
                 }
224 224
             }
225 225
         }
226
-        if (! empty($expired_ticket_IDs)) {
226
+        if ( ! empty($expired_ticket_IDs)) {
227 227
             EED_Ticket_Sales_Monitor::release_reservations_for_tickets(
228 228
                 \EEM_Ticket::instance()->get_tickets_with_IDs($expired_ticket_IDs),
229 229
                 $valid_ticket_line_items,
@@ -266,8 +266,8 @@  discard block
 block discarded – undo
266 266
             $qty = EED_Ticket_Sales_Monitor::instance()->_validate_ticket_sale($ticket, $qty);
267 267
         }
268 268
         if (self::debug) {
269
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '()';
270
-            echo '<br /><br /><b> RETURNED QTY: ' . $qty . '</b>';
269
+            echo '<br /><br /> '.__LINE__.') '.__METHOD__.'()';
270
+            echo '<br /><br /><b> RETURNED QTY: '.$qty.'</b>';
271 271
         }
272 272
         return $qty;
273 273
     }
@@ -286,36 +286,36 @@  discard block
 block discarded – undo
286 286
     protected function _validate_ticket_sale(EE_Ticket $ticket, $qty = 1)
287 287
     {
288 288
         if (self::debug) {
289
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
289
+            echo '<br /><br /> '.__LINE__.') '.__METHOD__.'() ';
290 290
         }
291
-        if (! $ticket instanceof EE_Ticket) {
291
+        if ( ! $ticket instanceof EE_Ticket) {
292 292
             return 0;
293 293
         }
294 294
         if (self::debug) {
295
-            echo '<br /><b> . ticket->ID: ' . $ticket->ID() . '</b>';
296
-            echo '<br /> . original ticket->reserved: ' . $ticket->reserved();
295
+            echo '<br /><b> . ticket->ID: '.$ticket->ID().'</b>';
296
+            echo '<br /> . original ticket->reserved: '.$ticket->reserved();
297 297
         }
298 298
         $ticket->refresh_from_db();
299 299
         // first let's determine the ticket availability based on sales
300 300
         $available = $ticket->qty('saleable');
301 301
         if (self::debug) {
302
-            echo '<br /> . . . ticket->qty: ' . $ticket->qty();
303
-            echo '<br /> . . . ticket->sold: ' . $ticket->sold();
304
-            echo '<br /> . . . ticket->reserved: ' . $ticket->reserved();
305
-            echo '<br /> . . . ticket->qty(saleable): ' . $ticket->qty('saleable');
306
-            echo '<br /> . . . available: ' . $available;
302
+            echo '<br /> . . . ticket->qty: '.$ticket->qty();
303
+            echo '<br /> . . . ticket->sold: '.$ticket->sold();
304
+            echo '<br /> . . . ticket->reserved: '.$ticket->reserved();
305
+            echo '<br /> . . . ticket->qty(saleable): '.$ticket->qty('saleable');
306
+            echo '<br /> . . . available: '.$available;
307 307
         }
308 308
         if ($available < 1) {
309 309
             $this->_ticket_sold_out($ticket);
310 310
             return 0;
311 311
         }
312 312
         if (self::debug) {
313
-            echo '<br /> . . . qty: ' . $qty;
313
+            echo '<br /> . . . qty: '.$qty;
314 314
         }
315 315
         if ($available < $qty) {
316 316
             $qty = $available;
317 317
             if (self::debug) {
318
-                echo '<br /> . . . QTY ADJUSTED: ' . $qty;
318
+                echo '<br /> . . . QTY ADJUSTED: '.$qty;
319 319
             }
320 320
             $this->_ticket_quantity_decremented($ticket);
321 321
         }
@@ -336,9 +336,9 @@  discard block
 block discarded – undo
336 336
     protected function _reserve_ticket(EE_Ticket $ticket, $quantity = 1)
337 337
     {
338 338
         if (self::debug) {
339
-            echo '<br /><br /> . . . INCREASE RESERVED: ' . $quantity;
339
+            echo '<br /><br /> . . . INCREASE RESERVED: '.$quantity;
340 340
         }
341
-        $ticket->increase_reserved($quantity, 'TicketSalesMonitor:'. __LINE__);
341
+        $ticket->increase_reserved($quantity, 'TicketSalesMonitor:'.__LINE__);
342 342
         return $ticket->save();
343 343
     }
344 344
 
@@ -353,12 +353,12 @@  discard block
 block discarded – undo
353 353
     protected function _release_reserved_ticket(EE_Ticket $ticket, $quantity = 1)
354 354
     {
355 355
         if (self::debug) {
356
-            echo '<br /> . . . ticket->ID: ' . $ticket->ID();
357
-            echo '<br /> . . . ticket->reserved: ' . $ticket->reserved();
356
+            echo '<br /> . . . ticket->ID: '.$ticket->ID();
357
+            echo '<br /> . . . ticket->reserved: '.$ticket->reserved();
358 358
         }
359
-        $ticket->decrease_reserved($quantity, true, 'TicketSalesMonitor:'. __LINE__);
359
+        $ticket->decrease_reserved($quantity, true, 'TicketSalesMonitor:'.__LINE__);
360 360
         if (self::debug) {
361
-            echo '<br /> . . . ticket->reserved: ' . $ticket->reserved();
361
+            echo '<br /> . . . ticket->reserved: '.$ticket->reserved();
362 362
         }
363 363
         return $ticket->save() ? 1 : 0;
364 364
     }
@@ -376,8 +376,8 @@  discard block
 block discarded – undo
376 376
     protected function _ticket_sold_out(EE_Ticket $ticket)
377 377
     {
378 378
         if (self::debug) {
379
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
380
-            echo '<br /> . . ticket->name: ' . $this->_get_ticket_and_event_name($ticket);
379
+            echo '<br /><br /> '.__LINE__.') '.__METHOD__.'() ';
380
+            echo '<br /> . . ticket->name: '.$this->_get_ticket_and_event_name($ticket);
381 381
         }
382 382
         $this->sold_out_tickets[] = $this->_get_ticket_and_event_name($ticket);
383 383
     }
@@ -395,8 +395,8 @@  discard block
 block discarded – undo
395 395
     protected function _ticket_quantity_decremented(EE_Ticket $ticket)
396 396
     {
397 397
         if (self::debug) {
398
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
399
-            echo '<br /> . . ticket->name: ' . $this->_get_ticket_and_event_name($ticket);
398
+            echo '<br /><br /> '.__LINE__.') '.__METHOD__.'() ';
399
+            echo '<br /> . . ticket->name: '.$this->_get_ticket_and_event_name($ticket);
400 400
         }
401 401
         $this->decremented_tickets[] = $this->_get_ticket_and_event_name($ticket);
402 402
     }
@@ -449,7 +449,7 @@  discard block
 block discarded – undo
449 449
         if ($ticket instanceof EE_Ticket) {
450 450
             $ticket->add_extra_meta(
451 451
                 EE_Ticket::META_KEY_TICKET_RESERVATIONS,
452
-                __LINE__ . ') ' . __METHOD__ . '()'
452
+                __LINE__.') '.__METHOD__.'()'
453 453
             );
454 454
             if ($quantity > 0) {
455 455
                 EED_Ticket_Sales_Monitor::instance()->_reserve_ticket($ticket, $quantity);
@@ -473,7 +473,7 @@  discard block
 block discarded – undo
473 473
     {
474 474
         $ticket->add_extra_meta(
475 475
             EE_Ticket::META_KEY_TICKET_RESERVATIONS,
476
-            __LINE__ . ') ' . __METHOD__ . '()'
476
+            __LINE__.') '.__METHOD__.'()'
477 477
         );
478 478
         EED_Ticket_Sales_Monitor::instance()->_release_reserved_ticket($ticket, $quantity);
479 479
     }
@@ -510,18 +510,18 @@  discard block
 block discarded – undo
510 510
     protected function _post_notices()
511 511
     {
512 512
         if (self::debug) {
513
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
513
+            echo '<br /><br /> '.__LINE__.') '.__METHOD__.'() ';
514 514
         }
515 515
         $refresh_msg    = '';
516 516
         $none_added_msg = '';
517 517
         if (defined('DOING_AJAX') && DOING_AJAX) {
518
-            $refresh_msg    = __(
518
+            $refresh_msg = __(
519 519
                 'Please refresh the page to view updated ticket quantities.',
520 520
                 'event_espresso'
521 521
             );
522 522
             $none_added_msg = __('No tickets were added for the event.', 'event_espresso');
523 523
         }
524
-        if (! empty($this->sold_out_tickets)) {
524
+        if ( ! empty($this->sold_out_tickets)) {
525 525
             EE_Error::add_attention(
526 526
                 sprintf(
527 527
                     apply_filters(
@@ -544,7 +544,7 @@  discard block
 block discarded – undo
544 544
             // and reset the cart
545 545
             EED_Ticket_Sales_Monitor::session_cart_reset(EE_Registry::instance()->SSN);
546 546
         }
547
-        if (! empty($this->decremented_tickets)) {
547
+        if ( ! empty($this->decremented_tickets)) {
548 548
             EE_Error::add_attention(
549 549
                 sprintf(
550 550
                     apply_filters(
@@ -582,9 +582,9 @@  discard block
 block discarded – undo
582 582
     protected function _release_all_reserved_tickets_for_transaction(EE_Transaction $transaction)
583 583
     {
584 584
         if (self::debug) {
585
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
586
-            echo '<br /> . transaction->ID: ' . $transaction->ID();
587
-            echo '<br /> . TXN status_ID: ' . $transaction->status_ID();
585
+            echo '<br /><br /> '.__LINE__.') '.__METHOD__.'() ';
586
+            echo '<br /> . transaction->ID: '.$transaction->ID();
587
+            echo '<br /> . TXN status_ID: '.$transaction->status_ID();
588 588
         }
589 589
         // check if 'finalize_registration' step has been completed...
590 590
         $finalized = $transaction->reg_step_completed('finalize_registration');
@@ -596,13 +596,13 @@  discard block
 block discarded – undo
596 596
                 __LINE__,
597 597
                 array('finalized' => $finalized),
598 598
                 false,
599
-                'EE_Transaction: ' . $transaction->ID()
599
+                'EE_Transaction: '.$transaction->ID()
600 600
             );
601 601
         }
602 602
         // how many tickets were released
603 603
         $count = 0;
604 604
         if (self::debug) {
605
-            echo '<br /> . . . TXN finalized: ' . $finalized;
605
+            echo '<br /> . . . TXN finalized: '.$finalized;
606 606
         }
607 607
         $release_tickets_with_TXN_status = array(
608 608
             EEM_Transaction::failed_status_code,
@@ -611,28 +611,28 @@  discard block
 block discarded – undo
611 611
         );
612 612
         $events = array();
613 613
         // if the session is getting cleared BEFORE the TXN has been finalized or the transaction is not completed
614
-        if (! $finalized || in_array($transaction->status_ID(), $release_tickets_with_TXN_status, true)) {
614
+        if ( ! $finalized || in_array($transaction->status_ID(), $release_tickets_with_TXN_status, true)) {
615 615
             // cancel any reserved tickets for registrations that were not approved
616 616
             $registrations = $transaction->registrations();
617 617
             if (self::debug) {
618
-                echo '<br /> . . . # registrations: ' . count($registrations);
618
+                echo '<br /> . . . # registrations: '.count($registrations);
619 619
                 $reg    = reset($registrations);
620 620
                 $ticket = $reg->ticket();
621 621
                 if ($ticket instanceof EE_Ticket) {
622 622
                     $ticket->add_extra_meta(
623 623
                         EE_Ticket::META_KEY_TICKET_RESERVATIONS,
624
-                        __LINE__ . ') Release All Tickets TXN:' . $transaction->ID()
624
+                        __LINE__.') Release All Tickets TXN:'.$transaction->ID()
625 625
                     );
626 626
                 }
627 627
             }
628
-            if (! empty($registrations)) {
628
+            if ( ! empty($registrations)) {
629 629
                 foreach ($registrations as $registration) {
630 630
                     if (
631 631
                         $registration instanceof EE_Registration
632 632
                         && $this->_release_reserved_ticket_for_registration($registration, $transaction)
633 633
                     ) {
634 634
                         $count++;
635
-                        $events[ $registration->event_ID() ] = $registration->event();
635
+                        $events[$registration->event_ID()] = $registration->event();
636 636
                     }
637 637
                 }
638 638
             }
@@ -663,10 +663,10 @@  discard block
 block discarded – undo
663 663
     ) {
664 664
         $STS_ID = $transaction->status_ID();
665 665
         if (self::debug) {
666
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
667
-            echo '<br /> . . registration->ID: ' . $registration->ID();
668
-            echo '<br /> . . registration->status_ID: ' . $registration->status_ID();
669
-            echo '<br /> . . transaction->status_ID(): ' . $STS_ID;
666
+            echo '<br /><br /> '.__LINE__.') '.__METHOD__.'() ';
667
+            echo '<br /> . . registration->ID: '.$registration->ID();
668
+            echo '<br /> . . registration->status_ID: '.$registration->status_ID();
669
+            echo '<br /> . . transaction->status_ID(): '.$STS_ID;
670 670
         }
671 671
         if (
672 672
             // release Tickets for Failed Transactions and Abandoned Transactions
@@ -684,7 +684,7 @@  discard block
 block discarded – undo
684 684
                 echo '<br /> . . . registration HAS_RESERVED_TICKET_KEY: ';
685 685
                 var_dump($rsrvd);
686 686
             }
687
-            $registration->release_reserved_ticket(true, 'TicketSalesMonitor:'. __LINE__);
687
+            $registration->release_reserved_ticket(true, 'TicketSalesMonitor:'.__LINE__);
688 688
             return 1;
689 689
         }
690 690
         return 0;
@@ -710,7 +710,7 @@  discard block
 block discarded – undo
710 710
     public static function session_cart_reset(EE_Session $session)
711 711
     {
712 712
         if (self::debug) {
713
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
713
+            echo '<br /><br /> '.__LINE__.') '.__METHOD__.'() ';
714 714
         }
715 715
         // first check of the session has a valid Checkout object
716 716
         $checkout = $session->checkout();
@@ -749,7 +749,7 @@  discard block
 block discarded – undo
749 749
     protected function _session_cart_reset(EE_Cart $cart, EE_Session $session)
750 750
     {
751 751
         if (self::debug) {
752
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
752
+            echo '<br /><br /> '.__LINE__.') '.__METHOD__.'() ';
753 753
         }
754 754
         EE_Registry::instance()->load_helper('Line_Item');
755 755
         $ticket_line_items = $cart->get_tickets();
@@ -758,21 +758,21 @@  discard block
 block discarded – undo
758 758
         }
759 759
         foreach ($ticket_line_items as $ticket_line_item) {
760 760
             if (self::debug) {
761
-                echo '<br /> . ticket_line_item->ID(): ' . $ticket_line_item->ID();
761
+                echo '<br /> . ticket_line_item->ID(): '.$ticket_line_item->ID();
762 762
             }
763 763
             if ($ticket_line_item instanceof EE_Line_Item && $ticket_line_item->OBJ_type() === 'Ticket') {
764 764
                 if (self::debug) {
765
-                    echo '<br /> . . ticket_line_item->OBJ_ID(): ' . $ticket_line_item->OBJ_ID();
765
+                    echo '<br /> . . ticket_line_item->OBJ_ID(): '.$ticket_line_item->OBJ_ID();
766 766
                 }
767 767
                 $ticket = EEM_Ticket::instance()->get_one_by_ID($ticket_line_item->OBJ_ID());
768 768
                 if ($ticket instanceof EE_Ticket) {
769 769
                     if (self::debug) {
770
-                        echo '<br /> . . ticket->ID(): ' . $ticket->ID();
771
-                        echo '<br /> . . ticket_line_item->quantity(): ' . $ticket_line_item->quantity();
770
+                        echo '<br /> . . ticket->ID(): '.$ticket->ID();
771
+                        echo '<br /> . . ticket_line_item->quantity(): '.$ticket_line_item->quantity();
772 772
                     }
773 773
                     $ticket->add_extra_meta(
774 774
                         EE_Ticket::META_KEY_TICKET_RESERVATIONS,
775
-                        __LINE__ . ') ' . __METHOD__ . '() SID = ' . $session->id()
775
+                        __LINE__.') '.__METHOD__.'() SID = '.$session->id()
776 776
                     );
777 777
                     $this->_release_reserved_ticket($ticket, $ticket_line_item->quantity());
778 778
                 }
@@ -818,7 +818,7 @@  discard block
 block discarded – undo
818 818
     protected function _session_checkout_reset(EE_Checkout $checkout)
819 819
     {
820 820
         if (self::debug) {
821
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
821
+            echo '<br /><br /> '.__LINE__.') '.__METHOD__.'() ';
822 822
         }
823 823
         // we want to release the each registration's reserved tickets if the session was cleared, but not if this is a revisit
824 824
         if ($checkout->revisit || ! $checkout->transaction instanceof EE_Transaction) {
@@ -868,7 +868,7 @@  discard block
 block discarded – undo
868 868
                     __LINE__,
869 869
                     array($transaction),
870 870
                     false,
871
-                    'EE_Transaction: ' . $transaction->ID()
871
+                    'EE_Transaction: '.$transaction->ID()
872 872
                 );
873 873
             }
874 874
             return;
@@ -885,7 +885,7 @@  discard block
 block discarded – undo
885 885
                         __LINE__,
886 886
                         array($payment),
887 887
                         false,
888
-                        'EE_Transaction: ' . $transaction->ID()
888
+                        'EE_Transaction: '.$transaction->ID()
889 889
                     );
890 890
                 }
891 891
                 return;
@@ -945,7 +945,7 @@  discard block
 block discarded – undo
945 945
             }
946 946
             $total_line_item = $transaction->total_line_item();
947 947
             // $transaction_in_progress->line
948
-            if (! $total_line_item instanceof EE_Line_Item) {
948
+            if ( ! $total_line_item instanceof EE_Line_Item) {
949 949
                 throw new DomainException(
950 950
                     esc_html__(
951 951
                         'Transaction does not have a valid Total Line Item associated with it.',
@@ -1008,7 +1008,7 @@  discard block
 block discarded – undo
1008 1008
         $total_tickets_released = 0;
1009 1009
         $sold_out_events = array();
1010 1010
         foreach ($tickets_with_reservations as $ticket_with_reservations) {
1011
-            if (! $ticket_with_reservations instanceof EE_Ticket) {
1011
+            if ( ! $ticket_with_reservations instanceof EE_Ticket) {
1012 1012
                 continue;
1013 1013
             }
1014 1014
             $reserved_qty = $ticket_with_reservations->reserved();
@@ -1023,9 +1023,9 @@  discard block
 block discarded – undo
1023 1023
             if ($reserved_qty > 0) {
1024 1024
                 $ticket_with_reservations->add_extra_meta(
1025 1025
                     EE_Ticket::META_KEY_TICKET_RESERVATIONS,
1026
-                    __LINE__ . ') ' . $source . '()'
1026
+                    __LINE__.') '.$source.'()'
1027 1027
                 );
1028
-                $ticket_with_reservations->decrease_reserved($reserved_qty, true, 'TicketSalesMonitor:'. __LINE__);
1028
+                $ticket_with_reservations->decrease_reserved($reserved_qty, true, 'TicketSalesMonitor:'.__LINE__);
1029 1029
                 $ticket_with_reservations->save();
1030 1030
                 $total_tickets_released += $reserved_qty;
1031 1031
                 $event = $ticket_with_reservations->get_related_event();
@@ -1036,7 +1036,7 @@  discard block
 block discarded – undo
1036 1036
             }
1037 1037
         }
1038 1038
         // double check whether sold out events should remain sold out after releasing tickets
1039
-        if($sold_out_events !== array()){
1039
+        if ($sold_out_events !== array()) {
1040 1040
             foreach ($sold_out_events as $sold_out_event) {
1041 1041
                 /** @var EE_Event $sold_out_event */
1042 1042
                 $sold_out_event->perform_sold_out_status_check();
@@ -1068,7 +1068,7 @@  discard block
 block discarded – undo
1068 1068
         );
1069 1069
         return $wpdb->query(
1070 1070
             $wpdb->prepare(
1071
-                'DELETE FROM ' . EEM_Line_Item::instance()->table() . '
1071
+                'DELETE FROM '.EEM_Line_Item::instance()->table().'
1072 1072
                 WHERE TXN_ID = 0 AND LIN_timestamp <= %s',
1073 1073
                 // use GMT time because that's what LIN_timestamps are in
1074 1074
                 date('Y-m-d H:i:s', $session_lifespan->expiration())
Please login to merge, or discard this patch.
admin_pages/transactions/EE_Admin_Transactions_List_Table.class.php 1 patch
Indentation   +630 added lines, -630 removed lines patch added patch discarded remove patch
@@ -17,121 +17,121 @@  discard block
 block discarded – undo
17 17
 class EE_Admin_Transactions_List_Table extends EE_Admin_List_Table
18 18
 {
19 19
 
20
-    /**
21
-     * @var SessionLifespan $session_lifespan
22
-     */
23
-    private $session_lifespan;
24
-
25
-    private $_status;
26
-
27
-
28
-    /**
29
-     * @param \Transactions_Admin_Page $admin_page
30
-     * @param SessionLifespan          $lifespan
31
-     */
32
-    public function __construct(\Transactions_Admin_Page $admin_page, SessionLifespan $lifespan)
33
-    {
34
-        parent::__construct($admin_page);
35
-        $this->session_lifespan = $lifespan;
36
-        $this->_status = $this->_admin_page->get_transaction_status_array();
37
-    }
38
-
39
-
40
-    /**
41
-     *_setup_data
42
-     */
43
-    protected function _setup_data()
44
-    {
45
-        $this->_data           = $this->_admin_page->get_transactions($this->_per_page);
46
-        $status                = ! empty($this->_req_data['status']) ? $this->_req_data['status'] : 'all';
47
-        $this->_all_data_count = $this->_admin_page->get_transactions($this->_per_page, true, $status);
48
-    }
49
-
50
-
51
-    /**
52
-     *_set_properties
53
-     */
54
-    protected function _set_properties()
55
-    {
56
-        $this->_wp_list_args = array(
57
-            'singular' => __('transaction', 'event_espresso'),
58
-            'plural'   => __('transactions', 'event_espresso'),
59
-            'ajax'     => true,
60
-            'screen'   => $this->_admin_page->get_current_screen()->id,
61
-        );
62
-        $ID_column_name      = __('ID', 'event_espresso');
63
-        $ID_column_name      .= ' : <span class="show-on-mobile-view-only" style="float:none">';
64
-        $ID_column_name      .= __('Transaction Date', 'event_espresso');
65
-        $ID_column_name      .= '</span> ';
66
-        $this->_columns      = array(
67
-            'TXN_ID'        => $ID_column_name,
68
-            'TXN_timestamp' => __('Transaction Date', 'event_espresso'),
69
-            'TXN_total'     => __('Total', 'event_espresso'),
70
-            'TXN_paid'      => __('Paid', 'event_espresso'),
71
-            'ATT_fname'     => __('Primary Registrant', 'event_espresso'),
72
-            'event_name'    => __('Event', 'event_espresso'),
73
-            'actions'       => __('Actions', 'event_espresso'),
74
-        );
75
-
76
-        $this->_sortable_columns = array(
77
-            'TXN_ID'        => array('TXN_ID' => false),
78
-            'event_name'    => array('event_name' => false),
79
-            'ATT_fname'     => array('ATT_fname' => false),
80
-            'TXN_timestamp' => array('TXN_timestamp' => true) //true means its already sorted
81
-        );
82
-
83
-        $this->_primary_column = 'TXN_ID';
84
-
85
-        $this->_hidden_columns = array();
86
-    }
87
-
88
-
89
-    /**
90
-     * This simply sets up the row class for the table rows.
91
-     * Allows for easier overriding of child methods for setting up sorting.
92
-     *
93
-     * @param  EE_Transaction $transaction the current item
94
-     * @return string
95
-     * @throws \EE_Error
96
-     */
97
-    protected function _get_row_class($transaction)
98
-    {
99
-        $class = parent::_get_row_class($transaction);
100
-        //add status class
101
-        $class .= ' ee-status-strip txn-status-' . $transaction->status_ID();
102
-        if ($this->_has_checkbox_column) {
103
-            $class .= ' has-checkbox-column';
104
-        }
105
-        return $class;
106
-    }
107
-
108
-
109
-    /**
110
-     * _get_table_filters
111
-     * We use this to assemble and return any filters that are associated with this table that help further refine what
112
-     * get's shown in the table.
113
-     *
114
-     * @abstract
115
-     * @access protected
116
-     * @return array
117
-     */
118
-    protected function _get_table_filters()
119
-    {
120
-        $filters    = array();
121
-        $start_date = isset($this->_req_data['txn-filter-start-date'])
122
-            ? wp_strip_all_tags($this->_req_data['txn-filter-start-date'])
123
-            : date(
124
-                'm/d/Y',
125
-                strtotime('-10 year')
126
-            );
127
-        $end_date   = isset($this->_req_data['txn-filter-end-date'])
128
-            ? wp_strip_all_tags($this->_req_data['txn-filter-end-date'])
129
-            : date(
130
-                'm/d/Y',
131
-                current_time('timestamp')
132
-            );
133
-        ob_start();
134
-        ?>
20
+	/**
21
+	 * @var SessionLifespan $session_lifespan
22
+	 */
23
+	private $session_lifespan;
24
+
25
+	private $_status;
26
+
27
+
28
+	/**
29
+	 * @param \Transactions_Admin_Page $admin_page
30
+	 * @param SessionLifespan          $lifespan
31
+	 */
32
+	public function __construct(\Transactions_Admin_Page $admin_page, SessionLifespan $lifespan)
33
+	{
34
+		parent::__construct($admin_page);
35
+		$this->session_lifespan = $lifespan;
36
+		$this->_status = $this->_admin_page->get_transaction_status_array();
37
+	}
38
+
39
+
40
+	/**
41
+	 *_setup_data
42
+	 */
43
+	protected function _setup_data()
44
+	{
45
+		$this->_data           = $this->_admin_page->get_transactions($this->_per_page);
46
+		$status                = ! empty($this->_req_data['status']) ? $this->_req_data['status'] : 'all';
47
+		$this->_all_data_count = $this->_admin_page->get_transactions($this->_per_page, true, $status);
48
+	}
49
+
50
+
51
+	/**
52
+	 *_set_properties
53
+	 */
54
+	protected function _set_properties()
55
+	{
56
+		$this->_wp_list_args = array(
57
+			'singular' => __('transaction', 'event_espresso'),
58
+			'plural'   => __('transactions', 'event_espresso'),
59
+			'ajax'     => true,
60
+			'screen'   => $this->_admin_page->get_current_screen()->id,
61
+		);
62
+		$ID_column_name      = __('ID', 'event_espresso');
63
+		$ID_column_name      .= ' : <span class="show-on-mobile-view-only" style="float:none">';
64
+		$ID_column_name      .= __('Transaction Date', 'event_espresso');
65
+		$ID_column_name      .= '</span> ';
66
+		$this->_columns      = array(
67
+			'TXN_ID'        => $ID_column_name,
68
+			'TXN_timestamp' => __('Transaction Date', 'event_espresso'),
69
+			'TXN_total'     => __('Total', 'event_espresso'),
70
+			'TXN_paid'      => __('Paid', 'event_espresso'),
71
+			'ATT_fname'     => __('Primary Registrant', 'event_espresso'),
72
+			'event_name'    => __('Event', 'event_espresso'),
73
+			'actions'       => __('Actions', 'event_espresso'),
74
+		);
75
+
76
+		$this->_sortable_columns = array(
77
+			'TXN_ID'        => array('TXN_ID' => false),
78
+			'event_name'    => array('event_name' => false),
79
+			'ATT_fname'     => array('ATT_fname' => false),
80
+			'TXN_timestamp' => array('TXN_timestamp' => true) //true means its already sorted
81
+		);
82
+
83
+		$this->_primary_column = 'TXN_ID';
84
+
85
+		$this->_hidden_columns = array();
86
+	}
87
+
88
+
89
+	/**
90
+	 * This simply sets up the row class for the table rows.
91
+	 * Allows for easier overriding of child methods for setting up sorting.
92
+	 *
93
+	 * @param  EE_Transaction $transaction the current item
94
+	 * @return string
95
+	 * @throws \EE_Error
96
+	 */
97
+	protected function _get_row_class($transaction)
98
+	{
99
+		$class = parent::_get_row_class($transaction);
100
+		//add status class
101
+		$class .= ' ee-status-strip txn-status-' . $transaction->status_ID();
102
+		if ($this->_has_checkbox_column) {
103
+			$class .= ' has-checkbox-column';
104
+		}
105
+		return $class;
106
+	}
107
+
108
+
109
+	/**
110
+	 * _get_table_filters
111
+	 * We use this to assemble and return any filters that are associated with this table that help further refine what
112
+	 * get's shown in the table.
113
+	 *
114
+	 * @abstract
115
+	 * @access protected
116
+	 * @return array
117
+	 */
118
+	protected function _get_table_filters()
119
+	{
120
+		$filters    = array();
121
+		$start_date = isset($this->_req_data['txn-filter-start-date'])
122
+			? wp_strip_all_tags($this->_req_data['txn-filter-start-date'])
123
+			: date(
124
+				'm/d/Y',
125
+				strtotime('-10 year')
126
+			);
127
+		$end_date   = isset($this->_req_data['txn-filter-end-date'])
128
+			? wp_strip_all_tags($this->_req_data['txn-filter-end-date'])
129
+			: date(
130
+				'm/d/Y',
131
+				current_time('timestamp')
132
+			);
133
+		ob_start();
134
+		?>
135 135
         <label for="txn-filter-start-date">Display Transactions from </label>
136 136
         <input id="txn-filter-start-date" class="datepicker" type="text" value="<?php echo $start_date; ?>"
137 137
                name="txn-filter-start-date" size="15"/>
@@ -139,551 +139,551 @@  discard block
 block discarded – undo
139 139
         <input id="txn-filter-end-date" class="datepicker" type="text" value="<?php echo $end_date; ?>"
140 140
                name="txn-filter-end-date" size="15"/>
141 141
         <?php
142
-        $filters[] = ob_get_contents();
143
-        ob_end_clean();
144
-        return $filters;
145
-    }
146
-
147
-
148
-    /**
149
-     *_add_view_counts
150
-     */
151
-    protected function _add_view_counts()
152
-    {
153
-        $this->_views['all']['count']       = $this->_admin_page->get_transactions($this->_per_page, true, 'all');
154
-        $this->_views['abandoned']['count'] = $this->_admin_page->get_transactions($this->_per_page, true, 'abandoned');
155
-        $this->_views['failed']['count']    = $this->_admin_page->get_transactions($this->_per_page, true, 'failed');
156
-    }
157
-
158
-
159
-    /**
160
-     *    column TXN_ID
161
-     *
162
-     * @param \EE_Transaction $transaction
163
-     * @return string
164
-     * @throws \EE_Error
165
-     */
166
-    public function column_TXN_ID(EE_Transaction $transaction)
167
-    {
168
-        $view_lnk_url = EE_Admin_Page::add_query_args_and_nonce(array(
169
-            'action' => 'view_transaction',
170
-            'TXN_ID' => $transaction->ID(),
171
-        ), TXN_ADMIN_URL);
172
-        $content      = '<a href="' . $view_lnk_url . '"'
173
-                        . ' title="' . esc_attr__('Go to Transaction Details', 'event_espresso') . '">'
174
-                        . $transaction->ID()
175
-                        . '</a>';
176
-
177
-        //txn timestamp
178
-        $content .= '  <span class="show-on-mobile-view-only">' . $this->_get_txn_timestamp($transaction) . '</span>';
179
-        return $content;
180
-    }
181
-
182
-
183
-    /**
184
-     * @param \EE_Transaction $transaction
185
-     * @return string
186
-     * @throws EE_Error
187
-     * @throws InvalidArgumentException
188
-     * @throws InvalidDataTypeException
189
-     * @throws InvalidInterfaceException
190
-     */
191
-    protected function _get_txn_timestamp(EE_Transaction $transaction)
192
-    {
193
-        // is TXN less than 2 hours old ?
194
-        if (($transaction->failed() || $transaction->is_abandoned())
195
-            && $this->session_lifespan->expiration() < $transaction->datetime(false, true)
196
-        ) {
197
-            $timestamp = esc_html__('TXN in progress...', 'event_espresso');
198
-        } else {
199
-            $timestamp = $transaction->get_i18n_datetime('TXN_timestamp');
200
-        }
201
-        return $timestamp;
202
-    }
203
-
204
-
205
-    /**
206
-     *    column_cb
207
-     *
208
-     * @param \EE_Transaction $transaction
209
-     * @return string
210
-     * @throws \EE_Error
211
-     */
212
-    public function column_cb($transaction)
213
-    {
214
-        return sprintf(
215
-            '<input type="checkbox" name="%1$s[]" value="%2$s" />',
216
-            $this->_wp_list_args['singular'],
217
-            $transaction->ID()
218
-        );
219
-    }
220
-
221
-
222
-    /**
223
-     *    column_TXN_timestamp
224
-     *
225
-     * @param \EE_Transaction $transaction
226
-     * @return string
227
-     * @throws \EE_Error
228
-     */
229
-    public function column_TXN_timestamp(EE_Transaction $transaction)
230
-    {
231
-        $view_lnk_url = EE_Admin_Page::add_query_args_and_nonce(array(
232
-            'action' => 'view_transaction',
233
-            'TXN_ID' => $transaction->ID(),
234
-        ), TXN_ADMIN_URL);
235
-        $txn_date     = '<a href="' . $view_lnk_url . '"'
236
-                        . ' title="'
237
-                        . esc_attr__('View Transaction Details for TXN #', 'event_espresso') . $transaction->ID() . '">'
238
-                        . $this->_get_txn_timestamp($transaction)
239
-                        . '</a>';
240
-        //status
241
-        $txn_date .= '<br><span class="ee-status-text-small">'
242
-                     . EEH_Template::pretty_status(
243
-                         $transaction->status_ID(),
244
-                         false,
245
-                         'sentence'
246
-                     )
247
-                     . '</span>';
248
-        return $txn_date;
249
-    }
250
-
251
-
252
-    /**
253
-     *    column_TXN_total
254
-     *
255
-     * @param \EE_Transaction $transaction
256
-     * @return string
257
-     * @throws \EE_Error
258
-     */
259
-    public function column_TXN_total(EE_Transaction $transaction)
260
-    {
261
-        if ($transaction->get('TXN_total') > 0) {
262
-            return '<span class="txn-pad-rght">'
263
-                   . apply_filters(
264
-                       'FHEE__EE_Admin_Transactions_List_Table__column_TXN_total__TXN_total',
265
-                       $transaction->get_pretty('TXN_total'),
266
-                       $transaction
267
-                   )
268
-                   . '</span>';
269
-        } else {
270
-            return '<span class="txn-overview-free-event-spn">' . esc_html__('free', 'event_espresso') . '</span>';
271
-        }
272
-    }
273
-
274
-
275
-    /**
276
-     *    column_TXN_paid
277
-     *
278
-     * @param \EE_Transaction $transaction
279
-     * @return mixed|string
280
-     * @throws \EE_Error
281
-     */
282
-    public function column_TXN_paid(EE_Transaction $transaction)
283
-    {
284
-        $transaction_total = $transaction->get('TXN_total');
285
-        $transaction_paid  = $transaction->get('TXN_paid');
286
-
287
-        if (\EEH_Money::compare_floats($transaction_total, 0, '>')) {
288
-            // monies owing
289
-            $span_class = 'txn-overview-part-payment-spn';
290
-            if (\EEH_Money::compare_floats($transaction_paid, $transaction_total, '>=')) {
291
-                // paid in full
292
-                $span_class = 'txn-overview-full-payment-spn';
293
-            } elseif (\EEH_Money::compare_floats($transaction_paid, 0, '==')) {
294
-                // no payments made
295
-                $span_class = 'txn-overview-no-payment-spn';
296
-            }
297
-        } else {
298
-            $span_class       = 'txn-overview-free-event-spn';
299
-            $transaction_paid = 0;
300
-        }
301
-
302
-        $payment_method      = $transaction->payment_method();
303
-        $payment_method_name = $payment_method instanceof EE_Payment_Method
304
-            ? $payment_method->admin_name()
305
-            : esc_html__('Unknown', 'event_espresso');
306
-        $transaction_paid_content = $transaction_paid !== 0 ? $transaction->get_pretty('TXN_paid') : $transaction_paid;
307
-
308
-        $content = '<span class="' . $span_class . ' txn-pad-rght">'
309
-                   . $transaction_paid_content
310
-                   . '</span>';
311
-        if ($transaction_paid > 0) {
312
-            $content .= '<br><span class="ee-status-text-small">'
313
-                        . sprintf(
314
-                            esc_html__('...via %s', 'event_espresso'),
315
-                            $payment_method_name
316
-                        )
317
-                        . '</span>';
318
-        }
319
-        return $content;
320
-    }
321
-
322
-
323
-    /**
324
-     *    column_ATT_fname
325
-     *
326
-     * @param \EE_Transaction $transaction
327
-     * @return string
328
-     * @throws EE_Error
329
-     * @throws InvalidArgumentException
330
-     * @throws InvalidDataTypeException
331
-     * @throws InvalidInterfaceException
332
-     */
333
-    public function column_ATT_fname(EE_Transaction $transaction)
334
-    {
335
-        $primary_reg = $transaction->primary_registration();
336
-        $attendee    = $primary_reg->get_first_related('Attendee');
337
-        if ($attendee instanceof EE_Attendee) {
338
-            $edit_lnk_url = EE_Admin_Page::add_query_args_and_nonce(array(
339
-                'action'  => 'view_registration',
340
-                '_REG_ID' => $primary_reg->ID(),
341
-            ), REG_ADMIN_URL);
342
-            $content      = EE_Registry::instance()->CAP->current_user_can(
343
-                'ee_read_registration',
344
-                'espresso_registrations_view_registration',
345
-                $primary_reg->ID()
346
-            )
347
-                ? '<a href="' . $edit_lnk_url . '"'
348
-                    . ' title="' . esc_attr__('View Registration Details', 'event_espresso') . '">'
349
-                    . $attendee->full_name()
350
-                    . '</a>'
351
-                : $attendee->full_name();
352
-            $content      .= '<br>' . $attendee->email();
353
-            return $content;
354
-        }
355
-        return $transaction->failed() || $transaction->is_abandoned()
356
-            ? esc_html__('no contact record.', 'event_espresso')
357
-            : esc_html__(
358
-                'No contact record, because the transaction was abandoned or the registration process failed.',
359
-                'event_espresso'
360
-            );
361
-    }
362
-
363
-
364
-    /**
365
-     *    column_ATT_email
366
-     *
367
-     * @param \EE_Transaction $transaction
368
-     * @return string
369
-     * @throws \EE_Error
370
-     */
371
-    public function column_ATT_email(EE_Transaction $transaction)
372
-    {
373
-        $attendee = $transaction->primary_registration()->get_first_related('Attendee');
374
-        if (! empty($attendee)) {
375
-            return '<a href="mailto:' . $attendee->get('ATT_email') . '">'
376
-                   . $attendee->get('ATT_email')
377
-                   . '</a>';
378
-        } else {
379
-            return $transaction->failed() || $transaction->is_abandoned()
380
-                ? esc_html__('no contact record.', 'event_espresso')
381
-                : esc_html__(
382
-                    'No contact record, because the transaction was abandoned or the registration process failed.',
383
-                    'event_espresso'
384
-                );
385
-        }
386
-    }
387
-
388
-
389
-    /**
390
-     *    column_event_name
391
-     *
392
-     * @param \EE_Transaction $transaction
393
-     * @return string
394
-     * @throws EE_Error
395
-     * @throws InvalidArgumentException
396
-     * @throws InvalidDataTypeException
397
-     * @throws InvalidInterfaceException
398
-     */
399
-    public function column_event_name(EE_Transaction $transaction)
400
-    {
401
-        $actions = array();
402
-        $event   = $transaction->primary_registration()->get_first_related('Event');
403
-        if (! empty($event)) {
404
-            $edit_event_url = EE_Admin_Page::add_query_args_and_nonce(
405
-                array('action' => 'edit', 'post' => $event->ID()),
406
-                EVENTS_ADMIN_URL
407
-            );
408
-            $event_name     = $event->get('EVT_name');
409
-
410
-            //filter this view by transactions for this event
411
-            $txn_by_event_lnk = EE_Admin_Page::add_query_args_and_nonce(array(
412
-                'action' => 'default',
413
-                'EVT_ID' => $event->ID(),
414
-            ));
415
-            if (empty($this->_req_data['EVT_ID'])
416
-                && EE_Registry::instance()->CAP->current_user_can(
417
-                    'ee_edit_event',
418
-                    'espresso_events_edit',
419
-                    $event->ID()
420
-                )
421
-            ) {
422
-                $actions['filter_by_event'] = '<a href="' . $txn_by_event_lnk . '"'
423
-                        . ' title="' . esc_attr__('Filter transactions by this event', 'event_espresso') . '">'
424
-                        . esc_html__('View Transactions for this event', 'event_espresso')
425
-                        . '</a>';
426
-            }
427
-
428
-            return sprintf(
429
-                '%1$s %2$s',
430
-                EE_Registry::instance()->CAP->current_user_can(
431
-                    'ee_edit_event',
432
-                    'espresso_events_edit',
433
-                    $event->ID()
434
-                )
435
-                    ? '<a href="' . $edit_event_url . '"'
436
-                        . ' title="'
437
-                        . sprintf(
438
-                            esc_attr__('Edit Event: %s', 'event_espresso'),
439
-                            $event->get('EVT_name')
440
-                        )
441
-                        . '">'
442
-                        . wp_trim_words(
443
-                            $event_name,
444
-                            30,
445
-                            '...'
446
-                        )
447
-                        . '</a>'
448
-                        : wp_trim_words($event_name, 30, '...'),
449
-                $this->row_actions($actions)
450
-            );
451
-        } else {
452
-            return esc_html__(
453
-                'The event associated with this transaction via the primary registration cannot be retrieved.',
454
-                'event_espresso'
455
-            );
456
-        }
457
-    }
458
-
459
-
460
-    /**
461
-     *    column_actions
462
-     *
463
-     * @param \EE_Transaction $transaction
464
-     * @return string
465
-     * @throws \EE_Error
466
-     */
467
-    public function column_actions(EE_Transaction $transaction)
468
-    {
469
-        return $this->_action_string(
470
-            $this->get_transaction_details_link($transaction)
471
-            . $this->get_invoice_link($transaction)
472
-            . $this->get_receipt_link($transaction)
473
-            . $this->get_primary_registration_details_link($transaction)
474
-            . $this->get_send_payment_reminder_trigger_link($transaction)
475
-            . $this->get_payment_overview_link($transaction)
476
-            . $this->get_related_messages_link($transaction),
477
-            $transaction,
478
-            'ul',
479
-            'txn-overview-actions-ul'
480
-        );
481
-    }
482
-
483
-
484
-    /**
485
-     * Get the transaction details link.
486
-     * @param EE_Transaction $transaction
487
-     * @return string
488
-     * @throws EE_Error
489
-     */
490
-    protected function get_transaction_details_link(EE_Transaction $transaction)
491
-    {
492
-        $url          = EE_Admin_Page::add_query_args_and_nonce(array(
493
-            'action' => 'view_transaction',
494
-            'TXN_ID' => $transaction->ID(),
495
-        ), TXN_ADMIN_URL);
496
-        return '
142
+		$filters[] = ob_get_contents();
143
+		ob_end_clean();
144
+		return $filters;
145
+	}
146
+
147
+
148
+	/**
149
+	 *_add_view_counts
150
+	 */
151
+	protected function _add_view_counts()
152
+	{
153
+		$this->_views['all']['count']       = $this->_admin_page->get_transactions($this->_per_page, true, 'all');
154
+		$this->_views['abandoned']['count'] = $this->_admin_page->get_transactions($this->_per_page, true, 'abandoned');
155
+		$this->_views['failed']['count']    = $this->_admin_page->get_transactions($this->_per_page, true, 'failed');
156
+	}
157
+
158
+
159
+	/**
160
+	 *    column TXN_ID
161
+	 *
162
+	 * @param \EE_Transaction $transaction
163
+	 * @return string
164
+	 * @throws \EE_Error
165
+	 */
166
+	public function column_TXN_ID(EE_Transaction $transaction)
167
+	{
168
+		$view_lnk_url = EE_Admin_Page::add_query_args_and_nonce(array(
169
+			'action' => 'view_transaction',
170
+			'TXN_ID' => $transaction->ID(),
171
+		), TXN_ADMIN_URL);
172
+		$content      = '<a href="' . $view_lnk_url . '"'
173
+						. ' title="' . esc_attr__('Go to Transaction Details', 'event_espresso') . '">'
174
+						. $transaction->ID()
175
+						. '</a>';
176
+
177
+		//txn timestamp
178
+		$content .= '  <span class="show-on-mobile-view-only">' . $this->_get_txn_timestamp($transaction) . '</span>';
179
+		return $content;
180
+	}
181
+
182
+
183
+	/**
184
+	 * @param \EE_Transaction $transaction
185
+	 * @return string
186
+	 * @throws EE_Error
187
+	 * @throws InvalidArgumentException
188
+	 * @throws InvalidDataTypeException
189
+	 * @throws InvalidInterfaceException
190
+	 */
191
+	protected function _get_txn_timestamp(EE_Transaction $transaction)
192
+	{
193
+		// is TXN less than 2 hours old ?
194
+		if (($transaction->failed() || $transaction->is_abandoned())
195
+			&& $this->session_lifespan->expiration() < $transaction->datetime(false, true)
196
+		) {
197
+			$timestamp = esc_html__('TXN in progress...', 'event_espresso');
198
+		} else {
199
+			$timestamp = $transaction->get_i18n_datetime('TXN_timestamp');
200
+		}
201
+		return $timestamp;
202
+	}
203
+
204
+
205
+	/**
206
+	 *    column_cb
207
+	 *
208
+	 * @param \EE_Transaction $transaction
209
+	 * @return string
210
+	 * @throws \EE_Error
211
+	 */
212
+	public function column_cb($transaction)
213
+	{
214
+		return sprintf(
215
+			'<input type="checkbox" name="%1$s[]" value="%2$s" />',
216
+			$this->_wp_list_args['singular'],
217
+			$transaction->ID()
218
+		);
219
+	}
220
+
221
+
222
+	/**
223
+	 *    column_TXN_timestamp
224
+	 *
225
+	 * @param \EE_Transaction $transaction
226
+	 * @return string
227
+	 * @throws \EE_Error
228
+	 */
229
+	public function column_TXN_timestamp(EE_Transaction $transaction)
230
+	{
231
+		$view_lnk_url = EE_Admin_Page::add_query_args_and_nonce(array(
232
+			'action' => 'view_transaction',
233
+			'TXN_ID' => $transaction->ID(),
234
+		), TXN_ADMIN_URL);
235
+		$txn_date     = '<a href="' . $view_lnk_url . '"'
236
+						. ' title="'
237
+						. esc_attr__('View Transaction Details for TXN #', 'event_espresso') . $transaction->ID() . '">'
238
+						. $this->_get_txn_timestamp($transaction)
239
+						. '</a>';
240
+		//status
241
+		$txn_date .= '<br><span class="ee-status-text-small">'
242
+					 . EEH_Template::pretty_status(
243
+						 $transaction->status_ID(),
244
+						 false,
245
+						 'sentence'
246
+					 )
247
+					 . '</span>';
248
+		return $txn_date;
249
+	}
250
+
251
+
252
+	/**
253
+	 *    column_TXN_total
254
+	 *
255
+	 * @param \EE_Transaction $transaction
256
+	 * @return string
257
+	 * @throws \EE_Error
258
+	 */
259
+	public function column_TXN_total(EE_Transaction $transaction)
260
+	{
261
+		if ($transaction->get('TXN_total') > 0) {
262
+			return '<span class="txn-pad-rght">'
263
+				   . apply_filters(
264
+					   'FHEE__EE_Admin_Transactions_List_Table__column_TXN_total__TXN_total',
265
+					   $transaction->get_pretty('TXN_total'),
266
+					   $transaction
267
+				   )
268
+				   . '</span>';
269
+		} else {
270
+			return '<span class="txn-overview-free-event-spn">' . esc_html__('free', 'event_espresso') . '</span>';
271
+		}
272
+	}
273
+
274
+
275
+	/**
276
+	 *    column_TXN_paid
277
+	 *
278
+	 * @param \EE_Transaction $transaction
279
+	 * @return mixed|string
280
+	 * @throws \EE_Error
281
+	 */
282
+	public function column_TXN_paid(EE_Transaction $transaction)
283
+	{
284
+		$transaction_total = $transaction->get('TXN_total');
285
+		$transaction_paid  = $transaction->get('TXN_paid');
286
+
287
+		if (\EEH_Money::compare_floats($transaction_total, 0, '>')) {
288
+			// monies owing
289
+			$span_class = 'txn-overview-part-payment-spn';
290
+			if (\EEH_Money::compare_floats($transaction_paid, $transaction_total, '>=')) {
291
+				// paid in full
292
+				$span_class = 'txn-overview-full-payment-spn';
293
+			} elseif (\EEH_Money::compare_floats($transaction_paid, 0, '==')) {
294
+				// no payments made
295
+				$span_class = 'txn-overview-no-payment-spn';
296
+			}
297
+		} else {
298
+			$span_class       = 'txn-overview-free-event-spn';
299
+			$transaction_paid = 0;
300
+		}
301
+
302
+		$payment_method      = $transaction->payment_method();
303
+		$payment_method_name = $payment_method instanceof EE_Payment_Method
304
+			? $payment_method->admin_name()
305
+			: esc_html__('Unknown', 'event_espresso');
306
+		$transaction_paid_content = $transaction_paid !== 0 ? $transaction->get_pretty('TXN_paid') : $transaction_paid;
307
+
308
+		$content = '<span class="' . $span_class . ' txn-pad-rght">'
309
+				   . $transaction_paid_content
310
+				   . '</span>';
311
+		if ($transaction_paid > 0) {
312
+			$content .= '<br><span class="ee-status-text-small">'
313
+						. sprintf(
314
+							esc_html__('...via %s', 'event_espresso'),
315
+							$payment_method_name
316
+						)
317
+						. '</span>';
318
+		}
319
+		return $content;
320
+	}
321
+
322
+
323
+	/**
324
+	 *    column_ATT_fname
325
+	 *
326
+	 * @param \EE_Transaction $transaction
327
+	 * @return string
328
+	 * @throws EE_Error
329
+	 * @throws InvalidArgumentException
330
+	 * @throws InvalidDataTypeException
331
+	 * @throws InvalidInterfaceException
332
+	 */
333
+	public function column_ATT_fname(EE_Transaction $transaction)
334
+	{
335
+		$primary_reg = $transaction->primary_registration();
336
+		$attendee    = $primary_reg->get_first_related('Attendee');
337
+		if ($attendee instanceof EE_Attendee) {
338
+			$edit_lnk_url = EE_Admin_Page::add_query_args_and_nonce(array(
339
+				'action'  => 'view_registration',
340
+				'_REG_ID' => $primary_reg->ID(),
341
+			), REG_ADMIN_URL);
342
+			$content      = EE_Registry::instance()->CAP->current_user_can(
343
+				'ee_read_registration',
344
+				'espresso_registrations_view_registration',
345
+				$primary_reg->ID()
346
+			)
347
+				? '<a href="' . $edit_lnk_url . '"'
348
+					. ' title="' . esc_attr__('View Registration Details', 'event_espresso') . '">'
349
+					. $attendee->full_name()
350
+					. '</a>'
351
+				: $attendee->full_name();
352
+			$content      .= '<br>' . $attendee->email();
353
+			return $content;
354
+		}
355
+		return $transaction->failed() || $transaction->is_abandoned()
356
+			? esc_html__('no contact record.', 'event_espresso')
357
+			: esc_html__(
358
+				'No contact record, because the transaction was abandoned or the registration process failed.',
359
+				'event_espresso'
360
+			);
361
+	}
362
+
363
+
364
+	/**
365
+	 *    column_ATT_email
366
+	 *
367
+	 * @param \EE_Transaction $transaction
368
+	 * @return string
369
+	 * @throws \EE_Error
370
+	 */
371
+	public function column_ATT_email(EE_Transaction $transaction)
372
+	{
373
+		$attendee = $transaction->primary_registration()->get_first_related('Attendee');
374
+		if (! empty($attendee)) {
375
+			return '<a href="mailto:' . $attendee->get('ATT_email') . '">'
376
+				   . $attendee->get('ATT_email')
377
+				   . '</a>';
378
+		} else {
379
+			return $transaction->failed() || $transaction->is_abandoned()
380
+				? esc_html__('no contact record.', 'event_espresso')
381
+				: esc_html__(
382
+					'No contact record, because the transaction was abandoned or the registration process failed.',
383
+					'event_espresso'
384
+				);
385
+		}
386
+	}
387
+
388
+
389
+	/**
390
+	 *    column_event_name
391
+	 *
392
+	 * @param \EE_Transaction $transaction
393
+	 * @return string
394
+	 * @throws EE_Error
395
+	 * @throws InvalidArgumentException
396
+	 * @throws InvalidDataTypeException
397
+	 * @throws InvalidInterfaceException
398
+	 */
399
+	public function column_event_name(EE_Transaction $transaction)
400
+	{
401
+		$actions = array();
402
+		$event   = $transaction->primary_registration()->get_first_related('Event');
403
+		if (! empty($event)) {
404
+			$edit_event_url = EE_Admin_Page::add_query_args_and_nonce(
405
+				array('action' => 'edit', 'post' => $event->ID()),
406
+				EVENTS_ADMIN_URL
407
+			);
408
+			$event_name     = $event->get('EVT_name');
409
+
410
+			//filter this view by transactions for this event
411
+			$txn_by_event_lnk = EE_Admin_Page::add_query_args_and_nonce(array(
412
+				'action' => 'default',
413
+				'EVT_ID' => $event->ID(),
414
+			));
415
+			if (empty($this->_req_data['EVT_ID'])
416
+				&& EE_Registry::instance()->CAP->current_user_can(
417
+					'ee_edit_event',
418
+					'espresso_events_edit',
419
+					$event->ID()
420
+				)
421
+			) {
422
+				$actions['filter_by_event'] = '<a href="' . $txn_by_event_lnk . '"'
423
+						. ' title="' . esc_attr__('Filter transactions by this event', 'event_espresso') . '">'
424
+						. esc_html__('View Transactions for this event', 'event_espresso')
425
+						. '</a>';
426
+			}
427
+
428
+			return sprintf(
429
+				'%1$s %2$s',
430
+				EE_Registry::instance()->CAP->current_user_can(
431
+					'ee_edit_event',
432
+					'espresso_events_edit',
433
+					$event->ID()
434
+				)
435
+					? '<a href="' . $edit_event_url . '"'
436
+						. ' title="'
437
+						. sprintf(
438
+							esc_attr__('Edit Event: %s', 'event_espresso'),
439
+							$event->get('EVT_name')
440
+						)
441
+						. '">'
442
+						. wp_trim_words(
443
+							$event_name,
444
+							30,
445
+							'...'
446
+						)
447
+						. '</a>'
448
+						: wp_trim_words($event_name, 30, '...'),
449
+				$this->row_actions($actions)
450
+			);
451
+		} else {
452
+			return esc_html__(
453
+				'The event associated with this transaction via the primary registration cannot be retrieved.',
454
+				'event_espresso'
455
+			);
456
+		}
457
+	}
458
+
459
+
460
+	/**
461
+	 *    column_actions
462
+	 *
463
+	 * @param \EE_Transaction $transaction
464
+	 * @return string
465
+	 * @throws \EE_Error
466
+	 */
467
+	public function column_actions(EE_Transaction $transaction)
468
+	{
469
+		return $this->_action_string(
470
+			$this->get_transaction_details_link($transaction)
471
+			. $this->get_invoice_link($transaction)
472
+			. $this->get_receipt_link($transaction)
473
+			. $this->get_primary_registration_details_link($transaction)
474
+			. $this->get_send_payment_reminder_trigger_link($transaction)
475
+			. $this->get_payment_overview_link($transaction)
476
+			. $this->get_related_messages_link($transaction),
477
+			$transaction,
478
+			'ul',
479
+			'txn-overview-actions-ul'
480
+		);
481
+	}
482
+
483
+
484
+	/**
485
+	 * Get the transaction details link.
486
+	 * @param EE_Transaction $transaction
487
+	 * @return string
488
+	 * @throws EE_Error
489
+	 */
490
+	protected function get_transaction_details_link(EE_Transaction $transaction)
491
+	{
492
+		$url          = EE_Admin_Page::add_query_args_and_nonce(array(
493
+			'action' => 'view_transaction',
494
+			'TXN_ID' => $transaction->ID(),
495
+		), TXN_ADMIN_URL);
496
+		return '
497 497
 			<li>
498 498
 				<a href="' . $url . '"'
499
-                    . ' title="' . esc_attr__('View Transaction Details', 'event_espresso') . '" class="tiny-text">
499
+					. ' title="' . esc_attr__('View Transaction Details', 'event_espresso') . '" class="tiny-text">
500 500
 					<span class="dashicons dashicons-cart"></span>
501 501
 				</a>
502 502
 			</li>';
503
-    }
504
-
505
-
506
-    /**
507
-     * Get the invoice link for the given registration.
508
-     * @param EE_Transaction $transaction
509
-     * @return string
510
-     * @throws EE_Error
511
-     */
512
-    protected function get_invoice_link(EE_Transaction $transaction)
513
-    {
514
-        $registration = $transaction->primary_registration();
515
-        if ($registration instanceof EE_Registration) {
516
-            $url = $registration->invoice_url();
517
-            //only show invoice link if message type is active.
518
-            if ($registration->attendee() instanceof EE_Attendee
519
-                && EEH_MSG_Template::is_mt_active('invoice')
520
-            ) {
521
-                return '
503
+	}
504
+
505
+
506
+	/**
507
+	 * Get the invoice link for the given registration.
508
+	 * @param EE_Transaction $transaction
509
+	 * @return string
510
+	 * @throws EE_Error
511
+	 */
512
+	protected function get_invoice_link(EE_Transaction $transaction)
513
+	{
514
+		$registration = $transaction->primary_registration();
515
+		if ($registration instanceof EE_Registration) {
516
+			$url = $registration->invoice_url();
517
+			//only show invoice link if message type is active.
518
+			if ($registration->attendee() instanceof EE_Attendee
519
+				&& EEH_MSG_Template::is_mt_active('invoice')
520
+			) {
521
+				return '
522 522
                 <li>
523 523
                     <a title="' . esc_attr__('View Transaction Invoice', 'event_espresso') . '"'
524
-                       . ' target="_blank" href="' . $url . '" class="tiny-text">
524
+					   . ' target="_blank" href="' . $url . '" class="tiny-text">
525 525
                         <span class="dashicons dashicons-media-spreadsheet ee-icon-size-18"></span>
526 526
                     </a>
527 527
                 </li>';
528
-            }
529
-        }
530
-        return '';
531
-    }
532
-
533
-
534
-    /**
535
-     * Get the receipt link for the transaction.
536
-     * @param EE_Transaction $transaction
537
-     * @return string
538
-     * @throws EE_Error
539
-     */
540
-    protected function get_receipt_link(EE_Transaction $transaction)
541
-    {
542
-        $registration = $transaction->primary_registration();
543
-        if ($registration instanceof EE_Registration) {
544
-            $url = $registration->receipt_url();
545
-            //only show receipt link if message type is active.
546
-            if ($registration->attendee() instanceof EE_Attendee
547
-                && EEH_MSG_Template::is_mt_active('receipt')) {
548
-                return '
528
+			}
529
+		}
530
+		return '';
531
+	}
532
+
533
+
534
+	/**
535
+	 * Get the receipt link for the transaction.
536
+	 * @param EE_Transaction $transaction
537
+	 * @return string
538
+	 * @throws EE_Error
539
+	 */
540
+	protected function get_receipt_link(EE_Transaction $transaction)
541
+	{
542
+		$registration = $transaction->primary_registration();
543
+		if ($registration instanceof EE_Registration) {
544
+			$url = $registration->receipt_url();
545
+			//only show receipt link if message type is active.
546
+			if ($registration->attendee() instanceof EE_Attendee
547
+				&& EEH_MSG_Template::is_mt_active('receipt')) {
548
+				return '
549 549
 			<li>
550 550
 				<a title="' . esc_attr__('View Transaction Receipt', 'event_espresso') . '"'
551
-                                  . ' target="_blank" href="' . $url . '" class="tiny-text">
551
+								  . ' target="_blank" href="' . $url . '" class="tiny-text">
552 552
 					<span class="dashicons dashicons-media-default ee-icon-size-18"></span>
553 553
 				</a>
554 554
 			</li>';
555
-            }
556
-        }
557
-        return '';
558
-    }
559
-
560
-
561
-    /**
562
-     * Get the link to view the details for the primary registration.
563
-     *
564
-     * @param EE_Transaction $transaction
565
-     * @return string
566
-     * @throws EE_Error
567
-     * @throws InvalidArgumentException
568
-     * @throws InvalidDataTypeException
569
-     * @throws InvalidInterfaceException
570
-     */
571
-    protected function get_primary_registration_details_link(EE_Transaction $transaction)
572
-    {
573
-        $registration = $transaction->primary_registration();
574
-        if ($registration instanceof EE_Registration) {
575
-            $url      = EE_Admin_Page::add_query_args_and_nonce(array(
576
-                'action'  => 'view_registration',
577
-                '_REG_ID' => $registration->ID(),
578
-            ), REG_ADMIN_URL);
579
-            return EE_Registry::instance()->CAP->current_user_can(
580
-                'ee_read_registration',
581
-                'espresso_registrations_view_registration',
582
-                $registration->ID()
583
-            )
584
-                ? '
555
+			}
556
+		}
557
+		return '';
558
+	}
559
+
560
+
561
+	/**
562
+	 * Get the link to view the details for the primary registration.
563
+	 *
564
+	 * @param EE_Transaction $transaction
565
+	 * @return string
566
+	 * @throws EE_Error
567
+	 * @throws InvalidArgumentException
568
+	 * @throws InvalidDataTypeException
569
+	 * @throws InvalidInterfaceException
570
+	 */
571
+	protected function get_primary_registration_details_link(EE_Transaction $transaction)
572
+	{
573
+		$registration = $transaction->primary_registration();
574
+		if ($registration instanceof EE_Registration) {
575
+			$url      = EE_Admin_Page::add_query_args_and_nonce(array(
576
+				'action'  => 'view_registration',
577
+				'_REG_ID' => $registration->ID(),
578
+			), REG_ADMIN_URL);
579
+			return EE_Registry::instance()->CAP->current_user_can(
580
+				'ee_read_registration',
581
+				'espresso_registrations_view_registration',
582
+				$registration->ID()
583
+			)
584
+				? '
585 585
 				<li>
586 586
 					<a href="' . $url . '"'
587
-                  . ' title="' . esc_attr__('View Registration Details', 'event_espresso') . '" class="tiny-text">
587
+				  . ' title="' . esc_attr__('View Registration Details', 'event_espresso') . '" class="tiny-text">
588 588
 						<span class="dashicons dashicons-clipboard"></span>
589 589
 					</a>
590 590
 				</li>'
591
-                : '';
592
-        }
593
-        return '';
594
-    }
595
-
596
-
597
-    /**
598
-     * Get send payment reminder trigger link
599
-     * @param EE_Transaction $transaction
600
-     * @return string
601
-     * @throws EE_Error
602
-     * @throws InvalidArgumentException
603
-     * @throws InvalidDataTypeException
604
-     * @throws InvalidInterfaceException
605
-     */
606
-    protected function get_send_payment_reminder_trigger_link(EE_Transaction $transaction)
607
-    {
608
-        $registration = $transaction->primary_registration();
609
-        if ($registration instanceof EE_Registration
610
-            && $registration->attendee() instanceof EE_Attendee
611
-            && EEH_MSG_Template::is_mt_active('payment_reminder')
612
-            && ! in_array(
613
-                $transaction->status_ID(),
614
-                array(EEM_Transaction::complete_status_code, EEM_Transaction::overpaid_status_code),
615
-                true
616
-            )
617
-            && EE_Registry::instance()->CAP->current_user_can(
618
-                'ee_send_message',
619
-                'espresso_transactions_send_payment_reminder'
620
-            )
621
-        ) {
622
-            $url = EE_Admin_Page::add_query_args_and_nonce(array(
623
-                'action' => 'send_payment_reminder',
624
-                'TXN_ID' => $transaction->ID(),
625
-            ), TXN_ADMIN_URL);
626
-            return  '
591
+				: '';
592
+		}
593
+		return '';
594
+	}
595
+
596
+
597
+	/**
598
+	 * Get send payment reminder trigger link
599
+	 * @param EE_Transaction $transaction
600
+	 * @return string
601
+	 * @throws EE_Error
602
+	 * @throws InvalidArgumentException
603
+	 * @throws InvalidDataTypeException
604
+	 * @throws InvalidInterfaceException
605
+	 */
606
+	protected function get_send_payment_reminder_trigger_link(EE_Transaction $transaction)
607
+	{
608
+		$registration = $transaction->primary_registration();
609
+		if ($registration instanceof EE_Registration
610
+			&& $registration->attendee() instanceof EE_Attendee
611
+			&& EEH_MSG_Template::is_mt_active('payment_reminder')
612
+			&& ! in_array(
613
+				$transaction->status_ID(),
614
+				array(EEM_Transaction::complete_status_code, EEM_Transaction::overpaid_status_code),
615
+				true
616
+			)
617
+			&& EE_Registry::instance()->CAP->current_user_can(
618
+				'ee_send_message',
619
+				'espresso_transactions_send_payment_reminder'
620
+			)
621
+		) {
622
+			$url = EE_Admin_Page::add_query_args_and_nonce(array(
623
+				'action' => 'send_payment_reminder',
624
+				'TXN_ID' => $transaction->ID(),
625
+			), TXN_ADMIN_URL);
626
+			return  '
627 627
             <li>
628 628
                 <a href="' . $url . '"'
629
-                  . ' title="' . esc_attr__('Send Payment Reminder', 'event_espresso') . '" class="tiny-text">
629
+				  . ' title="' . esc_attr__('Send Payment Reminder', 'event_espresso') . '" class="tiny-text">
630 630
                     <span class="dashicons dashicons-email-alt"></span>
631 631
                 </a>
632 632
             </li>';
633
-        }
634
-        return '';
635
-    }
636
-
637
-
638
-    /**
639
-     * Get link to filtered view in the message activity list table of messages for this transaction.
640
-     * @param EE_Transaction $transaction
641
-     * @return string
642
-     * @throws EE_Error
643
-     * @throws InvalidArgumentException
644
-     * @throws InvalidDataTypeException
645
-     * @throws InvalidInterfaceException
646
-     */
647
-    protected function get_related_messages_link(EE_Transaction $transaction)
648
-    {
649
-        $url = EEH_MSG_Template::get_message_action_link(
650
-            'see_notifications_for',
651
-            null,
652
-            array('TXN_ID' => $transaction->ID())
653
-        );
654
-        return EE_Registry::instance()->CAP->current_user_can(
655
-            'ee_read_global_messages',
656
-            'view_filtered_messages'
657
-        )
658
-            ? '<li>' . $url . '</li>'
659
-            : '';
660
-    }
661
-
662
-
663
-    /**
664
-     * Return the link to make a payment on the frontend
665
-     * @param EE_Transaction $transaction
666
-     * @return string
667
-     * @throws EE_Error
668
-     */
669
-    protected function get_payment_overview_link(EE_Transaction $transaction)
670
-    {
671
-        $registration = $transaction->primary_registration();
672
-        if ($registration instanceof EE_Registration
673
-            && $transaction->status_ID() !== EEM_Transaction::complete_status_code
674
-            && $registration->owes_monies_and_can_pay()
675
-        ) {
676
-            return '
633
+		}
634
+		return '';
635
+	}
636
+
637
+
638
+	/**
639
+	 * Get link to filtered view in the message activity list table of messages for this transaction.
640
+	 * @param EE_Transaction $transaction
641
+	 * @return string
642
+	 * @throws EE_Error
643
+	 * @throws InvalidArgumentException
644
+	 * @throws InvalidDataTypeException
645
+	 * @throws InvalidInterfaceException
646
+	 */
647
+	protected function get_related_messages_link(EE_Transaction $transaction)
648
+	{
649
+		$url = EEH_MSG_Template::get_message_action_link(
650
+			'see_notifications_for',
651
+			null,
652
+			array('TXN_ID' => $transaction->ID())
653
+		);
654
+		return EE_Registry::instance()->CAP->current_user_can(
655
+			'ee_read_global_messages',
656
+			'view_filtered_messages'
657
+		)
658
+			? '<li>' . $url . '</li>'
659
+			: '';
660
+	}
661
+
662
+
663
+	/**
664
+	 * Return the link to make a payment on the frontend
665
+	 * @param EE_Transaction $transaction
666
+	 * @return string
667
+	 * @throws EE_Error
668
+	 */
669
+	protected function get_payment_overview_link(EE_Transaction $transaction)
670
+	{
671
+		$registration = $transaction->primary_registration();
672
+		if ($registration instanceof EE_Registration
673
+			&& $transaction->status_ID() !== EEM_Transaction::complete_status_code
674
+			&& $registration->owes_monies_and_can_pay()
675
+		) {
676
+			return '
677 677
             <li>
678 678
                 <a title="' . esc_attr__('Make Payment from the Frontend.', 'event_espresso') . '"'
679
-                    . ' target="_blank" href="' . $registration->payment_overview_url(true) . '"'
680
-                    . ' class="tiny-text">
679
+					. ' target="_blank" href="' . $registration->payment_overview_url(true) . '"'
680
+					. ' class="tiny-text">
681 681
                     <span class="dashicons dashicons-money ee-icon-size-18"></span>
682 682
                 </a>
683 683
             </li>
684 684
             ';
685 685
 
686
-        }
687
-        return '';
688
-    }
686
+		}
687
+		return '';
688
+	}
689 689
 }
Please login to merge, or discard this patch.
core/domain/values/session/SessionLifespan.php 2 patches
Indentation   +95 added lines, -95 removed lines patch added patch discarded remove patch
@@ -24,99 +24,99 @@
 block discarded – undo
24 24
 class SessionLifespan
25 25
 {
26 26
 
27
-    /**
28
-     * how long an EE session lasts in seconds
29
-     * default session lifespan of 1 hour (for not so instant IPNs)
30
-     *
31
-     * @var int $lifespan
32
-     */
33
-    private $lifespan;
34
-
35
-
36
-    /**
37
-     * SessionLifespan constructor.
38
-     *
39
-     * @param int $lifespan
40
-     * @throws DomainException
41
-     */
42
-    public function __construct($lifespan = 0)
43
-    {
44
-        $lifespan = absint($lifespan);
45
-        $lifespan = $lifespan > 0 ? $lifespan : (int) HOUR_IN_SECONDS;
46
-        $this->setLifespan($lifespan);
47
-    }
48
-
49
-
50
-    /**
51
-     * @param int $lifespan
52
-     * @throws DomainException
53
-     */
54
-    protected function setLifespan($lifespan)
55
-    {
56
-        if($lifespan < 60) {
57
-            throw new DomainException(
58
-                esc_html__(
59
-                    'The session lifespan needs to be at least 60 seconds, and even that is extremely short',
60
-                    'event_espresso'
61
-                )
62
-            );
63
-
64
-        }
65
-        $this->lifespan = apply_filters(
66
-            'FHEE__EventEspresso_core_domain_values_session_SessionLifespan__setLifespan___lifespan',
67
-            // apply legacy filter for now but add doing it wrong notice in future
68
-            apply_filters(
69
-                'FHEE__EE_Session__construct___lifespan',
70
-                $lifespan
71
-            )
72
-        ) + 1;
73
-    }
74
-
75
-
76
-    /**
77
-     * @return int
78
-     */
79
-    public function inSeconds()
80
-    {
81
-        return $this->lifespan;
82
-    }
83
-
84
-
85
-    /**
86
-     * @param string $separator
87
-     * @return string
88
-     */
89
-    public function inHoursMinutesSeconds($separator = ':')
90
-    {
91
-        return sprintf(
92
-            '%02d%s%02d%s%02d',
93
-            floor($this->lifespan / 3600),
94
-            $separator,
95
-            ($this->lifespan / 60) % 60,
96
-            $separator,
97
-            $this->lifespan % 60
98
-        );
99
-    }
100
-
101
-
102
-    /**
103
-     * Returns a timestamp for when the session would expire based on this lifespan
104
-     *
105
-     * @param bool $utc If true, displays expiration in UTC
106
-     *                  If false, displays expiration in local time
107
-     * @return float
108
-     */
109
-    public function expiration($utc = true)
110
-    {
111
-        return current_time('timestamp', $utc) - $this->lifespan;
112
-    }
113
-
114
-
115
-    /**
116
-     * @return string
117
-     */
118
-    public function __toString()
119
-    {
120
-        return (string) $this->inSeconds();
121
-    }
27
+	/**
28
+	 * how long an EE session lasts in seconds
29
+	 * default session lifespan of 1 hour (for not so instant IPNs)
30
+	 *
31
+	 * @var int $lifespan
32
+	 */
33
+	private $lifespan;
34
+
35
+
36
+	/**
37
+	 * SessionLifespan constructor.
38
+	 *
39
+	 * @param int $lifespan
40
+	 * @throws DomainException
41
+	 */
42
+	public function __construct($lifespan = 0)
43
+	{
44
+		$lifespan = absint($lifespan);
45
+		$lifespan = $lifespan > 0 ? $lifespan : (int) HOUR_IN_SECONDS;
46
+		$this->setLifespan($lifespan);
47
+	}
48
+
49
+
50
+	/**
51
+	 * @param int $lifespan
52
+	 * @throws DomainException
53
+	 */
54
+	protected function setLifespan($lifespan)
55
+	{
56
+		if($lifespan < 60) {
57
+			throw new DomainException(
58
+				esc_html__(
59
+					'The session lifespan needs to be at least 60 seconds, and even that is extremely short',
60
+					'event_espresso'
61
+				)
62
+			);
63
+
64
+		}
65
+		$this->lifespan = apply_filters(
66
+			'FHEE__EventEspresso_core_domain_values_session_SessionLifespan__setLifespan___lifespan',
67
+			// apply legacy filter for now but add doing it wrong notice in future
68
+			apply_filters(
69
+				'FHEE__EE_Session__construct___lifespan',
70
+				$lifespan
71
+			)
72
+		) + 1;
73
+	}
74
+
75
+
76
+	/**
77
+	 * @return int
78
+	 */
79
+	public function inSeconds()
80
+	{
81
+		return $this->lifespan;
82
+	}
83
+
84
+
85
+	/**
86
+	 * @param string $separator
87
+	 * @return string
88
+	 */
89
+	public function inHoursMinutesSeconds($separator = ':')
90
+	{
91
+		return sprintf(
92
+			'%02d%s%02d%s%02d',
93
+			floor($this->lifespan / 3600),
94
+			$separator,
95
+			($this->lifespan / 60) % 60,
96
+			$separator,
97
+			$this->lifespan % 60
98
+		);
99
+	}
100
+
101
+
102
+	/**
103
+	 * Returns a timestamp for when the session would expire based on this lifespan
104
+	 *
105
+	 * @param bool $utc If true, displays expiration in UTC
106
+	 *                  If false, displays expiration in local time
107
+	 * @return float
108
+	 */
109
+	public function expiration($utc = true)
110
+	{
111
+		return current_time('timestamp', $utc) - $this->lifespan;
112
+	}
113
+
114
+
115
+	/**
116
+	 * @return string
117
+	 */
118
+	public function __toString()
119
+	{
120
+		return (string) $this->inSeconds();
121
+	}
122 122
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -53,7 +53,7 @@
 block discarded – undo
53 53
      */
54 54
     protected function setLifespan($lifespan)
55 55
     {
56
-        if($lifespan < 60) {
56
+        if ($lifespan < 60) {
57 57
             throw new DomainException(
58 58
                 esc_html__(
59 59
                     'The session lifespan needs to be at least 60 seconds, and even that is extremely short',
Please login to merge, or discard this patch.
core/EE_System.core.php 1 patch
Indentation   +1254 added lines, -1254 removed lines patch added patch discarded remove patch
@@ -24,1260 +24,1260 @@
 block discarded – undo
24 24
 {
25 25
 
26 26
 
27
-    /**
28
-     * indicates this is a 'normal' request. Ie, not activation, nor upgrade, nor activation.
29
-     * So examples of this would be a normal GET request on the frontend or backend, or a POST, etc
30
-     */
31
-    const req_type_normal = 0;
32
-
33
-    /**
34
-     * Indicates this is a brand new installation of EE so we should install
35
-     * tables and default data etc
36
-     */
37
-    const req_type_new_activation = 1;
38
-
39
-    /**
40
-     * we've detected that EE has been reactivated (or EE was activated during maintenance mode,
41
-     * and we just exited maintenance mode). We MUST check the database is setup properly
42
-     * and that default data is setup too
43
-     */
44
-    const req_type_reactivation = 2;
45
-
46
-    /**
47
-     * indicates that EE has been upgraded since its previous request.
48
-     * We may have data migration scripts to call and will want to trigger maintenance mode
49
-     */
50
-    const req_type_upgrade = 3;
51
-
52
-    /**
53
-     * TODO  will detect that EE has been DOWNGRADED. We probably don't want to run in this case...
54
-     */
55
-    const req_type_downgrade = 4;
56
-
57
-    /**
58
-     * @deprecated since version 4.6.0.dev.006
59
-     * Now whenever a new_activation is detected the request type is still just
60
-     * new_activation (same for reactivation, upgrade, downgrade etc), but if we'r ein maintenance mode
61
-     * EE_System::initialize_db_if_no_migrations_required and EE_Addon::initialize_db_if_no_migrations_required
62
-     * will instead enqueue that EE plugin's db initialization for when we're taken out of maintenance mode.
63
-     * (Specifically, when the migration manager indicates migrations are finished
64
-     * EE_Data_Migration_Manager::initialize_db_for_enqueued_ee_plugins() will be called)
65
-     */
66
-    const req_type_activation_but_not_installed = 5;
67
-
68
-    /**
69
-     * option prefix for recording the activation history (like core's "espresso_db_update") of addons
70
-     */
71
-    const addon_activation_history_option_prefix = 'ee_addon_activation_history_';
72
-
73
-
74
-    /**
75
-     * @var EE_System $_instance
76
-     */
77
-    private static $_instance;
78
-
79
-    /**
80
-     * @var EE_Registry $registry
81
-     */
82
-    private $registry;
83
-
84
-    /**
85
-     * @var LoaderInterface $loader
86
-     */
87
-    private $loader;
88
-
89
-    /**
90
-     * @var EE_Capabilities $capabilities
91
-     */
92
-    private $capabilities;
93
-
94
-    /**
95
-     * @var RequestInterface $request
96
-     */
97
-    private $request;
98
-
99
-    /**
100
-     * @var EE_Maintenance_Mode $maintenance_mode
101
-     */
102
-    private $maintenance_mode;
103
-
104
-    /**
105
-     * Stores which type of request this is, options being one of the constants on EE_System starting with req_type_*.
106
-     * It can be a brand-new activation, a reactivation, an upgrade, a downgrade, or a normal request.
107
-     *
108
-     * @var int $_req_type
109
-     */
110
-    private $_req_type;
111
-
112
-    /**
113
-     * Whether or not there was a non-micro version change in EE core version during this request
114
-     *
115
-     * @var boolean $_major_version_change
116
-     */
117
-    private $_major_version_change = false;
118
-
119
-    /**
120
-     * A Context DTO dedicated solely to identifying the current request type.
121
-     *
122
-     * @var RequestTypeContextCheckerInterface $request_type
123
-     */
124
-    private $request_type;
125
-
126
-
127
-
128
-    /**
129
-     * @singleton method used to instantiate class object
130
-     * @param EE_Registry|null         $registry
131
-     * @param LoaderInterface|null     $loader
132
-     * @param RequestInterface|null          $request
133
-     * @param EE_Maintenance_Mode|null $maintenance_mode
134
-     * @return EE_System
135
-     */
136
-    public static function instance(
137
-        EE_Registry $registry = null,
138
-        LoaderInterface $loader = null,
139
-        RequestInterface $request = null,
140
-        EE_Maintenance_Mode $maintenance_mode = null
141
-    ) {
142
-        // check if class object is instantiated
143
-        if (! self::$_instance instanceof EE_System) {
144
-            self::$_instance = new self($registry, $loader, $request, $maintenance_mode);
145
-        }
146
-        return self::$_instance;
147
-    }
148
-
149
-
150
-
151
-    /**
152
-     * resets the instance and returns it
153
-     *
154
-     * @return EE_System
155
-     */
156
-    public static function reset()
157
-    {
158
-        self::$_instance->_req_type = null;
159
-        //make sure none of the old hooks are left hanging around
160
-        remove_all_actions('AHEE__EE_System__perform_activations_upgrades_and_migrations');
161
-        //we need to reset the migration manager in order for it to detect DMSs properly
162
-        EE_Data_Migration_Manager::reset();
163
-        self::instance()->detect_activations_or_upgrades();
164
-        self::instance()->perform_activations_upgrades_and_migrations();
165
-        return self::instance();
166
-    }
167
-
168
-
169
-
170
-    /**
171
-     * sets hooks for running rest of system
172
-     * provides "AHEE__EE_System__construct__complete" hook for EE Addons to use as their starting point
173
-     * starting EE Addons from any other point may lead to problems
174
-     *
175
-     * @param EE_Registry         $registry
176
-     * @param LoaderInterface     $loader
177
-     * @param RequestInterface          $request
178
-     * @param EE_Maintenance_Mode $maintenance_mode
179
-     */
180
-    private function __construct(
181
-        EE_Registry $registry,
182
-        LoaderInterface $loader,
183
-        RequestInterface $request,
184
-        EE_Maintenance_Mode $maintenance_mode
185
-    ) {
186
-        $this->registry         = $registry;
187
-        $this->loader           = $loader;
188
-        $this->request          = $request;
189
-        $this->maintenance_mode = $maintenance_mode;
190
-        do_action('AHEE__EE_System__construct__begin', $this);
191
-        add_action(
192
-            'AHEE__EE_Bootstrap__load_espresso_addons',
193
-            array($this, 'loadCapabilities'),
194
-            5
195
-        );
196
-        add_action(
197
-            'AHEE__EE_Bootstrap__load_espresso_addons',
198
-            array($this, 'loadCommandBus'),
199
-            7
200
-        );
201
-        add_action(
202
-            'AHEE__EE_Bootstrap__load_espresso_addons',
203
-            array($this, 'loadPluginApi'),
204
-            9
205
-        );
206
-        // allow addons to load first so that they can register autoloaders, set hooks for running DMS's, etc
207
-        add_action(
208
-            'AHEE__EE_Bootstrap__load_espresso_addons',
209
-            array($this, 'load_espresso_addons')
210
-        );
211
-        // when an ee addon is activated, we want to call the core hook(s) again
212
-        // because the newly-activated addon didn't get a chance to run at all
213
-        add_action('activate_plugin', array($this, 'load_espresso_addons'), 1);
214
-        // detect whether install or upgrade
215
-        add_action(
216
-            'AHEE__EE_Bootstrap__detect_activations_or_upgrades',
217
-            array($this, 'detect_activations_or_upgrades'),
218
-            3
219
-        );
220
-        // load EE_Config, EE_Textdomain, etc
221
-        add_action(
222
-            'AHEE__EE_Bootstrap__load_core_configuration',
223
-            array($this, 'load_core_configuration'),
224
-            5
225
-        );
226
-        // load EE_Config, EE_Textdomain, etc
227
-        add_action(
228
-            'AHEE__EE_Bootstrap__register_shortcodes_modules_and_widgets',
229
-            array($this, 'register_shortcodes_modules_and_widgets'),
230
-            7
231
-        );
232
-        // you wanna get going? I wanna get going... let's get going!
233
-        add_action(
234
-            'AHEE__EE_Bootstrap__brew_espresso',
235
-            array($this, 'brew_espresso'),
236
-            9
237
-        );
238
-        //other housekeeping
239
-        //exclude EE critical pages from wp_list_pages
240
-        add_filter(
241
-            'wp_list_pages_excludes',
242
-            array($this, 'remove_pages_from_wp_list_pages'),
243
-            10
244
-        );
245
-        // ALL EE Addons should use the following hook point to attach their initial setup too
246
-        // it's extremely important for EE Addons to register any class autoloaders so that they can be available when the EE_Config loads
247
-        do_action('AHEE__EE_System__construct__complete', $this);
248
-    }
249
-
250
-
251
-    /**
252
-     * load and setup EE_Capabilities
253
-     *
254
-     * @return void
255
-     * @throws EE_Error
256
-     */
257
-    public function loadCapabilities()
258
-    {
259
-        $this->capabilities = $this->loader->getShared('EE_Capabilities');
260
-        add_action(
261
-            'AHEE__EE_Capabilities__init_caps__before_initialization',
262
-            function ()
263
-            {
264
-                LoaderFactory::getLoader()->getShared('EE_Payment_Method_Manager');
265
-            }
266
-        );
267
-    }
268
-
269
-
270
-
271
-    /**
272
-     * create and cache the CommandBus, and also add middleware
273
-     * The CapChecker middleware requires the use of EE_Capabilities
274
-     * which is why we need to load the CommandBus after Caps are set up
275
-     *
276
-     * @return void
277
-     * @throws EE_Error
278
-     */
279
-    public function loadCommandBus()
280
-    {
281
-        $this->loader->getShared(
282
-            'CommandBusInterface',
283
-            array(
284
-                null,
285
-                apply_filters(
286
-                    'FHEE__EE_Load_Espresso_Core__handle_request__CommandBus_middleware',
287
-                    array(
288
-                        $this->loader->getShared('EventEspresso\core\services\commands\middleware\CapChecker'),
289
-                        $this->loader->getShared('EventEspresso\core\services\commands\middleware\AddActionHook'),
290
-                    )
291
-                ),
292
-            )
293
-        );
294
-    }
295
-
296
-
297
-
298
-    /**
299
-     * @return void
300
-     * @throws EE_Error
301
-     */
302
-    public function loadPluginApi()
303
-    {
304
-        // set autoloaders for all of the classes implementing EEI_Plugin_API
305
-        // which provide helpers for EE plugin authors to more easily register certain components with EE.
306
-        EEH_Autoloader::instance()->register_autoloaders_for_each_file_in_folder(EE_LIBRARIES . 'plugin_api');
307
-        $this->loader->getShared('EE_Request_Handler');
308
-    }
309
-
310
-
311
-    /**
312
-     * @param string $addon_name
313
-     * @param string $version_constant
314
-     * @param string $min_version_required
315
-     * @param string $load_callback
316
-     * @param string $plugin_file_constant
317
-     * @return void
318
-     */
319
-    private function deactivateIncompatibleAddon(
320
-        $addon_name,
321
-        $version_constant,
322
-        $min_version_required,
323
-        $load_callback,
324
-        $plugin_file_constant
325
-    ) {
326
-        if (! defined($version_constant)) {
327
-            return;
328
-        }
329
-        $addon_version = constant($version_constant);
330
-        if ($addon_version && version_compare($addon_version, $min_version_required, '<')) {
331
-            remove_action('AHEE__EE_System__load_espresso_addons', $load_callback);
332
-            if (! function_exists('deactivate_plugins')) {
333
-                require_once ABSPATH . 'wp-admin/includes/plugin.php';
334
-            }
335
-            deactivate_plugins(plugin_basename(constant($plugin_file_constant)));
336
-            unset($_GET['activate'], $_REQUEST['activate'], $_GET['activate-multi'], $_REQUEST['activate-multi']);
337
-            EE_Error::add_error(
338
-                sprintf(
339
-                    esc_html__(
340
-                        'We\'re sorry, but the Event Espresso %1$s addon was deactivated because version %2$s or higher is required with this version of Event Espresso core.',
341
-                        'event_espresso'
342
-                    ),
343
-                    $addon_name,
344
-                    $min_version_required
345
-                ),
346
-                __FILE__, __FUNCTION__ . "({$addon_name})", __LINE__
347
-            );
348
-            EE_Error::get_notices(false, true);
349
-        }
350
-    }
351
-
352
-
353
-    /**
354
-     * load_espresso_addons
355
-     * allow addons to load first so that they can set hooks for running DMS's, etc
356
-     * this is hooked into both:
357
-     *    'AHEE__EE_Bootstrap__load_core_configuration'
358
-     *        which runs during the WP 'plugins_loaded' action at priority 5
359
-     *    and the WP 'activate_plugin' hook point
360
-     *
361
-     * @access public
362
-     * @return void
363
-     */
364
-    public function load_espresso_addons()
365
-    {
366
-        $this->deactivateIncompatibleAddon(
367
-            'Wait Lists',
368
-            'EE_WAIT_LISTS_VERSION',
369
-            '1.0.0.beta.074',
370
-            'load_espresso_wait_lists',
371
-            'EE_WAIT_LISTS_PLUGIN_FILE'
372
-        );
373
-        $this->deactivateIncompatibleAddon(
374
-            'Automated Upcoming Event Notifications',
375
-            'EE_AUTOMATED_UPCOMING_EVENT_NOTIFICATION_VERSION',
376
-            '1.0.0.beta.091',
377
-            'load_espresso_automated_upcoming_event_notification',
378
-            'EE_AUTOMATED_UPCOMING_EVENT_NOTIFICATION_PLUGIN_FILE'
379
-        );
380
-        do_action('AHEE__EE_System__load_espresso_addons');
381
-        //if the WP API basic auth plugin isn't already loaded, load it now.
382
-        //We want it for mobile apps. Just include the entire plugin
383
-        //also, don't load the basic auth when a plugin is getting activated, because
384
-        //it could be the basic auth plugin, and it doesn't check if its methods are already defined
385
-        //and causes a fatal error
386
-        if (
387
-            $this->request->getRequestParam('activate') !== 'true'
388
-            && ! function_exists('json_basic_auth_handler')
389
-            && ! function_exists('json_basic_auth_error')
390
-            && ! in_array(
391
-                $this->request->getRequestParam('action'),
392
-                array('activate', 'activate-selected'),
393
-                true
394
-            )
395
-        ) {
396
-            include_once EE_THIRD_PARTY . 'wp-api-basic-auth' . DS . 'basic-auth.php';
397
-        }
398
-        do_action('AHEE__EE_System__load_espresso_addons__complete');
399
-    }
400
-
401
-
402
-
403
-    /**
404
-     * detect_activations_or_upgrades
405
-     * Checks for activation or upgrade of core first;
406
-     * then also checks if any registered addons have been activated or upgraded
407
-     * This is hooked into 'AHEE__EE_Bootstrap__detect_activations_or_upgrades'
408
-     * which runs during the WP 'plugins_loaded' action at priority 3
409
-     *
410
-     * @access public
411
-     * @return void
412
-     */
413
-    public function detect_activations_or_upgrades()
414
-    {
415
-        //first off: let's make sure to handle core
416
-        $this->detect_if_activation_or_upgrade();
417
-        foreach ($this->registry->addons as $addon) {
418
-            if ($addon instanceof EE_Addon) {
419
-                //detect teh request type for that addon
420
-                $addon->detect_activation_or_upgrade();
421
-            }
422
-        }
423
-    }
424
-
425
-
426
-
427
-    /**
428
-     * detect_if_activation_or_upgrade
429
-     * Takes care of detecting whether this is a brand new install or code upgrade,
430
-     * and either setting up the DB or setting up maintenance mode etc.
431
-     *
432
-     * @access public
433
-     * @return void
434
-     */
435
-    public function detect_if_activation_or_upgrade()
436
-    {
437
-        do_action('AHEE__EE_System___detect_if_activation_or_upgrade__begin');
438
-        // check if db has been updated, or if its a brand-new installation
439
-        $espresso_db_update = $this->fix_espresso_db_upgrade_option();
440
-        $request_type       = $this->detect_req_type($espresso_db_update);
441
-        //EEH_Debug_Tools::printr( $request_type, '$request_type', __FILE__, __LINE__ );
442
-        switch ($request_type) {
443
-            case EE_System::req_type_new_activation:
444
-                do_action('AHEE__EE_System__detect_if_activation_or_upgrade__new_activation');
445
-                $this->_handle_core_version_change($espresso_db_update);
446
-                break;
447
-            case EE_System::req_type_reactivation:
448
-                do_action('AHEE__EE_System__detect_if_activation_or_upgrade__reactivation');
449
-                $this->_handle_core_version_change($espresso_db_update);
450
-                break;
451
-            case EE_System::req_type_upgrade:
452
-                do_action('AHEE__EE_System__detect_if_activation_or_upgrade__upgrade');
453
-                //migrations may be required now that we've upgraded
454
-                $this->maintenance_mode->set_maintenance_mode_if_db_old();
455
-                $this->_handle_core_version_change($espresso_db_update);
456
-                //				echo "done upgrade";die;
457
-                break;
458
-            case EE_System::req_type_downgrade:
459
-                do_action('AHEE__EE_System__detect_if_activation_or_upgrade__downgrade');
460
-                //its possible migrations are no longer required
461
-                $this->maintenance_mode->set_maintenance_mode_if_db_old();
462
-                $this->_handle_core_version_change($espresso_db_update);
463
-                break;
464
-            case EE_System::req_type_normal:
465
-            default:
466
-                break;
467
-        }
468
-        do_action('AHEE__EE_System__detect_if_activation_or_upgrade__complete');
469
-    }
470
-
471
-
472
-
473
-    /**
474
-     * Updates the list of installed versions and sets hooks for
475
-     * initializing the database later during the request
476
-     *
477
-     * @param array $espresso_db_update
478
-     */
479
-    private function _handle_core_version_change($espresso_db_update)
480
-    {
481
-        $this->update_list_of_installed_versions($espresso_db_update);
482
-        //get ready to verify the DB is ok (provided we aren't in maintenance mode, of course)
483
-        add_action(
484
-            'AHEE__EE_System__perform_activations_upgrades_and_migrations',
485
-            array($this, 'initialize_db_if_no_migrations_required')
486
-        );
487
-    }
488
-
489
-
490
-
491
-    /**
492
-     * standardizes the wp option 'espresso_db_upgrade' which actually stores
493
-     * information about what versions of EE have been installed and activated,
494
-     * NOT necessarily the state of the database
495
-     *
496
-     * @param mixed $espresso_db_update           the value of the WordPress option.
497
-     *                                            If not supplied, fetches it from the options table
498
-     * @return array the correct value of 'espresso_db_upgrade', after saving it, if it needed correction
499
-     */
500
-    private function fix_espresso_db_upgrade_option($espresso_db_update = null)
501
-    {
502
-        do_action('FHEE__EE_System__manage_fix_espresso_db_upgrade_option__begin', $espresso_db_update);
503
-        if (! $espresso_db_update) {
504
-            $espresso_db_update = get_option('espresso_db_update');
505
-        }
506
-        // check that option is an array
507
-        if (! is_array($espresso_db_update)) {
508
-            // if option is FALSE, then it never existed
509
-            if ($espresso_db_update === false) {
510
-                // make $espresso_db_update an array and save option with autoload OFF
511
-                $espresso_db_update = array();
512
-                add_option('espresso_db_update', $espresso_db_update, '', 'no');
513
-            } else {
514
-                // option is NOT FALSE but also is NOT an array, so make it an array and save it
515
-                $espresso_db_update = array($espresso_db_update => array());
516
-                update_option('espresso_db_update', $espresso_db_update);
517
-            }
518
-        } else {
519
-            $corrected_db_update = array();
520
-            //if IS an array, but is it an array where KEYS are version numbers, and values are arrays?
521
-            foreach ($espresso_db_update as $should_be_version_string => $should_be_array) {
522
-                if (is_int($should_be_version_string) && ! is_array($should_be_array)) {
523
-                    //the key is an int, and the value IS NOT an array
524
-                    //so it must be numerically-indexed, where values are versions installed...
525
-                    //fix it!
526
-                    $version_string                         = $should_be_array;
527
-                    $corrected_db_update[ $version_string ] = array('unknown-date');
528
-                } else {
529
-                    //ok it checks out
530
-                    $corrected_db_update[ $should_be_version_string ] = $should_be_array;
531
-                }
532
-            }
533
-            $espresso_db_update = $corrected_db_update;
534
-            update_option('espresso_db_update', $espresso_db_update);
535
-        }
536
-        do_action('FHEE__EE_System__manage_fix_espresso_db_upgrade_option__complete', $espresso_db_update);
537
-        return $espresso_db_update;
538
-    }
539
-
540
-
541
-
542
-    /**
543
-     * Does the traditional work of setting up the plugin's database and adding default data.
544
-     * If migration script/process did not exist, this is what would happen on every activation/reactivation/upgrade.
545
-     * NOTE: if we're in maintenance mode (which would be the case if we detect there are data
546
-     * migration scripts that need to be run and a version change happens), enqueues core for database initialization,
547
-     * so that it will be done when migrations are finished
548
-     *
549
-     * @param boolean $initialize_addons_too if true, we double-check addons' database tables etc too;
550
-     * @param boolean $verify_schema         if true will re-check the database tables have the correct schema.
551
-     *                                       This is a resource-intensive job
552
-     *                                       so we prefer to only do it when necessary
553
-     * @return void
554
-     * @throws EE_Error
555
-     */
556
-    public function initialize_db_if_no_migrations_required($initialize_addons_too = false, $verify_schema = true)
557
-    {
558
-        $request_type = $this->detect_req_type();
559
-        //only initialize system if we're not in maintenance mode.
560
-        if ($this->maintenance_mode->level() !== EE_Maintenance_Mode::level_2_complete_maintenance) {
561
-            update_option('ee_flush_rewrite_rules', true);
562
-            if ($verify_schema) {
563
-                EEH_Activation::initialize_db_and_folders();
564
-            }
565
-            EEH_Activation::initialize_db_content();
566
-            EEH_Activation::system_initialization();
567
-            if ($initialize_addons_too) {
568
-                $this->initialize_addons();
569
-            }
570
-        } else {
571
-            EE_Data_Migration_Manager::instance()->enqueue_db_initialization_for('Core');
572
-        }
573
-        if ($request_type === EE_System::req_type_new_activation
574
-            || $request_type === EE_System::req_type_reactivation
575
-            || (
576
-                $request_type === EE_System::req_type_upgrade
577
-                && $this->is_major_version_change()
578
-            )
579
-        ) {
580
-            add_action('AHEE__EE_System__initialize_last', array($this, 'redirect_to_about_ee'), 9);
581
-        }
582
-    }
583
-
584
-
585
-
586
-    /**
587
-     * Initializes the db for all registered addons
588
-     *
589
-     * @throws EE_Error
590
-     */
591
-    public function initialize_addons()
592
-    {
593
-        //foreach registered addon, make sure its db is up-to-date too
594
-        foreach ($this->registry->addons as $addon) {
595
-            if ($addon instanceof EE_Addon) {
596
-                $addon->initialize_db_if_no_migrations_required();
597
-            }
598
-        }
599
-    }
600
-
601
-
602
-
603
-    /**
604
-     * Adds the current code version to the saved wp option which stores a list of all ee versions ever installed.
605
-     *
606
-     * @param    array  $version_history
607
-     * @param    string $current_version_to_add version to be added to the version history
608
-     * @return    boolean success as to whether or not this option was changed
609
-     */
610
-    public function update_list_of_installed_versions($version_history = null, $current_version_to_add = null)
611
-    {
612
-        if (! $version_history) {
613
-            $version_history = $this->fix_espresso_db_upgrade_option($version_history);
614
-        }
615
-        if ($current_version_to_add === null) {
616
-            $current_version_to_add = espresso_version();
617
-        }
618
-        $version_history[ $current_version_to_add ][] = date('Y-m-d H:i:s', time());
619
-        // re-save
620
-        return update_option('espresso_db_update', $version_history);
621
-    }
622
-
623
-
624
-
625
-    /**
626
-     * Detects if the current version indicated in the has existed in the list of
627
-     * previously-installed versions of EE (espresso_db_update). Does NOT modify it (ie, no side-effect)
628
-     *
629
-     * @param array $espresso_db_update array from the wp option stored under the name 'espresso_db_update'.
630
-     *                                  If not supplied, fetches it from the options table.
631
-     *                                  Also, caches its result so later parts of the code can also know whether
632
-     *                                  there's been an update or not. This way we can add the current version to
633
-     *                                  espresso_db_update, but still know if this is a new install or not
634
-     * @return int one of the constants on EE_System::req_type_
635
-     */
636
-    public function detect_req_type($espresso_db_update = null)
637
-    {
638
-        if ($this->_req_type === null) {
639
-            $espresso_db_update          = ! empty($espresso_db_update)
640
-                ? $espresso_db_update
641
-                : $this->fix_espresso_db_upgrade_option();
642
-            $this->_req_type             = EE_System::detect_req_type_given_activation_history(
643
-                $espresso_db_update,
644
-                'ee_espresso_activation', espresso_version()
645
-            );
646
-            $this->_major_version_change = $this->_detect_major_version_change($espresso_db_update);
647
-            $this->request->setIsActivation($this->_req_type !== EE_System::req_type_normal);
648
-        }
649
-        return $this->_req_type;
650
-    }
651
-
652
-
653
-
654
-    /**
655
-     * Returns whether or not there was a non-micro version change (ie, change in either
656
-     * the first or second number in the version. Eg 4.9.0.rc.001 to 4.10.0.rc.000,
657
-     * but not 4.9.0.rc.0001 to 4.9.1.rc.0001
658
-     *
659
-     * @param $activation_history
660
-     * @return bool
661
-     */
662
-    private function _detect_major_version_change($activation_history)
663
-    {
664
-        $previous_version       = EE_System::_get_most_recently_active_version_from_activation_history($activation_history);
665
-        $previous_version_parts = explode('.', $previous_version);
666
-        $current_version_parts  = explode('.', espresso_version());
667
-        return isset($previous_version_parts[0], $previous_version_parts[1], $current_version_parts[0], $current_version_parts[1])
668
-               && ($previous_version_parts[0] !== $current_version_parts[0]
669
-                   || $previous_version_parts[1] !== $current_version_parts[1]
670
-               );
671
-    }
672
-
673
-
674
-
675
-    /**
676
-     * Returns true if either the major or minor version of EE changed during this request.
677
-     * Eg 4.9.0.rc.001 to 4.10.0.rc.000, but not 4.9.0.rc.0001 to 4.9.1.rc.0001
678
-     *
679
-     * @return bool
680
-     */
681
-    public function is_major_version_change()
682
-    {
683
-        return $this->_major_version_change;
684
-    }
685
-
686
-
687
-
688
-    /**
689
-     * Determines the request type for any ee addon, given three piece of info: the current array of activation
690
-     * histories (for core that' 'espresso_db_update' wp option); the name of the WordPress option which is temporarily
691
-     * set upon activation of the plugin (for core it's 'ee_espresso_activation'); and the version that this plugin was
692
-     * just activated to (for core that will always be espresso_version())
693
-     *
694
-     * @param array  $activation_history_for_addon     the option's value which stores the activation history for this
695
-     *                                                 ee plugin. for core that's 'espresso_db_update'
696
-     * @param string $activation_indicator_option_name the name of the WordPress option that is temporarily set to
697
-     *                                                 indicate that this plugin was just activated
698
-     * @param string $version_to_upgrade_to            the version that was just upgraded to (for core that will be
699
-     *                                                 espresso_version())
700
-     * @return int one of the constants on EE_System::req_type_*
701
-     */
702
-    public static function detect_req_type_given_activation_history(
703
-        $activation_history_for_addon,
704
-        $activation_indicator_option_name,
705
-        $version_to_upgrade_to
706
-    ) {
707
-        $version_is_higher = self::_new_version_is_higher($activation_history_for_addon, $version_to_upgrade_to);
708
-        if ($activation_history_for_addon) {
709
-            //it exists, so this isn't a completely new install
710
-            //check if this version already in that list of previously installed versions
711
-            if (! isset($activation_history_for_addon[ $version_to_upgrade_to ])) {
712
-                //it a version we haven't seen before
713
-                if ($version_is_higher === 1) {
714
-                    $req_type = EE_System::req_type_upgrade;
715
-                } else {
716
-                    $req_type = EE_System::req_type_downgrade;
717
-                }
718
-                delete_option($activation_indicator_option_name);
719
-            } else {
720
-                // its not an update. maybe a reactivation?
721
-                if (get_option($activation_indicator_option_name, false)) {
722
-                    if ($version_is_higher === -1) {
723
-                        $req_type = EE_System::req_type_downgrade;
724
-                    } elseif ($version_is_higher === 0) {
725
-                        //we've seen this version before, but it's an activation. must be a reactivation
726
-                        $req_type = EE_System::req_type_reactivation;
727
-                    } else {//$version_is_higher === 1
728
-                        $req_type = EE_System::req_type_upgrade;
729
-                    }
730
-                    delete_option($activation_indicator_option_name);
731
-                } else {
732
-                    //we've seen this version before and the activation indicate doesn't show it was just activated
733
-                    if ($version_is_higher === -1) {
734
-                        $req_type = EE_System::req_type_downgrade;
735
-                    } elseif ($version_is_higher === 0) {
736
-                        //we've seen this version before and it's not an activation. its normal request
737
-                        $req_type = EE_System::req_type_normal;
738
-                    } else {//$version_is_higher === 1
739
-                        $req_type = EE_System::req_type_upgrade;
740
-                    }
741
-                }
742
-            }
743
-        } else {
744
-            //brand new install
745
-            $req_type = EE_System::req_type_new_activation;
746
-            delete_option($activation_indicator_option_name);
747
-        }
748
-        return $req_type;
749
-    }
750
-
751
-
752
-
753
-    /**
754
-     * Detects if the $version_to_upgrade_to is higher than the most recent version in
755
-     * the $activation_history_for_addon
756
-     *
757
-     * @param array  $activation_history_for_addon (keys are versions, values are arrays of times activated,
758
-     *                                             sometimes containing 'unknown-date'
759
-     * @param string $version_to_upgrade_to        (current version)
760
-     * @return int results of version_compare( $version_to_upgrade_to, $most_recently_active_version ).
761
-     *                                             ie, -1 if $version_to_upgrade_to is LOWER (downgrade);
762
-     *                                             0 if $version_to_upgrade_to MATCHES (reactivation or normal request);
763
-     *                                             1 if $version_to_upgrade_to is HIGHER (upgrade) ;
764
-     */
765
-    private static function _new_version_is_higher($activation_history_for_addon, $version_to_upgrade_to)
766
-    {
767
-        //find the most recently-activated version
768
-        $most_recently_active_version =
769
-            EE_System::_get_most_recently_active_version_from_activation_history($activation_history_for_addon);
770
-        return version_compare($version_to_upgrade_to, $most_recently_active_version);
771
-    }
772
-
773
-
774
-
775
-    /**
776
-     * Gets the most recently active version listed in the activation history,
777
-     * and if none are found (ie, it's a brand new install) returns '0.0.0.dev.000'.
778
-     *
779
-     * @param array $activation_history  (keys are versions, values are arrays of times activated,
780
-     *                                   sometimes containing 'unknown-date'
781
-     * @return string
782
-     */
783
-    private static function _get_most_recently_active_version_from_activation_history($activation_history)
784
-    {
785
-        $most_recently_active_version_activation = '1970-01-01 00:00:00';
786
-        $most_recently_active_version            = '0.0.0.dev.000';
787
-        if (is_array($activation_history)) {
788
-            foreach ($activation_history as $version => $times_activated) {
789
-                //check there is a record of when this version was activated. Otherwise,
790
-                //mark it as unknown
791
-                if (! $times_activated) {
792
-                    $times_activated = array('unknown-date');
793
-                }
794
-                if (is_string($times_activated)) {
795
-                    $times_activated = array($times_activated);
796
-                }
797
-                foreach ($times_activated as $an_activation) {
798
-                    if ($an_activation !== 'unknown-date'
799
-                        && $an_activation
800
-                           > $most_recently_active_version_activation) {
801
-                        $most_recently_active_version            = $version;
802
-                        $most_recently_active_version_activation = $an_activation === 'unknown-date'
803
-                            ? '1970-01-01 00:00:00'
804
-                            : $an_activation;
805
-                    }
806
-                }
807
-            }
808
-        }
809
-        return $most_recently_active_version;
810
-    }
811
-
812
-
813
-
814
-    /**
815
-     * This redirects to the about EE page after activation
816
-     *
817
-     * @return void
818
-     */
819
-    public function redirect_to_about_ee()
820
-    {
821
-        $notices = EE_Error::get_notices(false);
822
-        //if current user is an admin and it's not an ajax or rest request
823
-        if (
824
-            ! isset($notices['errors'])
825
-            && $this->request->isAdmin()
826
-            && apply_filters(
827
-                'FHEE__EE_System__redirect_to_about_ee__do_redirect',
828
-                $this->capabilities->current_user_can('manage_options', 'espresso_about_default')
829
-            )
830
-        ) {
831
-            $query_params = array('page' => 'espresso_about');
832
-            if (EE_System::instance()->detect_req_type() === EE_System::req_type_new_activation) {
833
-                $query_params['new_activation'] = true;
834
-            }
835
-            if (EE_System::instance()->detect_req_type() === EE_System::req_type_reactivation) {
836
-                $query_params['reactivation'] = true;
837
-            }
838
-            $url = add_query_arg($query_params, admin_url('admin.php'));
839
-            wp_safe_redirect($url);
840
-            exit();
841
-        }
842
-    }
843
-
844
-
845
-
846
-    /**
847
-     * load_core_configuration
848
-     * this is hooked into 'AHEE__EE_Bootstrap__load_core_configuration'
849
-     * which runs during the WP 'plugins_loaded' action at priority 5
850
-     *
851
-     * @return void
852
-     * @throws ReflectionException
853
-     */
854
-    public function load_core_configuration()
855
-    {
856
-        do_action('AHEE__EE_System__load_core_configuration__begin', $this);
857
-        $this->loader->getShared('EE_Load_Textdomain');
858
-        //load textdomain
859
-        EE_Load_Textdomain::load_textdomain();
860
-        // load and setup EE_Config and EE_Network_Config
861
-        $config = $this->loader->getShared('EE_Config');
862
-        $this->loader->getShared('EE_Network_Config');
863
-        // setup autoloaders
864
-        // enable logging?
865
-        if ($config->admin->use_full_logging) {
866
-            $this->loader->getShared('EE_Log');
867
-        }
868
-        // check for activation errors
869
-        $activation_errors = get_option('ee_plugin_activation_errors', false);
870
-        if ($activation_errors) {
871
-            EE_Error::add_error($activation_errors, __FILE__, __FUNCTION__, __LINE__);
872
-            update_option('ee_plugin_activation_errors', false);
873
-        }
874
-        // get model names
875
-        $this->_parse_model_names();
876
-        //load caf stuff a chance to play during the activation process too.
877
-        $this->_maybe_brew_regular();
878
-        do_action('AHEE__EE_System__load_core_configuration__complete', $this);
879
-    }
880
-
881
-
882
-
883
-    /**
884
-     * cycles through all of the models/*.model.php files, and assembles an array of model names
885
-     *
886
-     * @return void
887
-     * @throws ReflectionException
888
-     */
889
-    private function _parse_model_names()
890
-    {
891
-        //get all the files in the EE_MODELS folder that end in .model.php
892
-        $models                 = glob(EE_MODELS . '*.model.php');
893
-        $model_names            = array();
894
-        $non_abstract_db_models = array();
895
-        foreach ($models as $model) {
896
-            // get model classname
897
-            $classname       = EEH_File::get_classname_from_filepath_with_standard_filename($model);
898
-            $short_name      = str_replace('EEM_', '', $classname);
899
-            $reflectionClass = new ReflectionClass($classname);
900
-            if ($reflectionClass->isSubclassOf('EEM_Base') && ! $reflectionClass->isAbstract()) {
901
-                $non_abstract_db_models[ $short_name ] = $classname;
902
-            }
903
-            $model_names[ $short_name ] = $classname;
904
-        }
905
-        $this->registry->models                 = apply_filters('FHEE__EE_System__parse_model_names', $model_names);
906
-        $this->registry->non_abstract_db_models = apply_filters(
907
-            'FHEE__EE_System__parse_implemented_model_names',
908
-            $non_abstract_db_models
909
-        );
910
-    }
911
-
912
-
913
-
914
-    /**
915
-     * The purpose of this method is to simply check for a file named "caffeinated/brewing_regular.php" for any hooks
916
-     * that need to be setup before our EE_System launches.
917
-     *
918
-     * @return void
919
-     */
920
-    private function _maybe_brew_regular()
921
-    {
922
-        if ((! defined('EE_DECAF') || EE_DECAF !== true) && is_readable(EE_CAFF_PATH . 'brewing_regular.php')) {
923
-            require_once EE_CAFF_PATH . 'brewing_regular.php';
924
-        }
925
-    }
926
-
927
-
928
-
929
-    /**
930
-     * register_shortcodes_modules_and_widgets
931
-     * generate lists of shortcodes and modules, then verify paths and classes
932
-     * This is hooked into 'AHEE__EE_Bootstrap__register_shortcodes_modules_and_widgets'
933
-     * which runs during the WP 'plugins_loaded' action at priority 7
934
-     *
935
-     * @access public
936
-     * @return void
937
-     * @throws Exception
938
-     */
939
-    public function register_shortcodes_modules_and_widgets()
940
-    {
941
-        if ($this->request->isFrontend() || $this->request->isIframe()) {
942
-            try {
943
-                // load, register, and add shortcodes the new way
944
-                $this->loader->getShared(
945
-                    'EventEspresso\core\services\shortcodes\ShortcodesManager',
946
-                    array(
947
-                        // and the old way, but we'll put it under control of the new system
948
-                        EE_Config::getLegacyShortcodesManager(),
949
-                    )
950
-                );
951
-            } catch (Exception $exception) {
952
-                new ExceptionStackTraceDisplay($exception);
953
-            }
954
-        }
955
-        do_action('AHEE__EE_System__register_shortcodes_modules_and_widgets');
956
-        // check for addons using old hook point
957
-        if (has_action('AHEE__EE_System__register_shortcodes_modules_and_addons')) {
958
-            $this->_incompatible_addon_error();
959
-        }
960
-    }
961
-
962
-
963
-
964
-    /**
965
-     * _incompatible_addon_error
966
-     *
967
-     * @access public
968
-     * @return void
969
-     */
970
-    private function _incompatible_addon_error()
971
-    {
972
-        // get array of classes hooking into here
973
-        $class_names = EEH_Class_Tools::get_class_names_for_all_callbacks_on_hook(
974
-            'AHEE__EE_System__register_shortcodes_modules_and_addons'
975
-        );
976
-        if (! empty($class_names)) {
977
-            $msg = __(
978
-                'The following plugins, addons, or modules appear to be incompatible with this version of Event Espresso and were automatically deactivated to avoid fatal errors:',
979
-                'event_espresso'
980
-            );
981
-            $msg .= '<ul>';
982
-            foreach ($class_names as $class_name) {
983
-                $msg .= '<li><b>Event Espresso - ' . str_replace(
984
-                        array('EE_', 'EEM_', 'EED_', 'EES_', 'EEW_'), '',
985
-                        $class_name
986
-                    ) . '</b></li>';
987
-            }
988
-            $msg .= '</ul>';
989
-            $msg .= __(
990
-                'Compatibility issues can be avoided and/or resolved by keeping addons and plugins updated to the latest version.',
991
-                'event_espresso'
992
-            );
993
-            // save list of incompatible addons to wp-options for later use
994
-            add_option('ee_incompatible_addons', $class_names, '', 'no');
995
-            if (is_admin()) {
996
-                EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
997
-            }
998
-        }
999
-    }
1000
-
1001
-
1002
-
1003
-    /**
1004
-     * brew_espresso
1005
-     * begins the process of setting hooks for initializing EE in the correct order
1006
-     * This is happening on the 'AHEE__EE_Bootstrap__brew_espresso' hook point
1007
-     * which runs during the WP 'plugins_loaded' action at priority 9
1008
-     *
1009
-     * @return void
1010
-     */
1011
-    public function brew_espresso()
1012
-    {
1013
-        do_action('AHEE__EE_System__brew_espresso__begin', $this);
1014
-        // load some final core systems
1015
-        add_action('init', array($this, 'set_hooks_for_core'), 1);
1016
-        add_action('init', array($this, 'perform_activations_upgrades_and_migrations'), 3);
1017
-        add_action('init', array($this, 'load_CPTs_and_session'), 5);
1018
-        add_action('init', array($this, 'load_controllers'), 7);
1019
-        add_action('init', array($this, 'core_loaded_and_ready'), 9);
1020
-        add_action('init', array($this, 'initialize'), 10);
1021
-        add_action('init', array($this, 'initialize_last'), 100);
1022
-        if (is_admin() && apply_filters('FHEE__EE_System__brew_espresso__load_pue', true)) {
1023
-            // pew pew pew
1024
-            $this->loader->getShared('EE_PUE');
1025
-            do_action('AHEE__EE_System__brew_espresso__after_pue_init');
1026
-        }
1027
-        do_action('AHEE__EE_System__brew_espresso__complete', $this);
1028
-    }
1029
-
1030
-
1031
-
1032
-    /**
1033
-     *    set_hooks_for_core
1034
-     *
1035
-     * @access public
1036
-     * @return    void
1037
-     * @throws EE_Error
1038
-     */
1039
-    public function set_hooks_for_core()
1040
-    {
1041
-        $this->_deactivate_incompatible_addons();
1042
-        do_action('AHEE__EE_System__set_hooks_for_core');
1043
-        $this->loader->getShared('EventEspresso\core\domain\values\session\SessionLifespan');
1044
-        //caps need to be initialized on every request so that capability maps are set.
1045
-        //@see https://events.codebasehq.com/projects/event-espresso/tickets/8674
1046
-        $this->registry->CAP->init_caps();
1047
-    }
1048
-
1049
-
1050
-
1051
-    /**
1052
-     * Using the information gathered in EE_System::_incompatible_addon_error,
1053
-     * deactivates any addons considered incompatible with the current version of EE
1054
-     */
1055
-    private function _deactivate_incompatible_addons()
1056
-    {
1057
-        $incompatible_addons = get_option('ee_incompatible_addons', array());
1058
-        if (! empty($incompatible_addons)) {
1059
-            $active_plugins = get_option('active_plugins', array());
1060
-            foreach ($active_plugins as $active_plugin) {
1061
-                foreach ($incompatible_addons as $incompatible_addon) {
1062
-                    if (strpos($active_plugin, $incompatible_addon) !== false) {
1063
-                        unset($_GET['activate']);
1064
-                        espresso_deactivate_plugin($active_plugin);
1065
-                    }
1066
-                }
1067
-            }
1068
-        }
1069
-    }
1070
-
1071
-
1072
-
1073
-    /**
1074
-     *    perform_activations_upgrades_and_migrations
1075
-     *
1076
-     * @access public
1077
-     * @return    void
1078
-     */
1079
-    public function perform_activations_upgrades_and_migrations()
1080
-    {
1081
-        //first check if we had previously attempted to setup EE's directories but failed
1082
-        if ($this->request->isActivation() && EEH_Activation::upload_directories_incomplete()) {
1083
-            EEH_Activation::create_upload_directories();
1084
-        }
1085
-        do_action('AHEE__EE_System__perform_activations_upgrades_and_migrations');
1086
-    }
1087
-
1088
-
1089
-
1090
-    /**
1091
-     *    load_CPTs_and_session
1092
-     *
1093
-     * @access public
1094
-     * @return    void
1095
-     */
1096
-    public function load_CPTs_and_session()
1097
-    {
1098
-        do_action('AHEE__EE_System__load_CPTs_and_session__start');
1099
-        // register Custom Post Types
1100
-        $this->loader->getShared('EE_Register_CPTs');
1101
-        do_action('AHEE__EE_System__load_CPTs_and_session__complete');
1102
-    }
1103
-
1104
-
1105
-
1106
-    /**
1107
-     * load_controllers
1108
-     * this is the best place to load any additional controllers that needs access to EE core.
1109
-     * it is expected that all basic core EE systems, that are not dependant on the current request are loaded at this
1110
-     * time
1111
-     *
1112
-     * @access public
1113
-     * @return void
1114
-     */
1115
-    public function load_controllers()
1116
-    {
1117
-        do_action('AHEE__EE_System__load_controllers__start');
1118
-        // let's get it started
1119
-        if (
1120
-            ! $this->maintenance_mode->level()
1121
-            && ($this->request->isFrontend() || $this->request->isFrontAjax())
1122
-        ) {
1123
-            do_action('AHEE__EE_System__load_controllers__load_front_controllers');
1124
-            $this->loader->getShared('EE_Front_Controller');
1125
-        } elseif ($this->request->isAdmin() || $this->request->isAdminAjax()) {
1126
-            do_action('AHEE__EE_System__load_controllers__load_admin_controllers');
1127
-            $this->loader->getShared('EE_Admin');
1128
-        }
1129
-        do_action('AHEE__EE_System__load_controllers__complete');
1130
-    }
1131
-
1132
-
1133
-
1134
-    /**
1135
-     * core_loaded_and_ready
1136
-     * all of the basic EE core should be loaded at this point and available regardless of M-Mode
1137
-     *
1138
-     * @access public
1139
-     * @return void
1140
-     */
1141
-    public function core_loaded_and_ready()
1142
-    {
1143
-        if (
1144
-            $this->request->isAdmin()
1145
-            || $this->request->isEeAjax()
1146
-            || $this->request->isFrontend()
1147
-        ) {
1148
-            $this->loader->getShared('EE_Session');
1149
-        }
1150
-        do_action('AHEE__EE_System__core_loaded_and_ready');
1151
-        // load_espresso_template_tags
1152
-        if (
1153
-            is_readable(EE_PUBLIC . 'template_tags.php')
1154
-            && ($this->request->isFrontend() || $this->request->isIframe() || $this->request->isFeed())
1155
-        ) {
1156
-            require_once EE_PUBLIC . 'template_tags.php';
1157
-        }
1158
-        do_action('AHEE__EE_System__set_hooks_for_shortcodes_modules_and_addons');
1159
-        if ($this->request->isAdmin() || $this->request->isFrontend() || $this->request->isIframe()) {
1160
-            $this->loader->getShared('EventEspresso\core\services\assets\Registry');
1161
-        }
1162
-    }
1163
-
1164
-
1165
-
1166
-    /**
1167
-     * initialize
1168
-     * this is the best place to begin initializing client code
1169
-     *
1170
-     * @access public
1171
-     * @return void
1172
-     */
1173
-    public function initialize()
1174
-    {
1175
-        do_action('AHEE__EE_System__initialize');
1176
-    }
1177
-
1178
-
1179
-
1180
-    /**
1181
-     * initialize_last
1182
-     * this is run really late during the WP init hook point, and ensures that mostly everything else that needs to
1183
-     * initialize has done so
1184
-     *
1185
-     * @access public
1186
-     * @return void
1187
-     */
1188
-    public function initialize_last()
1189
-    {
1190
-        do_action('AHEE__EE_System__initialize_last');
1191
-        add_action('admin_bar_init', array($this, 'addEspressoToolbar'));
1192
-    }
1193
-
1194
-
1195
-
1196
-    /**
1197
-     * @return void
1198
-     * @throws EE_Error
1199
-     */
1200
-    public function addEspressoToolbar()
1201
-    {
1202
-        $this->loader->getShared(
1203
-            'EventEspresso\core\domain\services\admin\AdminToolBar',
1204
-            array($this->registry->CAP)
1205
-        );
1206
-    }
1207
-
1208
-
1209
-
1210
-    /**
1211
-     * do_not_cache
1212
-     * sets no cache headers and defines no cache constants for WP plugins
1213
-     *
1214
-     * @access public
1215
-     * @return void
1216
-     */
1217
-    public static function do_not_cache()
1218
-    {
1219
-        // set no cache constants
1220
-        if (! defined('DONOTCACHEPAGE')) {
1221
-            define('DONOTCACHEPAGE', true);
1222
-        }
1223
-        if (! defined('DONOTCACHCEOBJECT')) {
1224
-            define('DONOTCACHCEOBJECT', true);
1225
-        }
1226
-        if (! defined('DONOTCACHEDB')) {
1227
-            define('DONOTCACHEDB', true);
1228
-        }
1229
-        // add no cache headers
1230
-        add_action('send_headers', array('EE_System', 'nocache_headers'), 10);
1231
-        // plus a little extra for nginx and Google Chrome
1232
-        add_filter('nocache_headers', array('EE_System', 'extra_nocache_headers'), 10, 1);
1233
-        // prevent browsers from prefetching of the rel='next' link, because it may contain content that interferes with the registration process
1234
-        remove_action('wp_head', 'adjacent_posts_rel_link_wp_head');
1235
-    }
1236
-
1237
-
1238
-
1239
-    /**
1240
-     *    extra_nocache_headers
1241
-     *
1242
-     * @access    public
1243
-     * @param $headers
1244
-     * @return    array
1245
-     */
1246
-    public static function extra_nocache_headers($headers)
1247
-    {
1248
-        // for NGINX
1249
-        $headers['X-Accel-Expires'] = 0;
1250
-        // plus extra for Google Chrome since it doesn't seem to respect "no-cache", but WILL respect "no-store"
1251
-        $headers['Cache-Control'] = 'no-store, no-cache, must-revalidate, max-age=0';
1252
-        return $headers;
1253
-    }
1254
-
1255
-
1256
-
1257
-    /**
1258
-     *    nocache_headers
1259
-     *
1260
-     * @access    public
1261
-     * @return    void
1262
-     */
1263
-    public static function nocache_headers()
1264
-    {
1265
-        nocache_headers();
1266
-    }
1267
-
1268
-
1269
-
1270
-    /**
1271
-     * simply hooks into "wp_list_pages_exclude" filter (for wp_list_pages method) and makes sure EE critical pages are
1272
-     * never returned with the function.
1273
-     *
1274
-     * @param  array $exclude_array any existing pages being excluded are in this array.
1275
-     * @return array
1276
-     */
1277
-    public function remove_pages_from_wp_list_pages($exclude_array)
1278
-    {
1279
-        return array_merge($exclude_array, $this->registry->CFG->core->get_critical_pages_array());
1280
-    }
27
+	/**
28
+	 * indicates this is a 'normal' request. Ie, not activation, nor upgrade, nor activation.
29
+	 * So examples of this would be a normal GET request on the frontend or backend, or a POST, etc
30
+	 */
31
+	const req_type_normal = 0;
32
+
33
+	/**
34
+	 * Indicates this is a brand new installation of EE so we should install
35
+	 * tables and default data etc
36
+	 */
37
+	const req_type_new_activation = 1;
38
+
39
+	/**
40
+	 * we've detected that EE has been reactivated (or EE was activated during maintenance mode,
41
+	 * and we just exited maintenance mode). We MUST check the database is setup properly
42
+	 * and that default data is setup too
43
+	 */
44
+	const req_type_reactivation = 2;
45
+
46
+	/**
47
+	 * indicates that EE has been upgraded since its previous request.
48
+	 * We may have data migration scripts to call and will want to trigger maintenance mode
49
+	 */
50
+	const req_type_upgrade = 3;
51
+
52
+	/**
53
+	 * TODO  will detect that EE has been DOWNGRADED. We probably don't want to run in this case...
54
+	 */
55
+	const req_type_downgrade = 4;
56
+
57
+	/**
58
+	 * @deprecated since version 4.6.0.dev.006
59
+	 * Now whenever a new_activation is detected the request type is still just
60
+	 * new_activation (same for reactivation, upgrade, downgrade etc), but if we'r ein maintenance mode
61
+	 * EE_System::initialize_db_if_no_migrations_required and EE_Addon::initialize_db_if_no_migrations_required
62
+	 * will instead enqueue that EE plugin's db initialization for when we're taken out of maintenance mode.
63
+	 * (Specifically, when the migration manager indicates migrations are finished
64
+	 * EE_Data_Migration_Manager::initialize_db_for_enqueued_ee_plugins() will be called)
65
+	 */
66
+	const req_type_activation_but_not_installed = 5;
67
+
68
+	/**
69
+	 * option prefix for recording the activation history (like core's "espresso_db_update") of addons
70
+	 */
71
+	const addon_activation_history_option_prefix = 'ee_addon_activation_history_';
72
+
73
+
74
+	/**
75
+	 * @var EE_System $_instance
76
+	 */
77
+	private static $_instance;
78
+
79
+	/**
80
+	 * @var EE_Registry $registry
81
+	 */
82
+	private $registry;
83
+
84
+	/**
85
+	 * @var LoaderInterface $loader
86
+	 */
87
+	private $loader;
88
+
89
+	/**
90
+	 * @var EE_Capabilities $capabilities
91
+	 */
92
+	private $capabilities;
93
+
94
+	/**
95
+	 * @var RequestInterface $request
96
+	 */
97
+	private $request;
98
+
99
+	/**
100
+	 * @var EE_Maintenance_Mode $maintenance_mode
101
+	 */
102
+	private $maintenance_mode;
103
+
104
+	/**
105
+	 * Stores which type of request this is, options being one of the constants on EE_System starting with req_type_*.
106
+	 * It can be a brand-new activation, a reactivation, an upgrade, a downgrade, or a normal request.
107
+	 *
108
+	 * @var int $_req_type
109
+	 */
110
+	private $_req_type;
111
+
112
+	/**
113
+	 * Whether or not there was a non-micro version change in EE core version during this request
114
+	 *
115
+	 * @var boolean $_major_version_change
116
+	 */
117
+	private $_major_version_change = false;
118
+
119
+	/**
120
+	 * A Context DTO dedicated solely to identifying the current request type.
121
+	 *
122
+	 * @var RequestTypeContextCheckerInterface $request_type
123
+	 */
124
+	private $request_type;
125
+
126
+
127
+
128
+	/**
129
+	 * @singleton method used to instantiate class object
130
+	 * @param EE_Registry|null         $registry
131
+	 * @param LoaderInterface|null     $loader
132
+	 * @param RequestInterface|null          $request
133
+	 * @param EE_Maintenance_Mode|null $maintenance_mode
134
+	 * @return EE_System
135
+	 */
136
+	public static function instance(
137
+		EE_Registry $registry = null,
138
+		LoaderInterface $loader = null,
139
+		RequestInterface $request = null,
140
+		EE_Maintenance_Mode $maintenance_mode = null
141
+	) {
142
+		// check if class object is instantiated
143
+		if (! self::$_instance instanceof EE_System) {
144
+			self::$_instance = new self($registry, $loader, $request, $maintenance_mode);
145
+		}
146
+		return self::$_instance;
147
+	}
148
+
149
+
150
+
151
+	/**
152
+	 * resets the instance and returns it
153
+	 *
154
+	 * @return EE_System
155
+	 */
156
+	public static function reset()
157
+	{
158
+		self::$_instance->_req_type = null;
159
+		//make sure none of the old hooks are left hanging around
160
+		remove_all_actions('AHEE__EE_System__perform_activations_upgrades_and_migrations');
161
+		//we need to reset the migration manager in order for it to detect DMSs properly
162
+		EE_Data_Migration_Manager::reset();
163
+		self::instance()->detect_activations_or_upgrades();
164
+		self::instance()->perform_activations_upgrades_and_migrations();
165
+		return self::instance();
166
+	}
167
+
168
+
169
+
170
+	/**
171
+	 * sets hooks for running rest of system
172
+	 * provides "AHEE__EE_System__construct__complete" hook for EE Addons to use as their starting point
173
+	 * starting EE Addons from any other point may lead to problems
174
+	 *
175
+	 * @param EE_Registry         $registry
176
+	 * @param LoaderInterface     $loader
177
+	 * @param RequestInterface          $request
178
+	 * @param EE_Maintenance_Mode $maintenance_mode
179
+	 */
180
+	private function __construct(
181
+		EE_Registry $registry,
182
+		LoaderInterface $loader,
183
+		RequestInterface $request,
184
+		EE_Maintenance_Mode $maintenance_mode
185
+	) {
186
+		$this->registry         = $registry;
187
+		$this->loader           = $loader;
188
+		$this->request          = $request;
189
+		$this->maintenance_mode = $maintenance_mode;
190
+		do_action('AHEE__EE_System__construct__begin', $this);
191
+		add_action(
192
+			'AHEE__EE_Bootstrap__load_espresso_addons',
193
+			array($this, 'loadCapabilities'),
194
+			5
195
+		);
196
+		add_action(
197
+			'AHEE__EE_Bootstrap__load_espresso_addons',
198
+			array($this, 'loadCommandBus'),
199
+			7
200
+		);
201
+		add_action(
202
+			'AHEE__EE_Bootstrap__load_espresso_addons',
203
+			array($this, 'loadPluginApi'),
204
+			9
205
+		);
206
+		// allow addons to load first so that they can register autoloaders, set hooks for running DMS's, etc
207
+		add_action(
208
+			'AHEE__EE_Bootstrap__load_espresso_addons',
209
+			array($this, 'load_espresso_addons')
210
+		);
211
+		// when an ee addon is activated, we want to call the core hook(s) again
212
+		// because the newly-activated addon didn't get a chance to run at all
213
+		add_action('activate_plugin', array($this, 'load_espresso_addons'), 1);
214
+		// detect whether install or upgrade
215
+		add_action(
216
+			'AHEE__EE_Bootstrap__detect_activations_or_upgrades',
217
+			array($this, 'detect_activations_or_upgrades'),
218
+			3
219
+		);
220
+		// load EE_Config, EE_Textdomain, etc
221
+		add_action(
222
+			'AHEE__EE_Bootstrap__load_core_configuration',
223
+			array($this, 'load_core_configuration'),
224
+			5
225
+		);
226
+		// load EE_Config, EE_Textdomain, etc
227
+		add_action(
228
+			'AHEE__EE_Bootstrap__register_shortcodes_modules_and_widgets',
229
+			array($this, 'register_shortcodes_modules_and_widgets'),
230
+			7
231
+		);
232
+		// you wanna get going? I wanna get going... let's get going!
233
+		add_action(
234
+			'AHEE__EE_Bootstrap__brew_espresso',
235
+			array($this, 'brew_espresso'),
236
+			9
237
+		);
238
+		//other housekeeping
239
+		//exclude EE critical pages from wp_list_pages
240
+		add_filter(
241
+			'wp_list_pages_excludes',
242
+			array($this, 'remove_pages_from_wp_list_pages'),
243
+			10
244
+		);
245
+		// ALL EE Addons should use the following hook point to attach their initial setup too
246
+		// it's extremely important for EE Addons to register any class autoloaders so that they can be available when the EE_Config loads
247
+		do_action('AHEE__EE_System__construct__complete', $this);
248
+	}
249
+
250
+
251
+	/**
252
+	 * load and setup EE_Capabilities
253
+	 *
254
+	 * @return void
255
+	 * @throws EE_Error
256
+	 */
257
+	public function loadCapabilities()
258
+	{
259
+		$this->capabilities = $this->loader->getShared('EE_Capabilities');
260
+		add_action(
261
+			'AHEE__EE_Capabilities__init_caps__before_initialization',
262
+			function ()
263
+			{
264
+				LoaderFactory::getLoader()->getShared('EE_Payment_Method_Manager');
265
+			}
266
+		);
267
+	}
268
+
269
+
270
+
271
+	/**
272
+	 * create and cache the CommandBus, and also add middleware
273
+	 * The CapChecker middleware requires the use of EE_Capabilities
274
+	 * which is why we need to load the CommandBus after Caps are set up
275
+	 *
276
+	 * @return void
277
+	 * @throws EE_Error
278
+	 */
279
+	public function loadCommandBus()
280
+	{
281
+		$this->loader->getShared(
282
+			'CommandBusInterface',
283
+			array(
284
+				null,
285
+				apply_filters(
286
+					'FHEE__EE_Load_Espresso_Core__handle_request__CommandBus_middleware',
287
+					array(
288
+						$this->loader->getShared('EventEspresso\core\services\commands\middleware\CapChecker'),
289
+						$this->loader->getShared('EventEspresso\core\services\commands\middleware\AddActionHook'),
290
+					)
291
+				),
292
+			)
293
+		);
294
+	}
295
+
296
+
297
+
298
+	/**
299
+	 * @return void
300
+	 * @throws EE_Error
301
+	 */
302
+	public function loadPluginApi()
303
+	{
304
+		// set autoloaders for all of the classes implementing EEI_Plugin_API
305
+		// which provide helpers for EE plugin authors to more easily register certain components with EE.
306
+		EEH_Autoloader::instance()->register_autoloaders_for_each_file_in_folder(EE_LIBRARIES . 'plugin_api');
307
+		$this->loader->getShared('EE_Request_Handler');
308
+	}
309
+
310
+
311
+	/**
312
+	 * @param string $addon_name
313
+	 * @param string $version_constant
314
+	 * @param string $min_version_required
315
+	 * @param string $load_callback
316
+	 * @param string $plugin_file_constant
317
+	 * @return void
318
+	 */
319
+	private function deactivateIncompatibleAddon(
320
+		$addon_name,
321
+		$version_constant,
322
+		$min_version_required,
323
+		$load_callback,
324
+		$plugin_file_constant
325
+	) {
326
+		if (! defined($version_constant)) {
327
+			return;
328
+		}
329
+		$addon_version = constant($version_constant);
330
+		if ($addon_version && version_compare($addon_version, $min_version_required, '<')) {
331
+			remove_action('AHEE__EE_System__load_espresso_addons', $load_callback);
332
+			if (! function_exists('deactivate_plugins')) {
333
+				require_once ABSPATH . 'wp-admin/includes/plugin.php';
334
+			}
335
+			deactivate_plugins(plugin_basename(constant($plugin_file_constant)));
336
+			unset($_GET['activate'], $_REQUEST['activate'], $_GET['activate-multi'], $_REQUEST['activate-multi']);
337
+			EE_Error::add_error(
338
+				sprintf(
339
+					esc_html__(
340
+						'We\'re sorry, but the Event Espresso %1$s addon was deactivated because version %2$s or higher is required with this version of Event Espresso core.',
341
+						'event_espresso'
342
+					),
343
+					$addon_name,
344
+					$min_version_required
345
+				),
346
+				__FILE__, __FUNCTION__ . "({$addon_name})", __LINE__
347
+			);
348
+			EE_Error::get_notices(false, true);
349
+		}
350
+	}
351
+
352
+
353
+	/**
354
+	 * load_espresso_addons
355
+	 * allow addons to load first so that they can set hooks for running DMS's, etc
356
+	 * this is hooked into both:
357
+	 *    'AHEE__EE_Bootstrap__load_core_configuration'
358
+	 *        which runs during the WP 'plugins_loaded' action at priority 5
359
+	 *    and the WP 'activate_plugin' hook point
360
+	 *
361
+	 * @access public
362
+	 * @return void
363
+	 */
364
+	public function load_espresso_addons()
365
+	{
366
+		$this->deactivateIncompatibleAddon(
367
+			'Wait Lists',
368
+			'EE_WAIT_LISTS_VERSION',
369
+			'1.0.0.beta.074',
370
+			'load_espresso_wait_lists',
371
+			'EE_WAIT_LISTS_PLUGIN_FILE'
372
+		);
373
+		$this->deactivateIncompatibleAddon(
374
+			'Automated Upcoming Event Notifications',
375
+			'EE_AUTOMATED_UPCOMING_EVENT_NOTIFICATION_VERSION',
376
+			'1.0.0.beta.091',
377
+			'load_espresso_automated_upcoming_event_notification',
378
+			'EE_AUTOMATED_UPCOMING_EVENT_NOTIFICATION_PLUGIN_FILE'
379
+		);
380
+		do_action('AHEE__EE_System__load_espresso_addons');
381
+		//if the WP API basic auth plugin isn't already loaded, load it now.
382
+		//We want it for mobile apps. Just include the entire plugin
383
+		//also, don't load the basic auth when a plugin is getting activated, because
384
+		//it could be the basic auth plugin, and it doesn't check if its methods are already defined
385
+		//and causes a fatal error
386
+		if (
387
+			$this->request->getRequestParam('activate') !== 'true'
388
+			&& ! function_exists('json_basic_auth_handler')
389
+			&& ! function_exists('json_basic_auth_error')
390
+			&& ! in_array(
391
+				$this->request->getRequestParam('action'),
392
+				array('activate', 'activate-selected'),
393
+				true
394
+			)
395
+		) {
396
+			include_once EE_THIRD_PARTY . 'wp-api-basic-auth' . DS . 'basic-auth.php';
397
+		}
398
+		do_action('AHEE__EE_System__load_espresso_addons__complete');
399
+	}
400
+
401
+
402
+
403
+	/**
404
+	 * detect_activations_or_upgrades
405
+	 * Checks for activation or upgrade of core first;
406
+	 * then also checks if any registered addons have been activated or upgraded
407
+	 * This is hooked into 'AHEE__EE_Bootstrap__detect_activations_or_upgrades'
408
+	 * which runs during the WP 'plugins_loaded' action at priority 3
409
+	 *
410
+	 * @access public
411
+	 * @return void
412
+	 */
413
+	public function detect_activations_or_upgrades()
414
+	{
415
+		//first off: let's make sure to handle core
416
+		$this->detect_if_activation_or_upgrade();
417
+		foreach ($this->registry->addons as $addon) {
418
+			if ($addon instanceof EE_Addon) {
419
+				//detect teh request type for that addon
420
+				$addon->detect_activation_or_upgrade();
421
+			}
422
+		}
423
+	}
424
+
425
+
426
+
427
+	/**
428
+	 * detect_if_activation_or_upgrade
429
+	 * Takes care of detecting whether this is a brand new install or code upgrade,
430
+	 * and either setting up the DB or setting up maintenance mode etc.
431
+	 *
432
+	 * @access public
433
+	 * @return void
434
+	 */
435
+	public function detect_if_activation_or_upgrade()
436
+	{
437
+		do_action('AHEE__EE_System___detect_if_activation_or_upgrade__begin');
438
+		// check if db has been updated, or if its a brand-new installation
439
+		$espresso_db_update = $this->fix_espresso_db_upgrade_option();
440
+		$request_type       = $this->detect_req_type($espresso_db_update);
441
+		//EEH_Debug_Tools::printr( $request_type, '$request_type', __FILE__, __LINE__ );
442
+		switch ($request_type) {
443
+			case EE_System::req_type_new_activation:
444
+				do_action('AHEE__EE_System__detect_if_activation_or_upgrade__new_activation');
445
+				$this->_handle_core_version_change($espresso_db_update);
446
+				break;
447
+			case EE_System::req_type_reactivation:
448
+				do_action('AHEE__EE_System__detect_if_activation_or_upgrade__reactivation');
449
+				$this->_handle_core_version_change($espresso_db_update);
450
+				break;
451
+			case EE_System::req_type_upgrade:
452
+				do_action('AHEE__EE_System__detect_if_activation_or_upgrade__upgrade');
453
+				//migrations may be required now that we've upgraded
454
+				$this->maintenance_mode->set_maintenance_mode_if_db_old();
455
+				$this->_handle_core_version_change($espresso_db_update);
456
+				//				echo "done upgrade";die;
457
+				break;
458
+			case EE_System::req_type_downgrade:
459
+				do_action('AHEE__EE_System__detect_if_activation_or_upgrade__downgrade');
460
+				//its possible migrations are no longer required
461
+				$this->maintenance_mode->set_maintenance_mode_if_db_old();
462
+				$this->_handle_core_version_change($espresso_db_update);
463
+				break;
464
+			case EE_System::req_type_normal:
465
+			default:
466
+				break;
467
+		}
468
+		do_action('AHEE__EE_System__detect_if_activation_or_upgrade__complete');
469
+	}
470
+
471
+
472
+
473
+	/**
474
+	 * Updates the list of installed versions and sets hooks for
475
+	 * initializing the database later during the request
476
+	 *
477
+	 * @param array $espresso_db_update
478
+	 */
479
+	private function _handle_core_version_change($espresso_db_update)
480
+	{
481
+		$this->update_list_of_installed_versions($espresso_db_update);
482
+		//get ready to verify the DB is ok (provided we aren't in maintenance mode, of course)
483
+		add_action(
484
+			'AHEE__EE_System__perform_activations_upgrades_and_migrations',
485
+			array($this, 'initialize_db_if_no_migrations_required')
486
+		);
487
+	}
488
+
489
+
490
+
491
+	/**
492
+	 * standardizes the wp option 'espresso_db_upgrade' which actually stores
493
+	 * information about what versions of EE have been installed and activated,
494
+	 * NOT necessarily the state of the database
495
+	 *
496
+	 * @param mixed $espresso_db_update           the value of the WordPress option.
497
+	 *                                            If not supplied, fetches it from the options table
498
+	 * @return array the correct value of 'espresso_db_upgrade', after saving it, if it needed correction
499
+	 */
500
+	private function fix_espresso_db_upgrade_option($espresso_db_update = null)
501
+	{
502
+		do_action('FHEE__EE_System__manage_fix_espresso_db_upgrade_option__begin', $espresso_db_update);
503
+		if (! $espresso_db_update) {
504
+			$espresso_db_update = get_option('espresso_db_update');
505
+		}
506
+		// check that option is an array
507
+		if (! is_array($espresso_db_update)) {
508
+			// if option is FALSE, then it never existed
509
+			if ($espresso_db_update === false) {
510
+				// make $espresso_db_update an array and save option with autoload OFF
511
+				$espresso_db_update = array();
512
+				add_option('espresso_db_update', $espresso_db_update, '', 'no');
513
+			} else {
514
+				// option is NOT FALSE but also is NOT an array, so make it an array and save it
515
+				$espresso_db_update = array($espresso_db_update => array());
516
+				update_option('espresso_db_update', $espresso_db_update);
517
+			}
518
+		} else {
519
+			$corrected_db_update = array();
520
+			//if IS an array, but is it an array where KEYS are version numbers, and values are arrays?
521
+			foreach ($espresso_db_update as $should_be_version_string => $should_be_array) {
522
+				if (is_int($should_be_version_string) && ! is_array($should_be_array)) {
523
+					//the key is an int, and the value IS NOT an array
524
+					//so it must be numerically-indexed, where values are versions installed...
525
+					//fix it!
526
+					$version_string                         = $should_be_array;
527
+					$corrected_db_update[ $version_string ] = array('unknown-date');
528
+				} else {
529
+					//ok it checks out
530
+					$corrected_db_update[ $should_be_version_string ] = $should_be_array;
531
+				}
532
+			}
533
+			$espresso_db_update = $corrected_db_update;
534
+			update_option('espresso_db_update', $espresso_db_update);
535
+		}
536
+		do_action('FHEE__EE_System__manage_fix_espresso_db_upgrade_option__complete', $espresso_db_update);
537
+		return $espresso_db_update;
538
+	}
539
+
540
+
541
+
542
+	/**
543
+	 * Does the traditional work of setting up the plugin's database and adding default data.
544
+	 * If migration script/process did not exist, this is what would happen on every activation/reactivation/upgrade.
545
+	 * NOTE: if we're in maintenance mode (which would be the case if we detect there are data
546
+	 * migration scripts that need to be run and a version change happens), enqueues core for database initialization,
547
+	 * so that it will be done when migrations are finished
548
+	 *
549
+	 * @param boolean $initialize_addons_too if true, we double-check addons' database tables etc too;
550
+	 * @param boolean $verify_schema         if true will re-check the database tables have the correct schema.
551
+	 *                                       This is a resource-intensive job
552
+	 *                                       so we prefer to only do it when necessary
553
+	 * @return void
554
+	 * @throws EE_Error
555
+	 */
556
+	public function initialize_db_if_no_migrations_required($initialize_addons_too = false, $verify_schema = true)
557
+	{
558
+		$request_type = $this->detect_req_type();
559
+		//only initialize system if we're not in maintenance mode.
560
+		if ($this->maintenance_mode->level() !== EE_Maintenance_Mode::level_2_complete_maintenance) {
561
+			update_option('ee_flush_rewrite_rules', true);
562
+			if ($verify_schema) {
563
+				EEH_Activation::initialize_db_and_folders();
564
+			}
565
+			EEH_Activation::initialize_db_content();
566
+			EEH_Activation::system_initialization();
567
+			if ($initialize_addons_too) {
568
+				$this->initialize_addons();
569
+			}
570
+		} else {
571
+			EE_Data_Migration_Manager::instance()->enqueue_db_initialization_for('Core');
572
+		}
573
+		if ($request_type === EE_System::req_type_new_activation
574
+			|| $request_type === EE_System::req_type_reactivation
575
+			|| (
576
+				$request_type === EE_System::req_type_upgrade
577
+				&& $this->is_major_version_change()
578
+			)
579
+		) {
580
+			add_action('AHEE__EE_System__initialize_last', array($this, 'redirect_to_about_ee'), 9);
581
+		}
582
+	}
583
+
584
+
585
+
586
+	/**
587
+	 * Initializes the db for all registered addons
588
+	 *
589
+	 * @throws EE_Error
590
+	 */
591
+	public function initialize_addons()
592
+	{
593
+		//foreach registered addon, make sure its db is up-to-date too
594
+		foreach ($this->registry->addons as $addon) {
595
+			if ($addon instanceof EE_Addon) {
596
+				$addon->initialize_db_if_no_migrations_required();
597
+			}
598
+		}
599
+	}
600
+
601
+
602
+
603
+	/**
604
+	 * Adds the current code version to the saved wp option which stores a list of all ee versions ever installed.
605
+	 *
606
+	 * @param    array  $version_history
607
+	 * @param    string $current_version_to_add version to be added to the version history
608
+	 * @return    boolean success as to whether or not this option was changed
609
+	 */
610
+	public function update_list_of_installed_versions($version_history = null, $current_version_to_add = null)
611
+	{
612
+		if (! $version_history) {
613
+			$version_history = $this->fix_espresso_db_upgrade_option($version_history);
614
+		}
615
+		if ($current_version_to_add === null) {
616
+			$current_version_to_add = espresso_version();
617
+		}
618
+		$version_history[ $current_version_to_add ][] = date('Y-m-d H:i:s', time());
619
+		// re-save
620
+		return update_option('espresso_db_update', $version_history);
621
+	}
622
+
623
+
624
+
625
+	/**
626
+	 * Detects if the current version indicated in the has existed in the list of
627
+	 * previously-installed versions of EE (espresso_db_update). Does NOT modify it (ie, no side-effect)
628
+	 *
629
+	 * @param array $espresso_db_update array from the wp option stored under the name 'espresso_db_update'.
630
+	 *                                  If not supplied, fetches it from the options table.
631
+	 *                                  Also, caches its result so later parts of the code can also know whether
632
+	 *                                  there's been an update or not. This way we can add the current version to
633
+	 *                                  espresso_db_update, but still know if this is a new install or not
634
+	 * @return int one of the constants on EE_System::req_type_
635
+	 */
636
+	public function detect_req_type($espresso_db_update = null)
637
+	{
638
+		if ($this->_req_type === null) {
639
+			$espresso_db_update          = ! empty($espresso_db_update)
640
+				? $espresso_db_update
641
+				: $this->fix_espresso_db_upgrade_option();
642
+			$this->_req_type             = EE_System::detect_req_type_given_activation_history(
643
+				$espresso_db_update,
644
+				'ee_espresso_activation', espresso_version()
645
+			);
646
+			$this->_major_version_change = $this->_detect_major_version_change($espresso_db_update);
647
+			$this->request->setIsActivation($this->_req_type !== EE_System::req_type_normal);
648
+		}
649
+		return $this->_req_type;
650
+	}
651
+
652
+
653
+
654
+	/**
655
+	 * Returns whether or not there was a non-micro version change (ie, change in either
656
+	 * the first or second number in the version. Eg 4.9.0.rc.001 to 4.10.0.rc.000,
657
+	 * but not 4.9.0.rc.0001 to 4.9.1.rc.0001
658
+	 *
659
+	 * @param $activation_history
660
+	 * @return bool
661
+	 */
662
+	private function _detect_major_version_change($activation_history)
663
+	{
664
+		$previous_version       = EE_System::_get_most_recently_active_version_from_activation_history($activation_history);
665
+		$previous_version_parts = explode('.', $previous_version);
666
+		$current_version_parts  = explode('.', espresso_version());
667
+		return isset($previous_version_parts[0], $previous_version_parts[1], $current_version_parts[0], $current_version_parts[1])
668
+			   && ($previous_version_parts[0] !== $current_version_parts[0]
669
+				   || $previous_version_parts[1] !== $current_version_parts[1]
670
+			   );
671
+	}
672
+
673
+
674
+
675
+	/**
676
+	 * Returns true if either the major or minor version of EE changed during this request.
677
+	 * Eg 4.9.0.rc.001 to 4.10.0.rc.000, but not 4.9.0.rc.0001 to 4.9.1.rc.0001
678
+	 *
679
+	 * @return bool
680
+	 */
681
+	public function is_major_version_change()
682
+	{
683
+		return $this->_major_version_change;
684
+	}
685
+
686
+
687
+
688
+	/**
689
+	 * Determines the request type for any ee addon, given three piece of info: the current array of activation
690
+	 * histories (for core that' 'espresso_db_update' wp option); the name of the WordPress option which is temporarily
691
+	 * set upon activation of the plugin (for core it's 'ee_espresso_activation'); and the version that this plugin was
692
+	 * just activated to (for core that will always be espresso_version())
693
+	 *
694
+	 * @param array  $activation_history_for_addon     the option's value which stores the activation history for this
695
+	 *                                                 ee plugin. for core that's 'espresso_db_update'
696
+	 * @param string $activation_indicator_option_name the name of the WordPress option that is temporarily set to
697
+	 *                                                 indicate that this plugin was just activated
698
+	 * @param string $version_to_upgrade_to            the version that was just upgraded to (for core that will be
699
+	 *                                                 espresso_version())
700
+	 * @return int one of the constants on EE_System::req_type_*
701
+	 */
702
+	public static function detect_req_type_given_activation_history(
703
+		$activation_history_for_addon,
704
+		$activation_indicator_option_name,
705
+		$version_to_upgrade_to
706
+	) {
707
+		$version_is_higher = self::_new_version_is_higher($activation_history_for_addon, $version_to_upgrade_to);
708
+		if ($activation_history_for_addon) {
709
+			//it exists, so this isn't a completely new install
710
+			//check if this version already in that list of previously installed versions
711
+			if (! isset($activation_history_for_addon[ $version_to_upgrade_to ])) {
712
+				//it a version we haven't seen before
713
+				if ($version_is_higher === 1) {
714
+					$req_type = EE_System::req_type_upgrade;
715
+				} else {
716
+					$req_type = EE_System::req_type_downgrade;
717
+				}
718
+				delete_option($activation_indicator_option_name);
719
+			} else {
720
+				// its not an update. maybe a reactivation?
721
+				if (get_option($activation_indicator_option_name, false)) {
722
+					if ($version_is_higher === -1) {
723
+						$req_type = EE_System::req_type_downgrade;
724
+					} elseif ($version_is_higher === 0) {
725
+						//we've seen this version before, but it's an activation. must be a reactivation
726
+						$req_type = EE_System::req_type_reactivation;
727
+					} else {//$version_is_higher === 1
728
+						$req_type = EE_System::req_type_upgrade;
729
+					}
730
+					delete_option($activation_indicator_option_name);
731
+				} else {
732
+					//we've seen this version before and the activation indicate doesn't show it was just activated
733
+					if ($version_is_higher === -1) {
734
+						$req_type = EE_System::req_type_downgrade;
735
+					} elseif ($version_is_higher === 0) {
736
+						//we've seen this version before and it's not an activation. its normal request
737
+						$req_type = EE_System::req_type_normal;
738
+					} else {//$version_is_higher === 1
739
+						$req_type = EE_System::req_type_upgrade;
740
+					}
741
+				}
742
+			}
743
+		} else {
744
+			//brand new install
745
+			$req_type = EE_System::req_type_new_activation;
746
+			delete_option($activation_indicator_option_name);
747
+		}
748
+		return $req_type;
749
+	}
750
+
751
+
752
+
753
+	/**
754
+	 * Detects if the $version_to_upgrade_to is higher than the most recent version in
755
+	 * the $activation_history_for_addon
756
+	 *
757
+	 * @param array  $activation_history_for_addon (keys are versions, values are arrays of times activated,
758
+	 *                                             sometimes containing 'unknown-date'
759
+	 * @param string $version_to_upgrade_to        (current version)
760
+	 * @return int results of version_compare( $version_to_upgrade_to, $most_recently_active_version ).
761
+	 *                                             ie, -1 if $version_to_upgrade_to is LOWER (downgrade);
762
+	 *                                             0 if $version_to_upgrade_to MATCHES (reactivation or normal request);
763
+	 *                                             1 if $version_to_upgrade_to is HIGHER (upgrade) ;
764
+	 */
765
+	private static function _new_version_is_higher($activation_history_for_addon, $version_to_upgrade_to)
766
+	{
767
+		//find the most recently-activated version
768
+		$most_recently_active_version =
769
+			EE_System::_get_most_recently_active_version_from_activation_history($activation_history_for_addon);
770
+		return version_compare($version_to_upgrade_to, $most_recently_active_version);
771
+	}
772
+
773
+
774
+
775
+	/**
776
+	 * Gets the most recently active version listed in the activation history,
777
+	 * and if none are found (ie, it's a brand new install) returns '0.0.0.dev.000'.
778
+	 *
779
+	 * @param array $activation_history  (keys are versions, values are arrays of times activated,
780
+	 *                                   sometimes containing 'unknown-date'
781
+	 * @return string
782
+	 */
783
+	private static function _get_most_recently_active_version_from_activation_history($activation_history)
784
+	{
785
+		$most_recently_active_version_activation = '1970-01-01 00:00:00';
786
+		$most_recently_active_version            = '0.0.0.dev.000';
787
+		if (is_array($activation_history)) {
788
+			foreach ($activation_history as $version => $times_activated) {
789
+				//check there is a record of when this version was activated. Otherwise,
790
+				//mark it as unknown
791
+				if (! $times_activated) {
792
+					$times_activated = array('unknown-date');
793
+				}
794
+				if (is_string($times_activated)) {
795
+					$times_activated = array($times_activated);
796
+				}
797
+				foreach ($times_activated as $an_activation) {
798
+					if ($an_activation !== 'unknown-date'
799
+						&& $an_activation
800
+						   > $most_recently_active_version_activation) {
801
+						$most_recently_active_version            = $version;
802
+						$most_recently_active_version_activation = $an_activation === 'unknown-date'
803
+							? '1970-01-01 00:00:00'
804
+							: $an_activation;
805
+					}
806
+				}
807
+			}
808
+		}
809
+		return $most_recently_active_version;
810
+	}
811
+
812
+
813
+
814
+	/**
815
+	 * This redirects to the about EE page after activation
816
+	 *
817
+	 * @return void
818
+	 */
819
+	public function redirect_to_about_ee()
820
+	{
821
+		$notices = EE_Error::get_notices(false);
822
+		//if current user is an admin and it's not an ajax or rest request
823
+		if (
824
+			! isset($notices['errors'])
825
+			&& $this->request->isAdmin()
826
+			&& apply_filters(
827
+				'FHEE__EE_System__redirect_to_about_ee__do_redirect',
828
+				$this->capabilities->current_user_can('manage_options', 'espresso_about_default')
829
+			)
830
+		) {
831
+			$query_params = array('page' => 'espresso_about');
832
+			if (EE_System::instance()->detect_req_type() === EE_System::req_type_new_activation) {
833
+				$query_params['new_activation'] = true;
834
+			}
835
+			if (EE_System::instance()->detect_req_type() === EE_System::req_type_reactivation) {
836
+				$query_params['reactivation'] = true;
837
+			}
838
+			$url = add_query_arg($query_params, admin_url('admin.php'));
839
+			wp_safe_redirect($url);
840
+			exit();
841
+		}
842
+	}
843
+
844
+
845
+
846
+	/**
847
+	 * load_core_configuration
848
+	 * this is hooked into 'AHEE__EE_Bootstrap__load_core_configuration'
849
+	 * which runs during the WP 'plugins_loaded' action at priority 5
850
+	 *
851
+	 * @return void
852
+	 * @throws ReflectionException
853
+	 */
854
+	public function load_core_configuration()
855
+	{
856
+		do_action('AHEE__EE_System__load_core_configuration__begin', $this);
857
+		$this->loader->getShared('EE_Load_Textdomain');
858
+		//load textdomain
859
+		EE_Load_Textdomain::load_textdomain();
860
+		// load and setup EE_Config and EE_Network_Config
861
+		$config = $this->loader->getShared('EE_Config');
862
+		$this->loader->getShared('EE_Network_Config');
863
+		// setup autoloaders
864
+		// enable logging?
865
+		if ($config->admin->use_full_logging) {
866
+			$this->loader->getShared('EE_Log');
867
+		}
868
+		// check for activation errors
869
+		$activation_errors = get_option('ee_plugin_activation_errors', false);
870
+		if ($activation_errors) {
871
+			EE_Error::add_error($activation_errors, __FILE__, __FUNCTION__, __LINE__);
872
+			update_option('ee_plugin_activation_errors', false);
873
+		}
874
+		// get model names
875
+		$this->_parse_model_names();
876
+		//load caf stuff a chance to play during the activation process too.
877
+		$this->_maybe_brew_regular();
878
+		do_action('AHEE__EE_System__load_core_configuration__complete', $this);
879
+	}
880
+
881
+
882
+
883
+	/**
884
+	 * cycles through all of the models/*.model.php files, and assembles an array of model names
885
+	 *
886
+	 * @return void
887
+	 * @throws ReflectionException
888
+	 */
889
+	private function _parse_model_names()
890
+	{
891
+		//get all the files in the EE_MODELS folder that end in .model.php
892
+		$models                 = glob(EE_MODELS . '*.model.php');
893
+		$model_names            = array();
894
+		$non_abstract_db_models = array();
895
+		foreach ($models as $model) {
896
+			// get model classname
897
+			$classname       = EEH_File::get_classname_from_filepath_with_standard_filename($model);
898
+			$short_name      = str_replace('EEM_', '', $classname);
899
+			$reflectionClass = new ReflectionClass($classname);
900
+			if ($reflectionClass->isSubclassOf('EEM_Base') && ! $reflectionClass->isAbstract()) {
901
+				$non_abstract_db_models[ $short_name ] = $classname;
902
+			}
903
+			$model_names[ $short_name ] = $classname;
904
+		}
905
+		$this->registry->models                 = apply_filters('FHEE__EE_System__parse_model_names', $model_names);
906
+		$this->registry->non_abstract_db_models = apply_filters(
907
+			'FHEE__EE_System__parse_implemented_model_names',
908
+			$non_abstract_db_models
909
+		);
910
+	}
911
+
912
+
913
+
914
+	/**
915
+	 * The purpose of this method is to simply check for a file named "caffeinated/brewing_regular.php" for any hooks
916
+	 * that need to be setup before our EE_System launches.
917
+	 *
918
+	 * @return void
919
+	 */
920
+	private function _maybe_brew_regular()
921
+	{
922
+		if ((! defined('EE_DECAF') || EE_DECAF !== true) && is_readable(EE_CAFF_PATH . 'brewing_regular.php')) {
923
+			require_once EE_CAFF_PATH . 'brewing_regular.php';
924
+		}
925
+	}
926
+
927
+
928
+
929
+	/**
930
+	 * register_shortcodes_modules_and_widgets
931
+	 * generate lists of shortcodes and modules, then verify paths and classes
932
+	 * This is hooked into 'AHEE__EE_Bootstrap__register_shortcodes_modules_and_widgets'
933
+	 * which runs during the WP 'plugins_loaded' action at priority 7
934
+	 *
935
+	 * @access public
936
+	 * @return void
937
+	 * @throws Exception
938
+	 */
939
+	public function register_shortcodes_modules_and_widgets()
940
+	{
941
+		if ($this->request->isFrontend() || $this->request->isIframe()) {
942
+			try {
943
+				// load, register, and add shortcodes the new way
944
+				$this->loader->getShared(
945
+					'EventEspresso\core\services\shortcodes\ShortcodesManager',
946
+					array(
947
+						// and the old way, but we'll put it under control of the new system
948
+						EE_Config::getLegacyShortcodesManager(),
949
+					)
950
+				);
951
+			} catch (Exception $exception) {
952
+				new ExceptionStackTraceDisplay($exception);
953
+			}
954
+		}
955
+		do_action('AHEE__EE_System__register_shortcodes_modules_and_widgets');
956
+		// check for addons using old hook point
957
+		if (has_action('AHEE__EE_System__register_shortcodes_modules_and_addons')) {
958
+			$this->_incompatible_addon_error();
959
+		}
960
+	}
961
+
962
+
963
+
964
+	/**
965
+	 * _incompatible_addon_error
966
+	 *
967
+	 * @access public
968
+	 * @return void
969
+	 */
970
+	private function _incompatible_addon_error()
971
+	{
972
+		// get array of classes hooking into here
973
+		$class_names = EEH_Class_Tools::get_class_names_for_all_callbacks_on_hook(
974
+			'AHEE__EE_System__register_shortcodes_modules_and_addons'
975
+		);
976
+		if (! empty($class_names)) {
977
+			$msg = __(
978
+				'The following plugins, addons, or modules appear to be incompatible with this version of Event Espresso and were automatically deactivated to avoid fatal errors:',
979
+				'event_espresso'
980
+			);
981
+			$msg .= '<ul>';
982
+			foreach ($class_names as $class_name) {
983
+				$msg .= '<li><b>Event Espresso - ' . str_replace(
984
+						array('EE_', 'EEM_', 'EED_', 'EES_', 'EEW_'), '',
985
+						$class_name
986
+					) . '</b></li>';
987
+			}
988
+			$msg .= '</ul>';
989
+			$msg .= __(
990
+				'Compatibility issues can be avoided and/or resolved by keeping addons and plugins updated to the latest version.',
991
+				'event_espresso'
992
+			);
993
+			// save list of incompatible addons to wp-options for later use
994
+			add_option('ee_incompatible_addons', $class_names, '', 'no');
995
+			if (is_admin()) {
996
+				EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
997
+			}
998
+		}
999
+	}
1000
+
1001
+
1002
+
1003
+	/**
1004
+	 * brew_espresso
1005
+	 * begins the process of setting hooks for initializing EE in the correct order
1006
+	 * This is happening on the 'AHEE__EE_Bootstrap__brew_espresso' hook point
1007
+	 * which runs during the WP 'plugins_loaded' action at priority 9
1008
+	 *
1009
+	 * @return void
1010
+	 */
1011
+	public function brew_espresso()
1012
+	{
1013
+		do_action('AHEE__EE_System__brew_espresso__begin', $this);
1014
+		// load some final core systems
1015
+		add_action('init', array($this, 'set_hooks_for_core'), 1);
1016
+		add_action('init', array($this, 'perform_activations_upgrades_and_migrations'), 3);
1017
+		add_action('init', array($this, 'load_CPTs_and_session'), 5);
1018
+		add_action('init', array($this, 'load_controllers'), 7);
1019
+		add_action('init', array($this, 'core_loaded_and_ready'), 9);
1020
+		add_action('init', array($this, 'initialize'), 10);
1021
+		add_action('init', array($this, 'initialize_last'), 100);
1022
+		if (is_admin() && apply_filters('FHEE__EE_System__brew_espresso__load_pue', true)) {
1023
+			// pew pew pew
1024
+			$this->loader->getShared('EE_PUE');
1025
+			do_action('AHEE__EE_System__brew_espresso__after_pue_init');
1026
+		}
1027
+		do_action('AHEE__EE_System__brew_espresso__complete', $this);
1028
+	}
1029
+
1030
+
1031
+
1032
+	/**
1033
+	 *    set_hooks_for_core
1034
+	 *
1035
+	 * @access public
1036
+	 * @return    void
1037
+	 * @throws EE_Error
1038
+	 */
1039
+	public function set_hooks_for_core()
1040
+	{
1041
+		$this->_deactivate_incompatible_addons();
1042
+		do_action('AHEE__EE_System__set_hooks_for_core');
1043
+		$this->loader->getShared('EventEspresso\core\domain\values\session\SessionLifespan');
1044
+		//caps need to be initialized on every request so that capability maps are set.
1045
+		//@see https://events.codebasehq.com/projects/event-espresso/tickets/8674
1046
+		$this->registry->CAP->init_caps();
1047
+	}
1048
+
1049
+
1050
+
1051
+	/**
1052
+	 * Using the information gathered in EE_System::_incompatible_addon_error,
1053
+	 * deactivates any addons considered incompatible with the current version of EE
1054
+	 */
1055
+	private function _deactivate_incompatible_addons()
1056
+	{
1057
+		$incompatible_addons = get_option('ee_incompatible_addons', array());
1058
+		if (! empty($incompatible_addons)) {
1059
+			$active_plugins = get_option('active_plugins', array());
1060
+			foreach ($active_plugins as $active_plugin) {
1061
+				foreach ($incompatible_addons as $incompatible_addon) {
1062
+					if (strpos($active_plugin, $incompatible_addon) !== false) {
1063
+						unset($_GET['activate']);
1064
+						espresso_deactivate_plugin($active_plugin);
1065
+					}
1066
+				}
1067
+			}
1068
+		}
1069
+	}
1070
+
1071
+
1072
+
1073
+	/**
1074
+	 *    perform_activations_upgrades_and_migrations
1075
+	 *
1076
+	 * @access public
1077
+	 * @return    void
1078
+	 */
1079
+	public function perform_activations_upgrades_and_migrations()
1080
+	{
1081
+		//first check if we had previously attempted to setup EE's directories but failed
1082
+		if ($this->request->isActivation() && EEH_Activation::upload_directories_incomplete()) {
1083
+			EEH_Activation::create_upload_directories();
1084
+		}
1085
+		do_action('AHEE__EE_System__perform_activations_upgrades_and_migrations');
1086
+	}
1087
+
1088
+
1089
+
1090
+	/**
1091
+	 *    load_CPTs_and_session
1092
+	 *
1093
+	 * @access public
1094
+	 * @return    void
1095
+	 */
1096
+	public function load_CPTs_and_session()
1097
+	{
1098
+		do_action('AHEE__EE_System__load_CPTs_and_session__start');
1099
+		// register Custom Post Types
1100
+		$this->loader->getShared('EE_Register_CPTs');
1101
+		do_action('AHEE__EE_System__load_CPTs_and_session__complete');
1102
+	}
1103
+
1104
+
1105
+
1106
+	/**
1107
+	 * load_controllers
1108
+	 * this is the best place to load any additional controllers that needs access to EE core.
1109
+	 * it is expected that all basic core EE systems, that are not dependant on the current request are loaded at this
1110
+	 * time
1111
+	 *
1112
+	 * @access public
1113
+	 * @return void
1114
+	 */
1115
+	public function load_controllers()
1116
+	{
1117
+		do_action('AHEE__EE_System__load_controllers__start');
1118
+		// let's get it started
1119
+		if (
1120
+			! $this->maintenance_mode->level()
1121
+			&& ($this->request->isFrontend() || $this->request->isFrontAjax())
1122
+		) {
1123
+			do_action('AHEE__EE_System__load_controllers__load_front_controllers');
1124
+			$this->loader->getShared('EE_Front_Controller');
1125
+		} elseif ($this->request->isAdmin() || $this->request->isAdminAjax()) {
1126
+			do_action('AHEE__EE_System__load_controllers__load_admin_controllers');
1127
+			$this->loader->getShared('EE_Admin');
1128
+		}
1129
+		do_action('AHEE__EE_System__load_controllers__complete');
1130
+	}
1131
+
1132
+
1133
+
1134
+	/**
1135
+	 * core_loaded_and_ready
1136
+	 * all of the basic EE core should be loaded at this point and available regardless of M-Mode
1137
+	 *
1138
+	 * @access public
1139
+	 * @return void
1140
+	 */
1141
+	public function core_loaded_and_ready()
1142
+	{
1143
+		if (
1144
+			$this->request->isAdmin()
1145
+			|| $this->request->isEeAjax()
1146
+			|| $this->request->isFrontend()
1147
+		) {
1148
+			$this->loader->getShared('EE_Session');
1149
+		}
1150
+		do_action('AHEE__EE_System__core_loaded_and_ready');
1151
+		// load_espresso_template_tags
1152
+		if (
1153
+			is_readable(EE_PUBLIC . 'template_tags.php')
1154
+			&& ($this->request->isFrontend() || $this->request->isIframe() || $this->request->isFeed())
1155
+		) {
1156
+			require_once EE_PUBLIC . 'template_tags.php';
1157
+		}
1158
+		do_action('AHEE__EE_System__set_hooks_for_shortcodes_modules_and_addons');
1159
+		if ($this->request->isAdmin() || $this->request->isFrontend() || $this->request->isIframe()) {
1160
+			$this->loader->getShared('EventEspresso\core\services\assets\Registry');
1161
+		}
1162
+	}
1163
+
1164
+
1165
+
1166
+	/**
1167
+	 * initialize
1168
+	 * this is the best place to begin initializing client code
1169
+	 *
1170
+	 * @access public
1171
+	 * @return void
1172
+	 */
1173
+	public function initialize()
1174
+	{
1175
+		do_action('AHEE__EE_System__initialize');
1176
+	}
1177
+
1178
+
1179
+
1180
+	/**
1181
+	 * initialize_last
1182
+	 * this is run really late during the WP init hook point, and ensures that mostly everything else that needs to
1183
+	 * initialize has done so
1184
+	 *
1185
+	 * @access public
1186
+	 * @return void
1187
+	 */
1188
+	public function initialize_last()
1189
+	{
1190
+		do_action('AHEE__EE_System__initialize_last');
1191
+		add_action('admin_bar_init', array($this, 'addEspressoToolbar'));
1192
+	}
1193
+
1194
+
1195
+
1196
+	/**
1197
+	 * @return void
1198
+	 * @throws EE_Error
1199
+	 */
1200
+	public function addEspressoToolbar()
1201
+	{
1202
+		$this->loader->getShared(
1203
+			'EventEspresso\core\domain\services\admin\AdminToolBar',
1204
+			array($this->registry->CAP)
1205
+		);
1206
+	}
1207
+
1208
+
1209
+
1210
+	/**
1211
+	 * do_not_cache
1212
+	 * sets no cache headers and defines no cache constants for WP plugins
1213
+	 *
1214
+	 * @access public
1215
+	 * @return void
1216
+	 */
1217
+	public static function do_not_cache()
1218
+	{
1219
+		// set no cache constants
1220
+		if (! defined('DONOTCACHEPAGE')) {
1221
+			define('DONOTCACHEPAGE', true);
1222
+		}
1223
+		if (! defined('DONOTCACHCEOBJECT')) {
1224
+			define('DONOTCACHCEOBJECT', true);
1225
+		}
1226
+		if (! defined('DONOTCACHEDB')) {
1227
+			define('DONOTCACHEDB', true);
1228
+		}
1229
+		// add no cache headers
1230
+		add_action('send_headers', array('EE_System', 'nocache_headers'), 10);
1231
+		// plus a little extra for nginx and Google Chrome
1232
+		add_filter('nocache_headers', array('EE_System', 'extra_nocache_headers'), 10, 1);
1233
+		// prevent browsers from prefetching of the rel='next' link, because it may contain content that interferes with the registration process
1234
+		remove_action('wp_head', 'adjacent_posts_rel_link_wp_head');
1235
+	}
1236
+
1237
+
1238
+
1239
+	/**
1240
+	 *    extra_nocache_headers
1241
+	 *
1242
+	 * @access    public
1243
+	 * @param $headers
1244
+	 * @return    array
1245
+	 */
1246
+	public static function extra_nocache_headers($headers)
1247
+	{
1248
+		// for NGINX
1249
+		$headers['X-Accel-Expires'] = 0;
1250
+		// plus extra for Google Chrome since it doesn't seem to respect "no-cache", but WILL respect "no-store"
1251
+		$headers['Cache-Control'] = 'no-store, no-cache, must-revalidate, max-age=0';
1252
+		return $headers;
1253
+	}
1254
+
1255
+
1256
+
1257
+	/**
1258
+	 *    nocache_headers
1259
+	 *
1260
+	 * @access    public
1261
+	 * @return    void
1262
+	 */
1263
+	public static function nocache_headers()
1264
+	{
1265
+		nocache_headers();
1266
+	}
1267
+
1268
+
1269
+
1270
+	/**
1271
+	 * simply hooks into "wp_list_pages_exclude" filter (for wp_list_pages method) and makes sure EE critical pages are
1272
+	 * never returned with the function.
1273
+	 *
1274
+	 * @param  array $exclude_array any existing pages being excluded are in this array.
1275
+	 * @return array
1276
+	 */
1277
+	public function remove_pages_from_wp_list_pages($exclude_array)
1278
+	{
1279
+		return array_merge($exclude_array, $this->registry->CFG->core->get_critical_pages_array());
1280
+	}
1281 1281
 
1282 1282
 
1283 1283
 
Please login to merge, or discard this patch.
core/admin/EE_Admin_Page.core.php 1 patch
Indentation   +4125 added lines, -4125 removed lines patch added patch discarded remove patch
@@ -21,4210 +21,4210 @@
 block discarded – undo
21 21
 {
22 22
 
23 23
 
24
-    //set in _init_page_props()
25
-    public $page_slug;
24
+	//set in _init_page_props()
25
+	public $page_slug;
26 26
 
27
-    public $page_label;
27
+	public $page_label;
28 28
 
29
-    public $page_folder;
29
+	public $page_folder;
30 30
 
31
-    //set in define_page_props()
32
-    protected $_admin_base_url;
31
+	//set in define_page_props()
32
+	protected $_admin_base_url;
33 33
 
34
-    protected $_admin_base_path;
34
+	protected $_admin_base_path;
35 35
 
36
-    protected $_admin_page_title;
36
+	protected $_admin_page_title;
37 37
 
38
-    protected $_labels;
38
+	protected $_labels;
39 39
 
40 40
 
41
-    //set early within EE_Admin_Init
42
-    protected $_wp_page_slug;
41
+	//set early within EE_Admin_Init
42
+	protected $_wp_page_slug;
43 43
 
44
-    //navtabs
45
-    protected $_nav_tabs;
44
+	//navtabs
45
+	protected $_nav_tabs;
46 46
 
47
-    protected $_default_nav_tab_name;
47
+	protected $_default_nav_tab_name;
48 48
 
49
-    /**
50
-     * @var array $_help_tour
51
-     */
52
-    protected $_help_tour = array();
49
+	/**
50
+	 * @var array $_help_tour
51
+	 */
52
+	protected $_help_tour = array();
53 53
 
54 54
 
55
-    //template variables (used by templates)
56
-    protected $_template_path;
55
+	//template variables (used by templates)
56
+	protected $_template_path;
57 57
 
58
-    protected $_column_template_path;
58
+	protected $_column_template_path;
59 59
 
60
-    /**
61
-     * @var array $_template_args
62
-     */
63
-    protected $_template_args = array();
60
+	/**
61
+	 * @var array $_template_args
62
+	 */
63
+	protected $_template_args = array();
64 64
 
65
-    /**
66
-     * this will hold the list table object for a given view.
67
-     *
68
-     * @var EE_Admin_List_Table $_list_table_object
69
-     */
70
-    protected $_list_table_object;
65
+	/**
66
+	 * this will hold the list table object for a given view.
67
+	 *
68
+	 * @var EE_Admin_List_Table $_list_table_object
69
+	 */
70
+	protected $_list_table_object;
71 71
 
72
-    //bools
73
-    protected $_is_UI_request = null; //this starts at null so we can have no header routes progress through two states.
72
+	//bools
73
+	protected $_is_UI_request = null; //this starts at null so we can have no header routes progress through two states.
74 74
 
75
-    protected $_routing;
75
+	protected $_routing;
76 76
 
77
-    //list table args
78
-    protected $_view;
77
+	//list table args
78
+	protected $_view;
79 79
 
80
-    protected $_views;
80
+	protected $_views;
81 81
 
82 82
 
83
-    //action => method pairs used for routing incoming requests
84
-    protected $_page_routes;
83
+	//action => method pairs used for routing incoming requests
84
+	protected $_page_routes;
85 85
 
86
-    /**
87
-     * @var array $_page_config
88
-     */
89
-    protected $_page_config;
86
+	/**
87
+	 * @var array $_page_config
88
+	 */
89
+	protected $_page_config;
90 90
 
91
-    /**
92
-     * the current page route and route config
93
-     *
94
-     * @var string $_route
95
-     */
96
-    protected $_route;
91
+	/**
92
+	 * the current page route and route config
93
+	 *
94
+	 * @var string $_route
95
+	 */
96
+	protected $_route;
97 97
 
98
-    /**
99
-     * @var string $_cpt_route
100
-     */
101
-    protected $_cpt_route;
98
+	/**
99
+	 * @var string $_cpt_route
100
+	 */
101
+	protected $_cpt_route;
102 102
 
103
-    /**
104
-     * @var array $_route_config
105
-     */
106
-    protected $_route_config;
103
+	/**
104
+	 * @var array $_route_config
105
+	 */
106
+	protected $_route_config;
107 107
 
108
-    /**
109
-     * Used to hold default query args for list table routes to help preserve stickiness of filters for carried out
110
-     * actions.
111
-     *
112
-     * @since 4.6.x
113
-     * @var array.
114
-     */
115
-    protected $_default_route_query_args;
116
-
117
-    //set via request page and action args.
118
-    protected $_current_page;
108
+	/**
109
+	 * Used to hold default query args for list table routes to help preserve stickiness of filters for carried out
110
+	 * actions.
111
+	 *
112
+	 * @since 4.6.x
113
+	 * @var array.
114
+	 */
115
+	protected $_default_route_query_args;
116
+
117
+	//set via request page and action args.
118
+	protected $_current_page;
119 119
 
120
-    protected $_current_view;
120
+	protected $_current_view;
121 121
 
122
-    protected $_current_page_view_url;
122
+	protected $_current_page_view_url;
123 123
 
124
-    //sanitized request action (and nonce)
124
+	//sanitized request action (and nonce)
125 125
 
126
-    /**
127
-     * @var string $_req_action
128
-     */
129
-    protected $_req_action;
130
-
131
-    /**
132
-     * @var string $_req_nonce
133
-     */
134
-    protected $_req_nonce;
135
-
136
-    //search related
137
-    protected $_search_btn_label;
138
-
139
-    protected $_search_box_callback;
140
-
141
-    /**
142
-     * WP Current Screen object
143
-     *
144
-     * @var WP_Screen
145
-     */
146
-    protected $_current_screen;
147
-
148
-    //for holding EE_Admin_Hooks object when needed (set via set_hook_object())
149
-    protected $_hook_obj;
150
-
151
-    //for holding incoming request data
152
-    protected $_req_data;
153
-
154
-    // yes / no array for admin form fields
155
-    protected $_yes_no_values = array();
156
-
157
-    //some default things shared by all child classes
158
-    protected $_default_espresso_metaboxes;
159
-
160
-    /**
161
-     *    EE_Registry Object
162
-     *
163
-     * @var    EE_Registry
164
-     */
165
-    protected $EE = null;
166
-
167
-
168
-
169
-    /**
170
-     * This is just a property that flags whether the given route is a caffeinated route or not.
171
-     *
172
-     * @var boolean
173
-     */
174
-    protected $_is_caf = false;
175
-
176
-
177
-
178
-    /**
179
-     * @Constructor
180
-     * @param bool $routing indicate whether we want to just load the object and handle routing or just load the object.
181
-     * @throws EE_Error
182
-     * @throws InvalidArgumentException
183
-     * @throws ReflectionException
184
-     * @throws InvalidDataTypeException
185
-     * @throws InvalidInterfaceException
186
-     */
187
-    public function __construct($routing = true)
188
-    {
189
-        if (strpos($this->_get_dir(), 'caffeinated') !== false) {
190
-            $this->_is_caf = true;
191
-        }
192
-        $this->_yes_no_values = array(
193
-            array('id' => true, 'text' => esc_html__('Yes', 'event_espresso')),
194
-            array('id' => false, 'text' => esc_html__('No', 'event_espresso')),
195
-        );
196
-        //set the _req_data property.
197
-        $this->_req_data = array_merge($_GET, $_POST);
198
-        //routing enabled?
199
-        $this->_routing = $routing;
200
-        //set initial page props (child method)
201
-        $this->_init_page_props();
202
-        //set global defaults
203
-        $this->_set_defaults();
204
-        //set early because incoming requests could be ajax related and we need to register those hooks.
205
-        $this->_global_ajax_hooks();
206
-        $this->_ajax_hooks();
207
-        //other_page_hooks have to be early too.
208
-        $this->_do_other_page_hooks();
209
-        //This just allows us to have extending classes do something specific
210
-        // before the parent constructor runs _page_setup().
211
-        if (method_exists($this, '_before_page_setup')) {
212
-            $this->_before_page_setup();
213
-        }
214
-        //set up page dependencies
215
-        $this->_page_setup();
216
-    }
217
-
218
-
219
-
220
-    /**
221
-     * _init_page_props
222
-     * Child classes use to set at least the following properties:
223
-     * $page_slug.
224
-     * $page_label.
225
-     *
226
-     * @abstract
227
-     * @return void
228
-     */
229
-    abstract protected function _init_page_props();
230
-
231
-
232
-
233
-    /**
234
-     * _ajax_hooks
235
-     * child classes put all their add_action('wp_ajax_{name_of_hook}') hooks in here.
236
-     * Note: within the ajax callback methods.
237
-     *
238
-     * @abstract
239
-     * @return void
240
-     */
241
-    abstract protected function _ajax_hooks();
242
-
243
-
244
-
245
-    /**
246
-     * _define_page_props
247
-     * child classes define page properties in here.  Must include at least:
248
-     * $_admin_base_url = base_url for all admin pages
249
-     * $_admin_page_title = default admin_page_title for admin pages
250
-     * $_labels = array of default labels for various automatically generated elements:
251
-     *    array(
252
-     *        'buttons' => array(
253
-     *            'add' => esc_html__('label for add new button'),
254
-     *            'edit' => esc_html__('label for edit button'),
255
-     *            'delete' => esc_html__('label for delete button')
256
-     *            )
257
-     *        )
258
-     *
259
-     * @abstract
260
-     * @return void
261
-     */
262
-    abstract protected function _define_page_props();
263
-
264
-
265
-
266
-    /**
267
-     * _set_page_routes
268
-     * child classes use this to define the page routes for all subpages handled by the class.  Page routes are
269
-     * assigned to a action => method pairs in an array and to the $_page_routes property.  Each page route must also
270
-     * have a 'default' route. Here's the format
271
-     * $this->_page_routes = array(
272
-     *        'default' => array(
273
-     *            'func' => '_default_method_handling_route',
274
-     *            'args' => array('array','of','args'),
275
-     *            'noheader' => true, //add this in if this page route is processed before any headers are loaded (i.e.
276
-     *            ajax request, backend processing)
277
-     *            'headers_sent_route'=>'headers_route_reference', //add this if noheader=>true, and you want to load a
278
-     *            headers route after.  The string you enter here should match the defined route reference for a
279
-     *            headers sent route.
280
-     *            'capability' => 'route_capability', //indicate a string for minimum capability required to access
281
-     *            this route.
282
-     *            'obj_id' => 10 // if this route has an object id, then this can include it (used for capability
283
-     *            checks).
284
-     *        ),
285
-     *        'insert_item' => '_method_for_handling_insert_item' //this can be used if all we need to have is a
286
-     *        handling method.
287
-     *        )
288
-     * )
289
-     *
290
-     * @abstract
291
-     * @return void
292
-     */
293
-    abstract protected function _set_page_routes();
294
-
295
-
296
-
297
-    /**
298
-     * _set_page_config
299
-     * child classes use this to define the _page_config array for all subpages handled by the class. Each key in the
300
-     * array corresponds to the page_route for the loaded page. Format:
301
-     * $this->_page_config = array(
302
-     *        'default' => array(
303
-     *            'labels' => array(
304
-     *                'buttons' => array(
305
-     *                    'add' => esc_html__('label for adding item'),
306
-     *                    'edit' => esc_html__('label for editing item'),
307
-     *                    'delete' => esc_html__('label for deleting item')
308
-     *                ),
309
-     *                'publishbox' => esc_html__('Localized Title for Publish metabox', 'event_espresso')
310
-     *            ), //optional an array of custom labels for various automatically generated elements to use on the
311
-     *            page. If this isn't present then the defaults will be used as set for the $this->_labels in
312
-     *            _define_page_props() method
313
-     *            'nav' => array(
314
-     *                'label' => esc_html__('Label for Tab', 'event_espresso').
315
-     *                'url' => 'http://someurl', //automatically generated UNLESS you define
316
-     *                'css_class' => 'css-class', //automatically generated UNLESS you define
317
-     *                'order' => 10, //required to indicate tab position.
318
-     *                'persistent' => false //if you want the nav tab to ONLY display when the specific route is
319
-     *                displayed then add this parameter.
320
-     *            'list_table' => 'name_of_list_table' //string for list table class to be loaded for this admin_page.
321
-     *            'metaboxes' => array('metabox1', 'metabox2'), //if present this key indicates we want to load
322
-     *            metaboxes set for eventespresso admin pages.
323
-     *            'has_metaboxes' => true, //this boolean flag can simply be used to indicate if the route will have
324
-     *            metaboxes.  Typically this is used if the 'metaboxes' index is not used because metaboxes are added
325
-     *            later.  We just use this flag to make sure the necessary js gets enqueued on page load.
326
-     *            'has_help_popups' => false //defaults(true) //this boolean flag can simply be used to indicate if the
327
-     *            given route has help popups setup and if it does then we need to make sure thickbox is enqueued.
328
-     *            'columns' => array(4, 2), //this key triggers the setup of a page that uses columns (metaboxes).  The
329
-     *            array indicates the max number of columns (4) and the default number of columns on page load (2).
330
-     *            There is an option in the "screen_options" dropdown that is setup so users can pick what columns they
331
-     *            want to display.
332
-     *            'help_tabs' => array( //this is used for adding help tabs to a page
333
-     *                'tab_id' => array(
334
-     *                    'title' => 'tab_title',
335
-     *                    'filename' => 'name_of_file_containing_content', //this is the primary method for setting
336
-     *                    help tab content.  The fallback if it isn't present is to try a the callback.  Filename
337
-     *                    should match a file in the admin folder's "help_tabs" dir (ie..
338
-     *                    events/help_tabs/name_of_file_containing_content.help_tab.php)
339
-     *                    'callback' => 'callback_method_for_content', //if 'filename' isn't present then system will
340
-     *                    attempt to use the callback which should match the name of a method in the class
341
-     *                    ),
342
-     *                'tab2_id' => array(
343
-     *                    'title' => 'tab2 title',
344
-     *                    'filename' => 'file_name_2'
345
-     *                    'callback' => 'callback_method_for_content',
346
-     *                 ),
347
-     *            'help_sidebar' => 'callback_for_sidebar_content', //this is used for setting up the sidebar in the
348
-     *            help tab area on an admin page. @link
349
-     *            http://make.wordpress.org/core/2011/12/06/help-and-screen-api-changes-in-3-3/
350
-     *            'help_tour' => array(
351
-     *                'name_of_help_tour_class', //all help tours shoudl be a child class of EE_Help_Tour and located
352
-     *                in a folder for this admin page named "help_tours", a file name matching the key given here
353
-     *                (name_of_help_tour_class.class.php), and class matching key given here (name_of_help_tour_class)
354
-     *            ),
355
-     *            'require_nonce' => TRUE //this is used if you want to set a route to NOT require a nonce (default is
356
-     *            true if it isn't present).  To remove the requirement for a nonce check when this route is visited
357
-     *            just set
358
-     *            'require_nonce' to FALSE
359
-     *            )
360
-     * )
361
-     *
362
-     * @abstract
363
-     * @return void
364
-     */
365
-    abstract protected function _set_page_config();
366
-
367
-
368
-
369
-
370
-
371
-    /** end sample help_tour methods **/
372
-    /**
373
-     * _add_screen_options
374
-     * Child classes can add any extra wp_screen_options within this method using built-in WP functions/methods for
375
-     * doing so. Note child classes can also define _add_screen_options_($this->_current_view) to limit screen options
376
-     * to a particular view.
377
-     *
378
-     * @link   http://chrismarslender.com/wp-tutorials/wordpress-screen-options-tutorial/
379
-     *         see also WP_Screen object documents...
380
-     * @link   http://codex.wordpress.org/Class_Reference/WP_Screen
381
-     * @abstract
382
-     * @return void
383
-     */
384
-    abstract protected function _add_screen_options();
385
-
386
-
387
-
388
-    /**
389
-     * _add_feature_pointers
390
-     * Child classes should use this method for implementing any "feature pointers" (using built-in WP styling js).
391
-     * Note child classes can also define _add_feature_pointers_($this->_current_view) to limit screen options to a
392
-     * particular view. Note: this is just a placeholder for now.  Implementation will come down the road See:
393
-     * WP_Internal_Pointers class in wp-admin/includes/template.php for example (its a final class so can't be
394
-     * extended) also see:
395
-     *
396
-     * @link   http://eamann.com/tech/wordpress-portland/
397
-     * @abstract
398
-     * @return void
399
-     */
400
-    abstract protected function _add_feature_pointers();
401
-
402
-
403
-
404
-    /**
405
-     * load_scripts_styles
406
-     * child classes put their wp_enqueue_script and wp_enqueue_style hooks in here for anything they need loaded for
407
-     * their pages/subpages.  Note this is for all pages/subpages of the system.  You can also load only specific
408
-     * scripts/styles per view by putting them in a dynamic function in this format
409
-     * (load_scripts_styles_{$this->_current_view}) which matches your page route (action request arg)
410
-     *
411
-     * @abstract
412
-     * @return void
413
-     */
414
-    abstract public function load_scripts_styles();
415
-
416
-
417
-
418
-    /**
419
-     * admin_init
420
-     * Anything that should be set/executed at 'admin_init' WP hook runtime should be put in here.  This will apply to
421
-     * all pages/views loaded by child class.
422
-     *
423
-     * @abstract
424
-     * @return void
425
-     */
426
-    abstract public function admin_init();
427
-
428
-
429
-
430
-    /**
431
-     * admin_notices
432
-     * Anything triggered by the 'admin_notices' WP hook should be put in here.  This particular method will apply to
433
-     * all pages/views loaded by child class.
434
-     *
435
-     * @abstract
436
-     * @return void
437
-     */
438
-    abstract public function admin_notices();
439
-
440
-
441
-
442
-    /**
443
-     * admin_footer_scripts
444
-     * Anything triggered by the 'admin_print_footer_scripts' WP hook should be put in here. This particular method
445
-     * will apply to all pages/views loaded by child class.
446
-     *
447
-     * @return void
448
-     */
449
-    abstract public function admin_footer_scripts();
450
-
451
-
452
-
453
-    /**
454
-     * admin_footer
455
-     * anything triggered by the 'admin_footer' WP action hook should be added to here. This particular method will
456
-     * apply to all pages/views loaded by child class.
457
-     *
458
-     * @return void
459
-     */
460
-    public function admin_footer()
461
-    {
462
-    }
463
-
464
-
465
-
466
-    /**
467
-     * _global_ajax_hooks
468
-     * all global add_action('wp_ajax_{name_of_hook}') hooks in here.
469
-     * Note: within the ajax callback methods.
470
-     *
471
-     * @abstract
472
-     * @return void
473
-     */
474
-    protected function _global_ajax_hooks()
475
-    {
476
-        //for lazy loading of metabox content
477
-        add_action('wp_ajax_espresso-ajax-content', array($this, 'ajax_metabox_content'), 10);
478
-    }
479
-
480
-
481
-
482
-    public function ajax_metabox_content()
483
-    {
484
-        $contentid = isset($this->_req_data['contentid']) ? $this->_req_data['contentid'] : '';
485
-        $url       = isset($this->_req_data['contenturl']) ? $this->_req_data['contenturl'] : '';
486
-        self::cached_rss_display($contentid, $url);
487
-        wp_die();
488
-    }
489
-
490
-
491
-
492
-    /**
493
-     * _page_setup
494
-     * Makes sure any things that need to be loaded early get handled.  We also escape early here if the page requested
495
-     * doesn't match the object.
496
-     *
497
-     * @final
498
-     * @return void
499
-     * @throws EE_Error
500
-     * @throws InvalidArgumentException
501
-     * @throws ReflectionException
502
-     * @throws InvalidDataTypeException
503
-     * @throws InvalidInterfaceException
504
-     */
505
-    final protected function _page_setup()
506
-    {
507
-        //requires?
508
-        //admin_init stuff - global - we're setting this REALLY early so if EE_Admin pages have to hook into other WP pages they can.  But keep in mind, not everything is available from the EE_Admin Page object at this point.
509
-        add_action('admin_init', array($this, 'admin_init_global'), 5);
510
-        //next verify if we need to load anything...
511
-        $this->_current_page = ! empty($_GET['page']) ? sanitize_key($_GET['page']) : '';
512
-        $this->page_folder   = strtolower(
513
-            str_replace(array('_Admin_Page', 'Extend_'), '', get_class($this))
514
-        );
515
-        global $ee_menu_slugs;
516
-        $ee_menu_slugs = (array)$ee_menu_slugs;
517
-        if (! defined('DOING_AJAX') && (! $this->_current_page || ! isset($ee_menu_slugs[$this->_current_page]))) {
518
-            return;
519
-        }
520
-        // becuz WP List tables have two duplicate select inputs for choosing bulk actions, we need to copy the action from the second to the first
521
-        if (isset($this->_req_data['action2']) && $this->_req_data['action'] === '-1') {
522
-            $this->_req_data['action'] = ! empty($this->_req_data['action2']) && $this->_req_data['action2'] !== '-1'
523
-                ? $this->_req_data['action2']
524
-                : $this->_req_data['action'];
525
-        }
526
-        // then set blank or -1 action values to 'default'
527
-        $this->_req_action = isset($this->_req_data['action'])
528
-                             && ! empty($this->_req_data['action'])
529
-                             && $this->_req_data['action'] !== '-1'
530
-            ? sanitize_key($this->_req_data['action'])
531
-            : 'default';
532
-        // if action is 'default' after the above BUT we have  'route' var set, then let's use the route as the action.
533
-        //  This covers cases where we're coming in from a list table that isn't on the default route.
534
-        $this->_req_action = $this->_req_action === 'default' && isset($this->_req_data['route'])
535
-            ? $this->_req_data['route'] : $this->_req_action;
536
-        //however if we are doing_ajax and we've got a 'route' set then that's what the req_action will be
537
-        $this->_req_action   = defined('DOING_AJAX') && isset($this->_req_data['route'])
538
-            ? $this->_req_data['route']
539
-            : $this->_req_action;
540
-        $this->_current_view = $this->_req_action;
541
-        $this->_req_nonce    = $this->_req_action . '_nonce';
542
-        $this->_define_page_props();
543
-        $this->_current_page_view_url = add_query_arg(
544
-            array('page' => $this->_current_page, 'action' => $this->_current_view),
545
-            $this->_admin_base_url
546
-        );
547
-        //default things
548
-        $this->_default_espresso_metaboxes = array(
549
-            '_espresso_news_post_box',
550
-            '_espresso_links_post_box',
551
-            '_espresso_ratings_request',
552
-            '_espresso_sponsors_post_box',
553
-        );
554
-        //set page configs
555
-        $this->_set_page_routes();
556
-        $this->_set_page_config();
557
-        //let's include any referrer data in our default_query_args for this route for "stickiness".
558
-        if (isset($this->_req_data['wp_referer'])) {
559
-            $this->_default_route_query_args['wp_referer'] = $this->_req_data['wp_referer'];
560
-        }
561
-        //for caffeinated and other extended functionality.
562
-        //  If there is a _extend_page_config method
563
-        // then let's run that to modify the all the various page configuration arrays
564
-        if (method_exists($this, '_extend_page_config')) {
565
-            $this->_extend_page_config();
566
-        }
567
-        //for CPT and other extended functionality.
568
-        // If there is an _extend_page_config_for_cpt
569
-        // then let's run that to modify all the various page configuration arrays.
570
-        if (method_exists($this, '_extend_page_config_for_cpt')) {
571
-            $this->_extend_page_config_for_cpt();
572
-        }
573
-        //filter routes and page_config so addons can add their stuff. Filtering done per class
574
-        $this->_page_routes = apply_filters(
575
-            'FHEE__' . get_class($this) . '__page_setup__page_routes',
576
-            $this->_page_routes,
577
-            $this
578
-        );
579
-        $this->_page_config = apply_filters(
580
-            'FHEE__' . get_class($this) . '__page_setup__page_config',
581
-            $this->_page_config,
582
-            $this
583
-        );
584
-        //if AHEE__EE_Admin_Page__route_admin_request_$this->_current_view method is present
585
-        // then we call it hooked into the AHEE__EE_Admin_Page__route_admin_request action
586
-        if (
587
-            method_exists($this, 'AHEE__EE_Admin_Page__route_admin_request_' . $this->_current_view)
588
-        ) {
589
-            add_action(
590
-                'AHEE__EE_Admin_Page__route_admin_request',
591
-                array($this, 'AHEE__EE_Admin_Page__route_admin_request_' . $this->_current_view),
592
-                10,
593
-                2
594
-            );
595
-        }
596
-        //next route only if routing enabled
597
-        if ($this->_routing && ! defined('DOING_AJAX')) {
598
-            $this->_verify_routes();
599
-            //next let's just check user_access and kill if no access
600
-            $this->check_user_access();
601
-            if ($this->_is_UI_request) {
602
-                //admin_init stuff - global, all views for this page class, specific view
603
-                add_action('admin_init', array($this, 'admin_init'), 10);
604
-                if (method_exists($this, 'admin_init_' . $this->_current_view)) {
605
-                    add_action('admin_init', array($this, 'admin_init_' . $this->_current_view), 15);
606
-                }
607
-            } else {
608
-                //hijack regular WP loading and route admin request immediately
609
-                @ini_set('memory_limit', apply_filters('admin_memory_limit', WP_MAX_MEMORY_LIMIT));
610
-                $this->route_admin_request();
611
-            }
612
-        }
613
-    }
614
-
615
-
616
-
617
-    /**
618
-     * Provides a way for related child admin pages to load stuff on the loaded admin page.
619
-     *
620
-     * @return void
621
-     * @throws ReflectionException
622
-     * @throws EE_Error
623
-     */
624
-    private function _do_other_page_hooks()
625
-    {
626
-        $registered_pages = apply_filters('FHEE_do_other_page_hooks_' . $this->page_slug, array());
627
-        foreach ($registered_pages as $page) {
628
-            //now let's setup the file name and class that should be present
629
-            $classname = str_replace('.class.php', '', $page);
630
-            //autoloaders should take care of loading file
631
-            if (! class_exists($classname)) {
632
-                $error_msg[] = sprintf(
633
-                    esc_html__(
634
-                        'Something went wrong with loading the %s admin hooks page.',
635
-                        'event_espresso'
636
-                    ),
637
-                    $page
638
-                );
639
-                $error_msg[] = $error_msg[0]
640
-                               . "\r\n"
641
-                               . sprintf(
642
-                                   esc_html__(
643
-                                       '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',
644
-                                       'event_espresso'
645
-                                   ),
646
-                                   $page,
647
-                                   '<br />',
648
-                                   '<strong>' . $classname . '</strong>'
649
-                               );
650
-                throw new EE_Error(implode('||', $error_msg));
651
-            }
652
-            $a = new ReflectionClass($classname);
653
-            //notice we are passing the instance of this class to the hook object.
654
-            $hookobj[] = $a->newInstance($this);
655
-        }
656
-    }
657
-
658
-
659
-
660
-    public function load_page_dependencies()
661
-    {
662
-        try {
663
-            $this->_load_page_dependencies();
664
-        } catch (EE_Error $e) {
665
-            $e->get_error();
666
-        }
667
-    }
668
-
669
-
670
-
671
-    /**
672
-     * load_page_dependencies
673
-     * loads things specific to this page class when its loaded.  Really helps with efficiency.
674
-     *
675
-     * @return void
676
-     * @throws DomainException
677
-     * @throws EE_Error
678
-     * @throws InvalidArgumentException
679
-     * @throws InvalidDataTypeException
680
-     * @throws InvalidInterfaceException
681
-     * @throws ReflectionException
682
-     */
683
-    protected function _load_page_dependencies()
684
-    {
685
-        //let's set the current_screen and screen options to override what WP set
686
-        $this->_current_screen = get_current_screen();
687
-        //load admin_notices - global, page class, and view specific
688
-        add_action('admin_notices', array($this, 'admin_notices_global'), 5);
689
-        add_action('admin_notices', array($this, 'admin_notices'), 10);
690
-        if (method_exists($this, 'admin_notices_' . $this->_current_view)) {
691
-            add_action('admin_notices', array($this, 'admin_notices_' . $this->_current_view), 15);
692
-        }
693
-        //load network admin_notices - global, page class, and view specific
694
-        add_action('network_admin_notices', array($this, 'network_admin_notices_global'), 5);
695
-        if (method_exists($this, 'network_admin_notices_' . $this->_current_view)) {
696
-            add_action('network_admin_notices', array($this, 'network_admin_notices_' . $this->_current_view));
697
-        }
698
-        //this will save any per_page screen options if they are present
699
-        $this->_set_per_page_screen_options();
700
-        //setup list table properties
701
-        $this->_set_list_table();
702
-        // child classes can "register" a metabox to be automatically handled via the _page_config array property.
703
-        // However in some cases the metaboxes will need to be added within a route handling callback.
704
-        $this->_add_registered_meta_boxes();
705
-        $this->_add_screen_columns();
706
-        //add screen options - global, page child class, and view specific
707
-        $this->_add_global_screen_options();
708
-        $this->_add_screen_options();
709
-        $add_screen_options  = "_add_screen_options_{$this->_current_view}";
710
-        if (method_exists($this, $add_screen_options )) {
711
-            $this->{$add_screen_options}();
712
-        }
713
-        //add help tab(s) and tours- set via page_config and qtips.
714
-        $this->_add_help_tour();
715
-        $this->_add_help_tabs();
716
-        $this->_add_qtips();
717
-        //add feature_pointers - global, page child class, and view specific
718
-        $this->_add_feature_pointers();
719
-        $this->_add_global_feature_pointers();
720
-        $add_feature_pointer = "_add_feature_pointer_{$this->_current_view}";
721
-        if (method_exists($this, $add_feature_pointer )) {
722
-            $this->{$add_feature_pointer}();
723
-        }
724
-        //enqueue scripts/styles - global, page class, and view specific
725
-        add_action('admin_enqueue_scripts', array($this, 'load_global_scripts_styles'), 5);
726
-        add_action('admin_enqueue_scripts', array($this, 'load_scripts_styles'), 10);
727
-        if (method_exists($this, "load_scripts_styles_{$this->_current_view}")) {
728
-            add_action('admin_enqueue_scripts', array($this, "load_scripts_styles_{$this->_current_view}"), 15);
729
-        }
730
-        add_action('admin_enqueue_scripts', array($this, 'admin_footer_scripts_eei18n_js_strings'), 100);
731
-        // admin_print_footer_scripts - global, page child class, and view specific.
732
-        // NOTE, despite the name, whenever possible, scripts should NOT be loaded using this.
733
-        // In most cases that's doing_it_wrong().  But adding hidden container elements etc.
734
-        // is a good use case. Notice the late priority we're giving these
735
-        add_action('admin_print_footer_scripts', array($this, 'admin_footer_scripts_global'), 99);
736
-        add_action('admin_print_footer_scripts', array($this, 'admin_footer_scripts'), 100);
737
-        if (method_exists($this, "admin_footer_scripts_{$this->_current_view}")) {
738
-            add_action('admin_print_footer_scripts', array($this, "admin_footer_scripts_{$this->_current_view}"), 101);
739
-        }
740
-        //admin footer scripts
741
-        add_action('admin_footer', array($this, 'admin_footer_global'), 99);
742
-        add_action('admin_footer', array($this, 'admin_footer'), 100);
743
-        if (method_exists($this, "admin_footer_{$this->_current_view}")) {
744
-            add_action('admin_footer', array($this, "admin_footer_{$this->_current_view}"), 101);
745
-        }
746
-        do_action('FHEE__EE_Admin_Page___load_page_dependencies__after_load', $this->page_slug);
747
-        //targeted hook
748
-        do_action(
749
-            "FHEE__EE_Admin_Page___load_page_dependencies__after_load__{$this->page_slug}__{$this->_req_action}"
750
-
751
-        );
752
-    }
753
-
754
-
755
-
756
-    /**
757
-     * _set_defaults
758
-     * This sets some global defaults for class properties.
759
-     */
760
-    private function _set_defaults()
761
-    {
762
-        $this->_current_screen = $this->_admin_page_title = $this->_req_action = $this->_req_nonce = null;
763
-        $this->_event = $this->_template_path = $this->_column_template_path = null;
764
-        $this->_nav_tabs = $this->_views = $this->_page_routes = array();
765
-        $this->_page_config = $this->_default_route_query_args = array();
766
-        $this->_default_nav_tab_name = 'overview';
767
-        //init template args
768
-        $this->_template_args = array(
769
-            'admin_page_header'  => '',
770
-            'admin_page_content' => '',
771
-            'post_body_content'  => '',
772
-            'before_list_table'  => '',
773
-            'after_list_table'   => '',
774
-        );
775
-    }
776
-
777
-
778
-
779
-    /**
780
-     * route_admin_request
781
-     *
782
-     * @see    _route_admin_request()
783
-     * @return exception|void error
784
-     * @throws InvalidArgumentException
785
-     * @throws InvalidInterfaceException
786
-     * @throws InvalidDataTypeException
787
-     * @throws EE_Error
788
-     * @throws ReflectionException
789
-     */
790
-    public function route_admin_request()
791
-    {
792
-        try {
793
-            $this->_route_admin_request();
794
-        } catch (EE_Error $e) {
795
-            $e->get_error();
796
-        }
797
-    }
798
-
799
-
800
-
801
-    public function set_wp_page_slug($wp_page_slug)
802
-    {
803
-        $this->_wp_page_slug = $wp_page_slug;
804
-        //if in network admin then we need to append "-network" to the page slug. Why? Because that's how WP rolls...
805
-        if (is_network_admin()) {
806
-            $this->_wp_page_slug .= '-network';
807
-        }
808
-    }
809
-
810
-
811
-
812
-    /**
813
-     * _verify_routes
814
-     * All this method does is verify the incoming request and make sure that routes exist for it.  We do this early so
815
-     * we know if we need to drop out.
816
-     *
817
-     * @return bool
818
-     * @throws EE_Error
819
-     */
820
-    protected function _verify_routes()
821
-    {
822
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
823
-        if (! $this->_current_page && ! defined('DOING_AJAX')) {
824
-            return false;
825
-        }
826
-        $this->_route = false;
827
-        // check that the page_routes array is not empty
828
-        if (empty($this->_page_routes)) {
829
-            // user error msg
830
-            $error_msg = sprintf(
831
-                esc_html__('No page routes have been set for the %s admin page.', 'event_espresso'),
832
-                $this->_admin_page_title
833
-            );
834
-            // developer error msg
835
-            $error_msg .= '||' . $error_msg . esc_html__(
836
-                ' Make sure the "set_page_routes()" method exists, and is setting the "_page_routes" array properly.',
837
-                'event_espresso'
838
-            );
839
-            throw new EE_Error($error_msg);
840
-        }
841
-        // and that the requested page route exists
842
-        if (array_key_exists($this->_req_action, $this->_page_routes)) {
843
-            $this->_route        = $this->_page_routes[$this->_req_action];
844
-            $this->_route_config = isset($this->_page_config[$this->_req_action])
845
-                ? $this->_page_config[$this->_req_action] : array();
846
-        } else {
847
-            // user error msg
848
-            $error_msg = sprintf(
849
-                esc_html__(
850
-                        'The requested page route does not exist for the %s admin page.',
851
-                        'event_espresso'
852
-                ),
853
-                $this->_admin_page_title
854
-            );
855
-            // developer error msg
856
-            $error_msg .= '||' . $error_msg . sprintf(
857
-                    esc_html__(
858
-                        ' Create a key in the "_page_routes" array named "%s" and set its value to the appropriate method.',
859
-                        'event_espresso'
860
-                    ),
861
-                    $this->_req_action
862
-                );
863
-            throw new EE_Error($error_msg);
864
-        }
865
-        // and that a default route exists
866
-        if (! array_key_exists('default', $this->_page_routes)) {
867
-            // user error msg
868
-            $error_msg = sprintf(
869
-                esc_html__(
870
-                        'A default page route has not been set for the % admin page.',
871
-                        'event_espresso'
872
-                ),
873
-                $this->_admin_page_title
874
-            );
875
-            // developer error msg
876
-            $error_msg .= '||' . $error_msg . esc_html__(
877
-                ' Create a key in the "_page_routes" array named "default" and set its value to your default page method.',
878
-                'event_espresso'
879
-            );
880
-            throw new EE_Error($error_msg);
881
-        }
882
-        //first lets' catch if the UI request has EVER been set.
883
-        if ($this->_is_UI_request === null) {
884
-            //lets set if this is a UI request or not.
885
-            $this->_is_UI_request = ! isset($this->_req_data['noheader']) || $this->_req_data['noheader'] !== true;
886
-            //wait a minute... we might have a noheader in the route array
887
-            $this->_is_UI_request = is_array($this->_route)
888
-                                    && isset($this->_route['noheader'])
889
-                                    && $this->_route['noheader'] ? false : $this->_is_UI_request;
890
-        }
891
-        $this->_set_current_labels();
892
-        return true;
893
-    }
894
-
895
-
896
-
897
-    /**
898
-     * this method simply verifies a given route and makes sure its an actual route available for the loaded page
899
-     *
900
-     * @param  string $route the route name we're verifying
901
-     * @return mixed (bool|Exception)      we'll throw an exception if this isn't a valid route.
902
-     * @throws EE_Error
903
-     */
904
-    protected function _verify_route($route)
905
-    {
906
-        if (array_key_exists($this->_req_action, $this->_page_routes)) {
907
-            return true;
908
-        }
909
-        // user error msg
910
-        $error_msg = sprintf(
911
-            esc_html__('The given page route does not exist for the %s admin page.', 'event_espresso'),
912
-            $this->_admin_page_title
913
-        );
914
-        // developer error msg
915
-        $error_msg .= '||' . $error_msg . sprintf(
916
-                esc_html__(
917
-                    ' Check the route you are using in your method (%s) and make sure it matches a route set in your "_page_routes" array property',
918
-                    'event_espresso'
919
-                ),
920
-                $route
921
-            );
922
-        throw new EE_Error($error_msg);
923
-    }
924
-
925
-
926
-
927
-    /**
928
-     * perform nonce verification
929
-     * This method has be encapsulated here so that any ajax requests that bypass normal routes can verify their nonces
930
-     * using this method (and save retyping!)
931
-     *
932
-     * @param  string $nonce     The nonce sent
933
-     * @param  string $nonce_ref The nonce reference string (name0)
934
-     * @return void
935
-     * @throws EE_Error
936
-     */
937
-    protected function _verify_nonce($nonce, $nonce_ref)
938
-    {
939
-        // verify nonce against expected value
940
-        if (! wp_verify_nonce($nonce, $nonce_ref)) {
941
-            // these are not the droids you are looking for !!!
942
-            $msg = sprintf(
943
-                esc_html__('%sNonce Fail.%s', 'event_espresso'),
944
-                '<a href="http://www.youtube.com/watch?v=56_S0WeTkzs">',
945
-                '</a>'
946
-            );
947
-            if (WP_DEBUG) {
948
-                $msg .= "\n  " . sprintf(
949
-                        esc_html__(
950
-                            'In order to dynamically generate nonces for your actions, use the %s::add_query_args_and_nonce() method. May the Nonce be with you!',
951
-                            'event_espresso'
952
-                        ),
953
-                        __CLASS__
954
-                    );
955
-            }
956
-            if (! defined('DOING_AJAX')) {
957
-                wp_die($msg);
958
-            } else {
959
-                EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
960
-                $this->_return_json();
961
-            }
962
-        }
963
-    }
964
-
965
-
966
-
967
-    /**
968
-     * _route_admin_request()
969
-     * Meat and potatoes of the class.  Basically, this dude checks out what's being requested and sees if theres are
970
-     * some doodads to work the magic and handle the flingjangy. Translation:  Checks if the requested action is listed
971
-     * in the page routes and then will try to load the corresponding method.
972
-     *
973
-     * @return void
974
-     * @throws EE_Error
975
-     * @throws InvalidArgumentException
976
-     * @throws InvalidDataTypeException
977
-     * @throws InvalidInterfaceException
978
-     * @throws ReflectionException
979
-     */
980
-    protected function _route_admin_request()
981
-    {
982
-        if (! $this->_is_UI_request) {
983
-            $this->_verify_routes();
984
-        }
985
-        $nonce_check = isset($this->_route_config['require_nonce'])
986
-            ? $this->_route_config['require_nonce']
987
-            : true;
988
-        if ($this->_req_action !== 'default' && $nonce_check) {
989
-            // set nonce from post data
990
-            $nonce = isset($this->_req_data[$this->_req_nonce])
991
-                ? sanitize_text_field($this->_req_data[$this->_req_nonce])
992
-                : '';
993
-            $this->_verify_nonce($nonce, $this->_req_nonce);
994
-        }
995
-        //set the nav_tabs array but ONLY if this is  UI_request
996
-        if ($this->_is_UI_request) {
997
-            $this->_set_nav_tabs();
998
-        }
999
-        // grab callback function
1000
-        $func = is_array($this->_route) ? $this->_route['func'] : $this->_route;
1001
-        // check if callback has args
1002
-        $args      = is_array($this->_route) && isset($this->_route['args']) ? $this->_route['args'] : array();
1003
-        $error_msg = '';
1004
-        // action right before calling route
1005
-        // (hook is something like 'AHEE__Registrations_Admin_Page__route_admin_request')
1006
-        if (! did_action('AHEE__EE_Admin_Page__route_admin_request')) {
1007
-            do_action('AHEE__EE_Admin_Page__route_admin_request', $this->_current_view, $this);
1008
-        }
1009
-        // right before calling the route, let's remove _wp_http_referer from the
1010
-        // $_SERVER[REQUEST_URI] global (its now in _req_data for route processing).
1011
-        $_SERVER['REQUEST_URI'] = remove_query_arg(
1012
-                '_wp_http_referer',
1013
-                wp_unslash($_SERVER['REQUEST_URI'])
1014
-        );
1015
-        if (! empty($func)) {
1016
-            if (is_array($func)) {
1017
-                list($class, $method) = $func;
1018
-            } elseif (strpos($func, '::') !== false) {
1019
-                list($class, $method) = explode('::', $func);
1020
-            } else {
1021
-                $class  = $this;
1022
-                $method = $func;
1023
-            }
1024
-            if (! (is_object($class) && $class === $this)) {
1025
-                // send along this admin page object for access by addons.
1026
-                $args['admin_page_object'] = $this;
1027
-            }
1028
-            if (
1029
-                //is it a method on a class that doesn't work?
1030
-                (
1031
-                    (
1032
-                        method_exists($class, $method)
1033
-                        && call_user_func_array(array($class, $method), $args) === false
1034
-                    )
1035
-                    && (
1036
-                        //is it a standalone function that doesn't work?
1037
-                        function_exists($method)
1038
-                        && call_user_func_array(
1039
-                            $func,
1040
-                            array_merge(array('admin_page_object' => $this), $args)
1041
-                           ) === false
1042
-                    )
1043
-                )
1044
-                || (
1045
-                    //is it neither a class method NOR a standalone function?
1046
-                    ! method_exists($class, $method)
1047
-                    && ! function_exists($method)
1048
-                )
1049
-            ) {
1050
-                // user error msg
1051
-                $error_msg = esc_html__(
1052
-                    'An error occurred. The  requested page route could not be found.',
1053
-                    'event_espresso'
1054
-                );
1055
-                // developer error msg
1056
-                $error_msg .= '||';
1057
-                $error_msg .= sprintf(
1058
-                    esc_html__(
1059
-                        'Page route "%s" could not be called. Check that the spelling for method names and actions in the "_page_routes" array are all correct.',
1060
-                        'event_espresso'
1061
-                    ),
1062
-                    $method
1063
-                );
1064
-            }
1065
-            if (! empty($error_msg)) {
1066
-                throw new EE_Error($error_msg);
1067
-            }
1068
-        }
1069
-        // if we've routed and this route has a no headers route AND a sent_headers_route,
1070
-        // then we need to reset the routing properties to the new route.
1071
-        //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.
1072
-        if ($this->_is_UI_request === false
1073
-            && is_array($this->_route)
1074
-            && ! empty($this->_route['headers_sent_route'])
1075
-        ) {
1076
-            $this->_reset_routing_properties($this->_route['headers_sent_route']);
1077
-        }
1078
-    }
1079
-
1080
-
1081
-
1082
-    /**
1083
-     * This method just allows the resetting of page properties in the case where a no headers
1084
-     * route redirects to a headers route in its route config.
1085
-     *
1086
-     * @since   4.3.0
1087
-     * @param  string $new_route New (non header) route to redirect to.
1088
-     * @return   void
1089
-     * @throws ReflectionException
1090
-     * @throws InvalidArgumentException
1091
-     * @throws InvalidInterfaceException
1092
-     * @throws InvalidDataTypeException
1093
-     * @throws EE_Error
1094
-     */
1095
-    protected function _reset_routing_properties($new_route)
1096
-    {
1097
-        $this->_is_UI_request = true;
1098
-        //now we set the current route to whatever the headers_sent_route is set at
1099
-        $this->_req_data['action'] = $new_route;
1100
-        //rerun page setup
1101
-        $this->_page_setup();
1102
-    }
1103
-
1104
-
1105
-
1106
-    /**
1107
-     * _add_query_arg
1108
-     * adds nonce to array of arguments then calls WP add_query_arg function
1109
-     *(internally just uses EEH_URL's function with the same name)
1110
-     *
1111
-     * @param array  $args
1112
-     * @param string $url
1113
-     * @param bool   $sticky                  if true, then the existing Request params will be appended to the
1114
-     *                                        generated url in an associative array indexed by the key 'wp_referer';
1115
-     *                                        Example usage: If the current page is:
1116
-     *                                        http://mydomain.com/wp-admin/admin.php?page=espresso_registrations
1117
-     *                                        &action=default&event_id=20&month_range=March%202015
1118
-     *                                        &_wpnonce=5467821
1119
-     *                                        and you call:
1120
-     *                                        EE_Admin_Page::add_query_args_and_nonce(
1121
-     *                                        array(
1122
-     *                                        'action' => 'resend_something',
1123
-     *                                        'page=>espresso_registrations'
1124
-     *                                        ),
1125
-     *                                        $some_url,
1126
-     *                                        true
1127
-     *                                        );
1128
-     *                                        It will produce a url in this structure:
1129
-     *                                        http://{$some_url}/?page=espresso_registrations&action=resend_something
1130
-     *                                        &wp_referer[action]=default&wp_referer[event_id]=20&wpreferer[
1131
-     *                                        month_range]=March%202015
1132
-     * @param   bool $exclude_nonce           If true, the the nonce will be excluded from the generated nonce.
1133
-     * @return string
1134
-     */
1135
-    public static function add_query_args_and_nonce(
1136
-        $args = array(),
1137
-        $url = false,
1138
-        $sticky = false,
1139
-        $exclude_nonce = false
1140
-    ) {
1141
-        //if there is a _wp_http_referer include the values from the request but only if sticky = true
1142
-        if ($sticky) {
1143
-            $request = $_REQUEST;
1144
-            unset($request['_wp_http_referer']);
1145
-            unset($request['wp_referer']);
1146
-            foreach ($request as $key => $value) {
1147
-                //do not add nonces
1148
-                if (strpos($key, 'nonce') !== false) {
1149
-                    continue;
1150
-                }
1151
-                $args['wp_referer[' . $key . ']'] = $value;
1152
-            }
1153
-        }
1154
-        return EEH_URL::add_query_args_and_nonce($args, $url, $exclude_nonce);
1155
-    }
1156
-
1157
-
1158
-
1159
-    /**
1160
-     * This returns a generated link that will load the related help tab.
1161
-     *
1162
-     * @param  string $help_tab_id the id for the connected help tab
1163
-     * @param  string $icon_style  (optional) include css class for the style you want to use for the help icon.
1164
-     * @param  string $help_text   (optional) send help text you want to use for the link if default not to be used
1165
-     * @uses EEH_Template::get_help_tab_link()
1166
-     * @return string              generated link
1167
-     */
1168
-    protected function _get_help_tab_link($help_tab_id, $icon_style = '', $help_text = '')
1169
-    {
1170
-        return EEH_Template::get_help_tab_link(
1171
-            $help_tab_id,
1172
-            $this->page_slug,
1173
-            $this->_req_action,
1174
-            $icon_style,
1175
-            $help_text
1176
-        );
1177
-    }
1178
-
1179
-
1180
-
1181
-    /**
1182
-     * _add_help_tabs
1183
-     * Note child classes define their help tabs within the page_config array.
1184
-     *
1185
-     * @link   http://codex.wordpress.org/Function_Reference/add_help_tab
1186
-     * @return void
1187
-     * @throws DomainException
1188
-     * @throws EE_Error
1189
-     */
1190
-    protected function _add_help_tabs()
1191
-    {
1192
-        $tour_buttons = '';
1193
-        if (isset($this->_page_config[$this->_req_action])) {
1194
-            $config = $this->_page_config[$this->_req_action];
1195
-            //is there a help tour for the current route?  if there is let's setup the tour buttons
1196
-            if (isset($this->_help_tour[$this->_req_action])) {
1197
-                $tb           = array();
1198
-                $tour_buttons = '<div class="ee-abs-container"><div class="ee-help-tour-restart-buttons">';
1199
-                foreach ($this->_help_tour['tours'] as $tour) {
1200
-                    //if this is the end tour then we don't need to setup a button
1201
-                    if ($tour instanceof EE_Help_Tour_final_stop || ! $tour instanceof EE_Help_Tour) {
1202
-                        continue;
1203
-                    }
1204
-                    $tb[] = '<button id="trigger-tour-'
1205
-                            . $tour->get_slug()
1206
-                            . '" class="button-primary trigger-ee-help-tour">'
1207
-                            . $tour->get_label()
1208
-                            . '</button>';
1209
-                }
1210
-                $tour_buttons .= implode('<br />', $tb);
1211
-                $tour_buttons .= '</div></div>';
1212
-            }
1213
-            // let's see if there is a help_sidebar set for the current route and we'll set that up for usage as well.
1214
-            if (is_array($config) && isset($config['help_sidebar'])) {
1215
-                //check that the callback given is valid
1216
-                if (! method_exists($this, $config['help_sidebar'])) {
1217
-                    throw new EE_Error(
1218
-                        sprintf(
1219
-                            esc_html__(
1220
-                                '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',
1221
-                                'event_espresso'
1222
-                            ),
1223
-                            $config['help_sidebar'],
1224
-                            get_class($this)
1225
-                        )
1226
-                    );
1227
-                }
1228
-                $content = apply_filters(
1229
-                    'FHEE__' . get_class($this) . '__add_help_tabs__help_sidebar',
1230
-                    $this->{$config['help_sidebar']}()
1231
-                );
1232
-                $content .= $tour_buttons; //add help tour buttons.
1233
-                //do we have any help tours setup?  Cause if we do we want to add the buttons
1234
-                $this->_current_screen->set_help_sidebar($content);
1235
-            }
1236
-            //if we DON'T have config help sidebar and there ARE tour buttons then we'll just add the tour buttons to the sidebar.
1237
-            if (! isset($config['help_sidebar']) && ! empty($tour_buttons)) {
1238
-                $this->_current_screen->set_help_sidebar($tour_buttons);
1239
-            }
1240
-            //handle if no help_tabs are set so the sidebar will still show for the help tour buttons
1241
-            if (! isset($config['help_tabs']) && ! empty($tour_buttons)) {
1242
-                $_ht['id']      = $this->page_slug;
1243
-                $_ht['title']   = esc_html__('Help Tours', 'event_espresso');
1244
-                $_ht['content'] = '<p>' . esc_html__(
1245
-                        'The buttons to the right allow you to start/restart any help tours available for this page',
1246
-                        'event_espresso'
1247
-                    ) . '</p>';
1248
-                $this->_current_screen->add_help_tab($_ht);
1249
-            }
1250
-            if (! isset($config['help_tabs'])) {
1251
-                return;
1252
-            } //no help tabs for this route
1253
-            foreach ((array)$config['help_tabs'] as $tab_id => $cfg) {
1254
-                //we're here so there ARE help tabs!
1255
-                //make sure we've got what we need
1256
-                if (! isset($cfg['title'])) {
1257
-                    throw new EE_Error(
1258
-                        esc_html__(
1259
-                            'The _page_config array is not set up properly for help tabs.  It is missing a title',
1260
-                            'event_espresso'
1261
-                        )
1262
-                    );
1263
-                }
1264
-                if (! isset($cfg['filename']) && ! isset($cfg['callback']) && ! isset($cfg['content'])) {
1265
-                    throw new EE_Error(
1266
-                        esc_html__(
1267
-                            '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',
1268
-                            'event_espresso'
1269
-                        )
1270
-                    );
1271
-                }
1272
-                //first priority goes to content.
1273
-                if (! empty($cfg['content'])) {
1274
-                    $content = ! empty($cfg['content']) ? $cfg['content'] : null;
1275
-                    //second priority goes to filename
1276
-                } elseif (! empty($cfg['filename'])) {
1277
-                    $file_path = $this->_get_dir() . '/help_tabs/' . $cfg['filename'] . '.help_tab.php';
1278
-                    //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)
1279
-                    $file_path = ! is_readable($file_path) ? EE_ADMIN_PAGES
1280
-                                                             . basename($this->_get_dir())
1281
-                                                             . '/help_tabs/'
1282
-                                                             . $cfg['filename']
1283
-                                                             . '.help_tab.php' : $file_path;
1284
-                    //if file is STILL not readable then let's do a EE_Error so its more graceful than a fatal error.
1285
-                    if (! isset($cfg['callback']) && ! is_readable($file_path)) {
1286
-                        EE_Error::add_error(
1287
-                            sprintf(
1288
-                                esc_html__(
1289
-                                    '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',
1290
-                                    'event_espresso'
1291
-                                ),
1292
-                                $tab_id,
1293
-                                key($config),
1294
-                                $file_path
1295
-                            ),
1296
-                            __FILE__,
1297
-                            __FUNCTION__,
1298
-                            __LINE__
1299
-                        );
1300
-                        return;
1301
-                    }
1302
-                    $template_args['admin_page_obj'] = $this;
1303
-                    $content = EEH_Template::display_template(
1304
-                        $file_path,
1305
-                        $template_args,
1306
-                        true
1307
-                    );
1308
-                } else {
1309
-                    $content = '';
1310
-                }
1311
-                //check if callback is valid
1312
-                if (
1313
-                    empty($content) && (
1314
-                        ! isset($cfg['callback']) || ! method_exists($this, $cfg['callback'])
1315
-                    )
1316
-                ) {
1317
-                    EE_Error::add_error(
1318
-                        sprintf(
1319
-                            esc_html__(
1320
-                                '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.',
1321
-                                'event_espresso'
1322
-                            ),
1323
-                            $cfg['title']
1324
-                        ),
1325
-                        __FILE__,
1326
-                        __FUNCTION__,
1327
-                        __LINE__
1328
-                    );
1329
-                    return;
1330
-                }
1331
-                //setup config array for help tab method
1332
-                $id  = $this->page_slug . '-' . $this->_req_action . '-' . $tab_id;
1333
-                $_ht = array(
1334
-                    'id'       => $id,
1335
-                    'title'    => $cfg['title'],
1336
-                    'callback' => isset($cfg['callback']) && empty($content) ? array($this, $cfg['callback']) : null,
1337
-                    'content'  => $content,
1338
-                );
1339
-                $this->_current_screen->add_help_tab($_ht);
1340
-            }
1341
-        }
1342
-    }
1343
-
1344
-
1345
-
1346
-    /**
1347
-     * This basically checks loaded $_page_config property to see if there are any help_tours defined.  "help_tours" is
1348
-     * an array with properties for setting up usage of the joyride plugin
1349
-     *
1350
-     * @link   http://zurb.com/playground/jquery-joyride-feature-tour-plugin
1351
-     * @see    instructions regarding the format and construction of the "help_tour" array element is found in the
1352
-     *         _set_page_config() comments
1353
-     * @return void
1354
-     * @throws EE_Error
1355
-     * @throws InvalidArgumentException
1356
-     * @throws InvalidDataTypeException
1357
-     * @throws InvalidInterfaceException
1358
-     */
1359
-    protected function _add_help_tour()
1360
-    {
1361
-        $tours            = array();
1362
-        $this->_help_tour = array();
1363
-        //exit early if help tours are turned off globally
1364
-        if ((defined('EE_DISABLE_HELP_TOURS') && EE_DISABLE_HELP_TOURS)
1365
-            || ! EE_Registry::instance()->CFG->admin->help_tour_activation
1366
-        ) {
1367
-            return;
1368
-        }
1369
-        //loop through _page_config to find any help_tour defined
1370
-        foreach ($this->_page_config as $route => $config) {
1371
-            //we're only going to set things up for this route
1372
-            if ($route !== $this->_req_action) {
1373
-                continue;
1374
-            }
1375
-            if (isset($config['help_tour'])) {
1376
-                foreach ($config['help_tour'] as $tour) {
1377
-                    $file_path = $this->_get_dir() . '/help_tours/' . $tour . '.class.php';
1378
-                    // let's see if we can get that file...
1379
-                    // if not its possible this is a decaf route not set in caffeinated
1380
-                    // so lets try and get the caffeinated equivalent
1381
-                    $file_path = ! is_readable($file_path) ? EE_ADMIN_PAGES
1382
-                                                             . basename($this->_get_dir())
1383
-                                                             . '/help_tours/'
1384
-                                                             . $tour
1385
-                                                             . '.class.php' : $file_path;
1386
-                    //if file is STILL not readable then let's do a EE_Error so its more graceful than a fatal error.
1387
-                    if (! is_readable($file_path)) {
1388
-                        EE_Error::add_error(
1389
-                            sprintf(
1390
-                                esc_html__(
1391
-                                    'The file path given for the help tour (%s) is not a valid path.  Please check that the string you set for the help tour on this route (%s) is the correct spelling',
1392
-                                    'event_espresso'
1393
-                                ),
1394
-                                $file_path,
1395
-                                $tour
1396
-                            ),
1397
-                            __FILE__,
1398
-                            __FUNCTION__,
1399
-                            __LINE__
1400
-                        );
1401
-                        return;
1402
-                    }
1403
-                    require_once $file_path;
1404
-                    if (! class_exists($tour)) {
1405
-                        $error_msg[] = sprintf(
1406
-                            esc_html__('Something went wrong with loading the %s Help Tour Class.', 'event_espresso'),
1407
-                            $tour
1408
-                        );
1409
-                        $error_msg[] = $error_msg[0] . "\r\n" . sprintf(
1410
-                                esc_html__(
1411
-                                    'There is no class in place for the %s help tour.%s Make sure you have <strong>%s</strong> defined in the "help_tour" array for the %s route of the % admin page.',
1412
-                                    'event_espresso'
1413
-                                ),
1414
-                                $tour,
1415
-                                '<br />',
1416
-                                $tour,
1417
-                                $this->_req_action,
1418
-                                get_class($this)
1419
-                            );
1420
-                        throw new EE_Error(implode('||', $error_msg));
1421
-                    }
1422
-                    $tour_obj                   = new $tour($this->_is_caf);
1423
-                    $tours[]                    = $tour_obj;
1424
-                    $this->_help_tour[$route][] = EEH_Template::help_tour_stops_generator($tour_obj);
1425
-                }
1426
-                //let's inject the end tour stop element common to all pages... this will only get seen once per machine.
1427
-                $end_stop_tour              = new EE_Help_Tour_final_stop($this->_is_caf);
1428
-                $tours[]                    = $end_stop_tour;
1429
-                $this->_help_tour[$route][] = EEH_Template::help_tour_stops_generator($end_stop_tour);
1430
-            }
1431
-        }
1432
-        if (! empty($tours)) {
1433
-            $this->_help_tour['tours'] = $tours;
1434
-        }
1435
-        // that's it!  Now that the $_help_tours property is set (or not)
1436
-        // the scripts and html should be taken care of automatically.
1437
-    }
1438
-
1439
-
1440
-
1441
-    /**
1442
-     * This simply sets up any qtips that have been defined in the page config
1443
-     *
1444
-     * @return void
1445
-     */
1446
-    protected function _add_qtips()
1447
-    {
1448
-        if (isset($this->_route_config['qtips'])) {
1449
-            $qtips = (array)$this->_route_config['qtips'];
1450
-            //load qtip loader
1451
-            $path = array(
1452
-                $this->_get_dir() . '/qtips/',
1453
-                EE_ADMIN_PAGES . basename($this->_get_dir()) . '/qtips/',
1454
-            );
1455
-            EEH_Qtip_Loader::instance()->register($qtips, $path);
1456
-        }
1457
-    }
1458
-
1459
-
1460
-
1461
-    /**
1462
-     * _set_nav_tabs
1463
-     * This sets up the nav tabs from the page_routes array.  This method can be overwritten by child classes if you
1464
-     * wish to add additional tabs or modify accordingly.
1465
-     *
1466
-     * @return void
1467
-     * @throws InvalidArgumentException
1468
-     * @throws InvalidInterfaceException
1469
-     * @throws InvalidDataTypeException
1470
-     */
1471
-    protected function _set_nav_tabs()
1472
-    {
1473
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
1474
-        $i = 0;
1475
-        foreach ($this->_page_config as $slug => $config) {
1476
-            if (
1477
-                ! is_array($config)
1478
-                || (
1479
-                    is_array($config)
1480
-                    && (
1481
-                        (isset($config['nav']) && ! $config['nav'])
1482
-                        || ! isset($config['nav'])
1483
-                    )
1484
-                )
1485
-            ) {
1486
-                continue;
1487
-            }
1488
-            //no nav tab for this config
1489
-            //check for persistent flag
1490
-            if ($slug !== $this->_req_action && isset($config['nav']['persistent']) && ! $config['nav']['persistent']) {
1491
-                // nav tab is only to appear when route requested.
1492
-                continue;
1493
-            }
1494
-            if (! $this->check_user_access($slug, true)) {
1495
-                // no nav tab because current user does not have access.
1496
-                continue;
1497
-            }
1498
-            $css_class              = isset($config['css_class']) ? $config['css_class'] . ' ' : '';
1499
-            $this->_nav_tabs[$slug] = array(
1500
-                'url'       => isset($config['nav']['url'])
1501
-                    ? $config['nav']['url']
1502
-                    : self::add_query_args_and_nonce(
1503
-                        array('action' => $slug),
1504
-                        $this->_admin_base_url
1505
-                    ),
1506
-                'link_text' => isset($config['nav']['label'])
1507
-                    ? $config['nav']['label']
1508
-                    : ucwords(
1509
-                        str_replace('_', ' ', $slug)
1510
-                    ),
1511
-                'css_class' => $this->_req_action === $slug ? $css_class . 'nav-tab-active' : $css_class,
1512
-                'order'     => isset($config['nav']['order']) ? $config['nav']['order'] : $i,
1513
-            );
1514
-            $i++;
1515
-        }
1516
-        //if $this->_nav_tabs is empty then lets set the default
1517
-        if (empty($this->_nav_tabs)) {
1518
-            $this->_nav_tabs[$this->_default_nav_tab_name] = array(
1519
-                'url'       => $this->_admin_base_url,
1520
-                'link_text' => ucwords(str_replace('_', ' ', $this->_default_nav_tab_name)),
1521
-                'css_class' => 'nav-tab-active',
1522
-                'order'     => 10,
1523
-            );
1524
-        }
1525
-        //now let's sort the tabs according to order
1526
-        usort($this->_nav_tabs, array($this, '_sort_nav_tabs'));
1527
-    }
1528
-
1529
-
1530
-
1531
-    /**
1532
-     * _set_current_labels
1533
-     * This method modifies the _labels property with any optional specific labels indicated in the _page_routes
1534
-     * property array
1535
-     *
1536
-     * @return void
1537
-     */
1538
-    private function _set_current_labels()
1539
-    {
1540
-        if (is_array($this->_route_config) && isset($this->_route_config['labels'])) {
1541
-            foreach ($this->_route_config['labels'] as $label => $text) {
1542
-                if (is_array($text)) {
1543
-                    foreach ($text as $sublabel => $subtext) {
1544
-                        $this->_labels[$label][$sublabel] = $subtext;
1545
-                    }
1546
-                } else {
1547
-                    $this->_labels[$label] = $text;
1548
-                }
1549
-            }
1550
-        }
1551
-    }
1552
-
1553
-
1554
-
1555
-    /**
1556
-     *        verifies user access for this admin page
1557
-     *
1558
-     * @param string $route_to_check if present then the capability for the route matching this string is checked.
1559
-     * @param bool   $verify_only    Default is FALSE which means if user check fails then wp_die().  Otherwise just
1560
-     *                               return false if verify fail.
1561
-     * @return bool
1562
-     * @throws InvalidArgumentException
1563
-     * @throws InvalidDataTypeException
1564
-     * @throws InvalidInterfaceException
1565
-     */
1566
-    public function check_user_access($route_to_check = '', $verify_only = false)
1567
-    {
1568
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
1569
-        $route_to_check = empty($route_to_check) ? $this->_req_action : $route_to_check;
1570
-        $capability     = ! empty($route_to_check) && isset($this->_page_routes[$route_to_check])
1571
-                          && is_array(
1572
-                              $this->_page_routes[$route_to_check]
1573
-                          )
1574
-                          && ! empty($this->_page_routes[$route_to_check]['capability'])
1575
-            ? $this->_page_routes[$route_to_check]['capability'] : null;
1576
-        if (empty($capability) && empty($route_to_check)) {
1577
-            $capability = is_array($this->_route) && empty($this->_route['capability']) ? 'manage_options'
1578
-                : $this->_route['capability'];
1579
-        } else {
1580
-            $capability = empty($capability) ? 'manage_options' : $capability;
1581
-        }
1582
-        $id = is_array($this->_route) && ! empty($this->_route['obj_id']) ? $this->_route['obj_id'] : 0;
1583
-        if (
1584
-            ! defined('DOING_AJAX')
1585
-            && (
1586
-                ! function_exists('is_admin')
1587
-                || ! EE_Registry::instance()->CAP->current_user_can(
1588
-                    $capability,
1589
-                    $this->page_slug
1590
-                    . '_'
1591
-                    . $route_to_check,
1592
-                    $id
1593
-                )
1594
-            )
1595
-        ) {
1596
-            if ($verify_only) {
1597
-                return false;
1598
-            }
1599
-            if (is_user_logged_in()) {
1600
-                wp_die(__('You do not have access to this route.', 'event_espresso'));
1601
-            } else {
1602
-                return false;
1603
-            }
1604
-        }
1605
-        return true;
1606
-    }
1607
-
1608
-
1609
-
1610
-    /**
1611
-     * admin_init_global
1612
-     * This runs all the code that we want executed within the WP admin_init hook.
1613
-     * This method executes for ALL EE Admin pages.
1614
-     *
1615
-     * @return void
1616
-     */
1617
-    public function admin_init_global()
1618
-    {
1619
-    }
1620
-
1621
-
1622
-
1623
-    /**
1624
-     * wp_loaded_global
1625
-     * This runs all the code that we want executed within the WP wp_loaded hook.  This method is optional for an
1626
-     * EE_Admin page and will execute on every EE Admin Page load
1627
-     *
1628
-     * @return void
1629
-     */
1630
-    public function wp_loaded()
1631
-    {
1632
-    }
1633
-
1634
-
1635
-
1636
-    /**
1637
-     * admin_notices
1638
-     * Anything triggered by the 'admin_notices' WP hook should be put in here.  This particular method will apply on
1639
-     * ALL EE_Admin pages.
1640
-     *
1641
-     * @return void
1642
-     */
1643
-    public function admin_notices_global()
1644
-    {
1645
-        $this->_display_no_javascript_warning();
1646
-        $this->_display_espresso_notices();
1647
-    }
1648
-
1649
-
1650
-
1651
-    public function network_admin_notices_global()
1652
-    {
1653
-        $this->_display_no_javascript_warning();
1654
-        $this->_display_espresso_notices();
1655
-    }
1656
-
1657
-
1658
-
1659
-    /**
1660
-     * admin_footer_scripts_global
1661
-     * Anything triggered by the 'admin_print_footer_scripts' WP hook should be put in here. This particular method
1662
-     * will apply on ALL EE_Admin pages.
1663
-     *
1664
-     * @return void
1665
-     */
1666
-    public function admin_footer_scripts_global()
1667
-    {
1668
-        $this->_add_admin_page_ajax_loading_img();
1669
-        $this->_add_admin_page_overlay();
1670
-        //if metaboxes are present we need to add the nonce field
1671
-        if (
1672
-             isset($this->_route_config['metaboxes'])
1673
-             || isset($this->_route_config['list_table'])
1674
-             || (isset($this->_route_config['has_metaboxes']) && $this->_route_config['has_metaboxes'])
1675
-        ) {
1676
-            wp_nonce_field('closedpostboxes', 'closedpostboxesnonce', false);
1677
-            wp_nonce_field('meta-box-order', 'meta-box-order-nonce', false);
1678
-        }
1679
-    }
1680
-
1681
-
1682
-
1683
-    /**
1684
-     * admin_footer_global
1685
-     * Anything triggered by the wp 'admin_footer' wp hook should be put in here. This particular method will apply on
1686
-     * ALL EE_Admin Pages.
1687
-     *
1688
-     * @return void
1689
-     * @throws EE_Error
1690
-     */
1691
-    public function admin_footer_global()
1692
-    {
1693
-        //dialog container for dialog helper
1694
-        $d_cont = '<div class="ee-admin-dialog-container auto-hide hidden">' . "\n";
1695
-        $d_cont .= '<div class="ee-notices"></div>';
1696
-        $d_cont .= '<div class="ee-admin-dialog-container-inner-content"></div>';
1697
-        $d_cont .= '</div>';
1698
-        echo $d_cont;
1699
-        //help tour stuff?
1700
-        if (isset($this->_help_tour[$this->_req_action])) {
1701
-            echo implode('<br />', $this->_help_tour[$this->_req_action]);
1702
-        }
1703
-        //current set timezone for timezone js
1704
-        echo '<span id="current_timezone" class="hidden">' . EEH_DTT_Helper::get_timezone() . '</span>';
1705
-    }
1706
-
1707
-
1708
-
1709
-    /**
1710
-     * This function sees if there is a method for help popup content existing for the given route.  If there is then
1711
-     * we'll use the retrieved array to output the content using the template. For child classes: If you want to have
1712
-     * help popups then in your templates or your content you set "triggers" for the content using the
1713
-     * "_set_help_trigger('help_trigger_id')" where "help_trigger_id" is what you will use later in your custom method
1714
-     * for the help popup content on that page. Then in your Child_Admin_Page class you need to define a help popup
1715
-     * method for the content in the format "_help_popup_content_{route_name}()"  So if you are setting help content
1716
-     * for the
1717
-     * 'edit_event' route you should have a method named "_help_popup_content_edit_route". In your defined
1718
-     * "help_popup_content_..." method.  You must prepare and return an array in the following format array(
1719
-     *    'help_trigger_id' => array(
1720
-     *        'title' => esc_html__('localized title for popup', 'event_espresso'),
1721
-     *        'content' => esc_html__('localized content for popup', 'event_espresso')
1722
-     *    )
1723
-     * );
1724
-     * Then the EE_Admin_Parent will take care of making sure that is setup properly on the correct route.
1725
-     *
1726
-     * @param array $help_array
1727
-     * @param bool  $display
1728
-     * @return string content
1729
-     * @throws DomainException
1730
-     * @throws EE_Error
1731
-     */
1732
-    protected function _set_help_popup_content($help_array = array(), $display = false)
1733
-    {
1734
-        $content       = '';
1735
-        $help_array    = empty($help_array) ? $this->_get_help_content() : $help_array;
1736
-        //loop through the array and setup content
1737
-        foreach ($help_array as $trigger => $help) {
1738
-            //make sure the array is setup properly
1739
-            if (! isset($help['title']) || ! isset($help['content'])) {
1740
-                throw new EE_Error(
1741
-                    esc_html__(
1742
-                        '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',
1743
-                        'event_espresso'
1744
-                    )
1745
-                );
1746
-            }
1747
-            //we're good so let'd setup the template vars and then assign parsed template content to our content.
1748
-            $template_args = array(
1749
-                'help_popup_id'      => $trigger,
1750
-                'help_popup_title'   => $help['title'],
1751
-                'help_popup_content' => $help['content'],
1752
-            );
1753
-            $content       .= EEH_Template::display_template(
1754
-                EE_ADMIN_TEMPLATE . 'admin_help_popup.template.php',
1755
-                $template_args,
1756
-                true
1757
-            );
1758
-        }
1759
-        if ($display) {
1760
-            echo $content;
1761
-            return '';
1762
-        }
1763
-        return $content;
1764
-    }
1765
-
1766
-
1767
-
1768
-    /**
1769
-     * All this does is retrieve the help content array if set by the EE_Admin_Page child
1770
-     *
1771
-     * @return array properly formatted array for help popup content
1772
-     * @throws EE_Error
1773
-     */
1774
-    private function _get_help_content()
1775
-    {
1776
-        //what is the method we're looking for?
1777
-        $method_name = '_help_popup_content_' . $this->_req_action;
1778
-        //if method doesn't exist let's get out.
1779
-        if (! method_exists($this, $method_name)) {
1780
-            return array();
1781
-        }
1782
-        //k we're good to go let's retrieve the help array
1783
-        $help_array = call_user_func(array($this, $method_name));
1784
-        //make sure we've got an array!
1785
-        if (! is_array($help_array)) {
1786
-            throw new EE_Error(
1787
-                esc_html__(
1788
-                    'Something went wrong with help popup content generation. Expecting an array and well, this ain\'t no array bub.',
1789
-                    'event_espresso'
1790
-                )
1791
-            );
1792
-        }
1793
-        return $help_array;
1794
-    }
1795
-
1796
-
1797
-
1798
-    /**
1799
-     * EE Admin Pages can use this to set a properly formatted trigger for a help popup.
1800
-     * By default the trigger html is printed.  Otherwise it can be returned if the $display flag is set "false"
1801
-     * See comments made on the _set_help_content method for understanding other parts to the help popup tool.
1802
-     *
1803
-     * @param string  $trigger_id reference for retrieving the trigger content for the popup
1804
-     * @param boolean $display    if false then we return the trigger string
1805
-     * @param array   $dimensions an array of dimensions for the box (array(h,w))
1806
-     * @return string
1807
-     * @throws DomainException
1808
-     * @throws EE_Error
1809
-     */
1810
-    protected function _set_help_trigger($trigger_id, $display = true, $dimensions = array('400', '640'))
1811
-    {
1812
-        if (defined('DOING_AJAX')) {
1813
-            return '';
1814
-        }
1815
-        //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
1816
-        $help_array   = $this->_get_help_content();
1817
-        $help_content = '';
1818
-        if (empty($help_array) || ! isset($help_array[$trigger_id])) {
1819
-            $help_array[$trigger_id] = array(
1820
-                'title'   => esc_html__('Missing Content', 'event_espresso'),
1821
-                'content' => esc_html__(
1822
-                    '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.)',
1823
-                    'event_espresso'
1824
-                ),
1825
-            );
1826
-            $help_content            = $this->_set_help_popup_content($help_array, false);
1827
-        }
1828
-        //let's setup the trigger
1829
-        $content = '<a class="ee-dialog" href="?height='
1830
-                   . $dimensions[0]
1831
-                   . '&width='
1832
-                   . $dimensions[1]
1833
-                   . '&inlineId='
1834
-                   . $trigger_id
1835
-                   . '" target="_blank"><span class="question ee-help-popup-question"></span></a>';
1836
-        $content .= $help_content;
1837
-        if ($display) {
1838
-            echo $content;
1839
-            return  '';
1840
-        }
1841
-        return $content;
1842
-    }
1843
-
1844
-
1845
-
1846
-    /**
1847
-     * _add_global_screen_options
1848
-     * Add any extra wp_screen_options within this method using built-in WP functions/methods for doing so.
1849
-     * This particular method will add_screen_options on ALL EE_Admin Pages
1850
-     *
1851
-     * @link   http://chrismarslender.com/wp-tutorials/wordpress-screen-options-tutorial/
1852
-     *         see also WP_Screen object documents...
1853
-     * @link   http://codex.wordpress.org/Class_Reference/WP_Screen
1854
-     * @abstract
1855
-     * @return void
1856
-     */
1857
-    private function _add_global_screen_options()
1858
-    {
1859
-    }
1860
-
1861
-
1862
-
1863
-    /**
1864
-     * _add_global_feature_pointers
1865
-     * This method is used for implementing any "feature pointers" (using built-in WP styling js).
1866
-     * This particular method will implement feature pointers for ALL EE_Admin pages.
1867
-     * Note: this is just a placeholder for now.  Implementation will come down the road
1868
-     *
1869
-     * @see    WP_Internal_Pointers class in wp-admin/includes/template.php for example (its a final class so can't be
1870
-     *         extended) also see:
1871
-     * @link   http://eamann.com/tech/wordpress-portland/
1872
-     * @abstract
1873
-     * @return void
1874
-     */
1875
-    private function _add_global_feature_pointers()
1876
-    {
1877
-    }
1878
-
1879
-
1880
-
1881
-    /**
1882
-     * load_global_scripts_styles
1883
-     * The scripts and styles enqueued in here will be loaded on every EE Admin page
1884
-     *
1885
-     * @return void
1886
-     * @throws EE_Error
1887
-     */
1888
-    public function load_global_scripts_styles()
1889
-    {
1890
-        /** STYLES **/
1891
-        // add debugging styles
1892
-        if (WP_DEBUG) {
1893
-            add_action('admin_head', array($this, 'add_xdebug_style'));
1894
-        }
1895
-        // register all styles
1896
-        wp_register_style(
1897
-            'espresso-ui-theme',
1898
-            EE_GLOBAL_ASSETS_URL . 'css/espresso-ui-theme/jquery-ui-1.10.3.custom.min.css',
1899
-            array(),
1900
-            EVENT_ESPRESSO_VERSION
1901
-        );
1902
-        wp_register_style('ee-admin-css', EE_ADMIN_URL . 'assets/ee-admin-page.css', array(), EVENT_ESPRESSO_VERSION);
1903
-        //helpers styles
1904
-        wp_register_style(
1905
-            'ee-text-links',
1906
-            EE_PLUGIN_DIR_URL . 'core/helpers/assets/ee_text_list_helper.css',
1907
-            array(),
1908
-            EVENT_ESPRESSO_VERSION
1909
-        );
1910
-        /** SCRIPTS **/
1911
-        //register all scripts
1912
-        wp_register_script(
1913
-            'ee-dialog',
1914
-            EE_ADMIN_URL . 'assets/ee-dialog-helper.js',
1915
-            array('jquery', 'jquery-ui-draggable'),
1916
-            EVENT_ESPRESSO_VERSION,
1917
-            true
1918
-        );
1919
-        wp_register_script(
1920
-            'ee_admin_js',
1921
-            EE_ADMIN_URL . 'assets/ee-admin-page.js',
1922
-            array('espresso_core', 'ee-parse-uri', 'ee-dialog'),
1923
-            EVENT_ESPRESSO_VERSION,
1924
-            true
1925
-        );
1926
-        wp_register_script(
1927
-            'jquery-ui-timepicker-addon',
1928
-            EE_GLOBAL_ASSETS_URL . 'scripts/jquery-ui-timepicker-addon.js',
1929
-            array('jquery-ui-datepicker', 'jquery-ui-slider'),
1930
-            EVENT_ESPRESSO_VERSION,
1931
-            true
1932
-        );
1933
-        add_filter('FHEE_load_joyride', '__return_true');
1934
-        //script for sorting tables
1935
-        wp_register_script(
1936
-            'espresso_ajax_table_sorting',
1937
-            EE_ADMIN_URL . 'assets/espresso_ajax_table_sorting.js',
1938
-            array('ee_admin_js', 'jquery-ui-sortable'),
1939
-            EVENT_ESPRESSO_VERSION,
1940
-            true
1941
-        );
1942
-        //script for parsing uri's
1943
-        wp_register_script(
1944
-            'ee-parse-uri',
1945
-            EE_GLOBAL_ASSETS_URL . 'scripts/parseuri.js',
1946
-            array(),
1947
-            EVENT_ESPRESSO_VERSION,
1948
-            true
1949
-        );
1950
-        //and parsing associative serialized form elements
1951
-        wp_register_script(
1952
-            'ee-serialize-full-array',
1953
-            EE_GLOBAL_ASSETS_URL . 'scripts/jquery.serializefullarray.js',
1954
-            array('jquery'),
1955
-            EVENT_ESPRESSO_VERSION,
1956
-            true
1957
-        );
1958
-        //helpers scripts
1959
-        wp_register_script(
1960
-            'ee-text-links',
1961
-            EE_PLUGIN_DIR_URL . 'core/helpers/assets/ee_text_list_helper.js',
1962
-            array('jquery'),
1963
-            EVENT_ESPRESSO_VERSION,
1964
-            true
1965
-        );
1966
-        wp_register_script(
1967
-            'ee-moment-core',
1968
-            EE_THIRD_PARTY_URL . 'moment/moment-with-locales.min.js',
1969
-            array(),
1970
-            EVENT_ESPRESSO_VERSION,
1971
-            true
1972
-        );
1973
-        wp_register_script(
1974
-            'ee-moment',
1975
-            EE_THIRD_PARTY_URL . 'moment/moment-timezone-with-data.min.js',
1976
-            array('ee-moment-core'),
1977
-            EVENT_ESPRESSO_VERSION,
1978
-            true
1979
-        );
1980
-        wp_register_script(
1981
-            'ee-datepicker',
1982
-            EE_ADMIN_URL . 'assets/ee-datepicker.js',
1983
-            array('jquery-ui-timepicker-addon', 'ee-moment'),
1984
-            EVENT_ESPRESSO_VERSION,
1985
-            true
1986
-        );
1987
-        //google charts
1988
-        wp_register_script(
1989
-            'google-charts',
1990
-            'https://www.gstatic.com/charts/loader.js',
1991
-            array(),
1992
-            EVENT_ESPRESSO_VERSION,
1993
-            false
1994
-        );
1995
-        // ENQUEUE ALL BASICS BY DEFAULT
1996
-        wp_enqueue_style('ee-admin-css');
1997
-        wp_enqueue_script('ee_admin_js');
1998
-        wp_enqueue_script('ee-accounting');
1999
-        wp_enqueue_script('jquery-validate');
2000
-        //taking care of metaboxes
2001
-        if (
2002
-            empty($this->_cpt_route)
2003
-            && (isset($this->_route_config['metaboxes']) || isset($this->_route_config['has_metaboxes']))
2004
-        ) {
2005
-            wp_enqueue_script('dashboard');
2006
-        }
2007
-        // LOCALIZED DATA
2008
-        //localize script for ajax lazy loading
2009
-        $lazy_loader_container_ids = apply_filters(
2010
-            'FHEE__EE_Admin_Page_Core__load_global_scripts_styles__loader_containers',
2011
-            array('espresso_news_post_box_content')
2012
-        );
2013
-        wp_localize_script('ee_admin_js', 'eeLazyLoadingContainers', $lazy_loader_container_ids);
2014
-        /**
2015
-         * help tour stuff
2016
-         */
2017
-        if (! empty($this->_help_tour)) {
2018
-            //register the js for kicking things off
2019
-            wp_enqueue_script(
2020
-                'ee-help-tour',
2021
-                EE_ADMIN_URL . 'assets/ee-help-tour.js',
2022
-                array('jquery-joyride'),
2023
-                EVENT_ESPRESSO_VERSION,
2024
-                true
2025
-            );
2026
-            $tours = array();
2027
-            //setup tours for the js tour object
2028
-            foreach ($this->_help_tour['tours'] as $tour) {
2029
-                if ($tour instanceof EE_Help_Tour) {
2030
-                    $tours[] = array(
2031
-                        'id'      => $tour->get_slug(),
2032
-                        'options' => $tour->get_options(),
2033
-                    );
2034
-                }
2035
-            }
2036
-            wp_localize_script('ee-help-tour', 'EE_HELP_TOUR', array('tours' => $tours));
2037
-            //admin_footer_global will take care of making sure our help_tour skeleton gets printed via the info stored in $this->_help_tour
2038
-        }
2039
-    }
2040
-
2041
-
2042
-
2043
-    /**
2044
-     *        admin_footer_scripts_eei18n_js_strings
2045
-     *
2046
-     * @return        void
2047
-     */
2048
-    public function admin_footer_scripts_eei18n_js_strings()
2049
-    {
2050
-        EE_Registry::$i18n_js_strings['ajax_url']       = WP_AJAX_URL;
2051
-        EE_Registry::$i18n_js_strings['confirm_delete'] = esc_html__(
2052
-            '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!!!',
2053
-            'event_espresso'
2054
-        );
2055
-        EE_Registry::$i18n_js_strings['January']        = esc_html__('January', 'event_espresso');
2056
-        EE_Registry::$i18n_js_strings['February']       = esc_html__('February', 'event_espresso');
2057
-        EE_Registry::$i18n_js_strings['March']          = esc_html__('March', 'event_espresso');
2058
-        EE_Registry::$i18n_js_strings['April']          = esc_html__('April', 'event_espresso');
2059
-        EE_Registry::$i18n_js_strings['May']            = esc_html__('May', 'event_espresso');
2060
-        EE_Registry::$i18n_js_strings['June']           = esc_html__('June', 'event_espresso');
2061
-        EE_Registry::$i18n_js_strings['July']           = esc_html__('July', 'event_espresso');
2062
-        EE_Registry::$i18n_js_strings['August']         = esc_html__('August', 'event_espresso');
2063
-        EE_Registry::$i18n_js_strings['September']      = esc_html__('September', 'event_espresso');
2064
-        EE_Registry::$i18n_js_strings['October']        = esc_html__('October', 'event_espresso');
2065
-        EE_Registry::$i18n_js_strings['November']       = esc_html__('November', 'event_espresso');
2066
-        EE_Registry::$i18n_js_strings['December']       = esc_html__('December', 'event_espresso');
2067
-        EE_Registry::$i18n_js_strings['Jan']            = esc_html__('Jan', 'event_espresso');
2068
-        EE_Registry::$i18n_js_strings['Feb']            = esc_html__('Feb', 'event_espresso');
2069
-        EE_Registry::$i18n_js_strings['Mar']            = esc_html__('Mar', 'event_espresso');
2070
-        EE_Registry::$i18n_js_strings['Apr']            = esc_html__('Apr', 'event_espresso');
2071
-        EE_Registry::$i18n_js_strings['May']            = esc_html__('May', 'event_espresso');
2072
-        EE_Registry::$i18n_js_strings['Jun']            = esc_html__('Jun', 'event_espresso');
2073
-        EE_Registry::$i18n_js_strings['Jul']            = esc_html__('Jul', 'event_espresso');
2074
-        EE_Registry::$i18n_js_strings['Aug']            = esc_html__('Aug', 'event_espresso');
2075
-        EE_Registry::$i18n_js_strings['Sep']            = esc_html__('Sep', 'event_espresso');
2076
-        EE_Registry::$i18n_js_strings['Oct']            = esc_html__('Oct', 'event_espresso');
2077
-        EE_Registry::$i18n_js_strings['Nov']            = esc_html__('Nov', 'event_espresso');
2078
-        EE_Registry::$i18n_js_strings['Dec']            = esc_html__('Dec', 'event_espresso');
2079
-        EE_Registry::$i18n_js_strings['Sunday']         = esc_html__('Sunday', 'event_espresso');
2080
-        EE_Registry::$i18n_js_strings['Monday']         = esc_html__('Monday', 'event_espresso');
2081
-        EE_Registry::$i18n_js_strings['Tuesday']        = esc_html__('Tuesday', 'event_espresso');
2082
-        EE_Registry::$i18n_js_strings['Wednesday']      = esc_html__('Wednesday', 'event_espresso');
2083
-        EE_Registry::$i18n_js_strings['Thursday']       = esc_html__('Thursday', 'event_espresso');
2084
-        EE_Registry::$i18n_js_strings['Friday']         = esc_html__('Friday', 'event_espresso');
2085
-        EE_Registry::$i18n_js_strings['Saturday']       = esc_html__('Saturday', 'event_espresso');
2086
-        EE_Registry::$i18n_js_strings['Sun']            = esc_html__('Sun', 'event_espresso');
2087
-        EE_Registry::$i18n_js_strings['Mon']            = esc_html__('Mon', 'event_espresso');
2088
-        EE_Registry::$i18n_js_strings['Tue']            = esc_html__('Tue', 'event_espresso');
2089
-        EE_Registry::$i18n_js_strings['Wed']            = esc_html__('Wed', 'event_espresso');
2090
-        EE_Registry::$i18n_js_strings['Thu']            = esc_html__('Thu', 'event_espresso');
2091
-        EE_Registry::$i18n_js_strings['Fri']            = esc_html__('Fri', 'event_espresso');
2092
-        EE_Registry::$i18n_js_strings['Sat']            = esc_html__('Sat', 'event_espresso');
2093
-    }
2094
-
2095
-
2096
-
2097
-    /**
2098
-     *        load enhanced xdebug styles for ppl with failing eyesight
2099
-     *
2100
-     * @return        void
2101
-     */
2102
-    public function add_xdebug_style()
2103
-    {
2104
-        echo '<style>.xdebug-error { font-size:1.5em; }</style>';
2105
-    }
2106
-
2107
-
2108
-    /************************/
2109
-    /** LIST TABLE METHODS **/
2110
-    /************************/
2111
-    /**
2112
-     * this sets up the list table if the current view requires it.
2113
-     *
2114
-     * @return void
2115
-     * @throws EE_Error
2116
-     */
2117
-    protected function _set_list_table()
2118
-    {
2119
-        //first is this a list_table view?
2120
-        if (! isset($this->_route_config['list_table'])) {
2121
-            return;
2122
-        } //not a list_table view so get out.
2123
-        // list table functions are per view specific (because some admin pages might have more than one list table!)
2124
-        $list_table_view = '_set_list_table_views_' . $this->_req_action;
2125
-        if (! method_exists($this, $list_table_view) || $this->{$list_table_view}() === false) {
2126
-            //user error msg
2127
-            $error_msg = esc_html__(
2128
-                'An error occurred. The requested list table views could not be found.',
2129
-                'event_espresso'
2130
-            );
2131
-            //developer error msg
2132
-            $error_msg .= '||' . sprintf(
2133
-                    esc_html__(
2134
-                        '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.',
2135
-                        'event_espresso'
2136
-                    ),
2137
-                    $this->_req_action,
2138
-                    $list_table_view
2139
-                );
2140
-            throw new EE_Error($error_msg);
2141
-        }
2142
-        //let's provide the ability to filter the views per PAGE AND ROUTE, per PAGE, and globally
2143
-        $this->_views = apply_filters(
2144
-            'FHEE_list_table_views_' . $this->page_slug . '_' . $this->_req_action,
2145
-            $this->_views
2146
-        );
2147
-        $this->_views = apply_filters('FHEE_list_table_views_' . $this->page_slug, $this->_views);
2148
-        $this->_views = apply_filters('FHEE_list_table_views', $this->_views);
2149
-        $this->_set_list_table_view();
2150
-        $this->_set_list_table_object();
2151
-    }
2152
-
2153
-
2154
-
2155
-    /**
2156
-     * set current view for List Table
2157
-     *
2158
-     * @return void
2159
-     */
2160
-    protected function _set_list_table_view()
2161
-    {
2162
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2163
-        // looking at active items or dumpster diving ?
2164
-        if (! isset($this->_req_data['status']) || ! array_key_exists($this->_req_data['status'], $this->_views)) {
2165
-            $this->_view = isset($this->_views['in_use']) ? 'in_use' : 'all';
2166
-        } else {
2167
-            $this->_view = sanitize_key($this->_req_data['status']);
2168
-        }
2169
-    }
2170
-
2171
-
2172
-    /**
2173
-     * _set_list_table_object
2174
-     * WP_List_Table objects need to be loaded fairly early so automatic stuff WP does is taken care of.
2175
-     *
2176
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2177
-     * @throws \InvalidArgumentException
2178
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2179
-     * @throws EE_Error
2180
-     * @throws InvalidInterfaceException
2181
-     */
2182
-    protected function _set_list_table_object()
2183
-    {
2184
-        if (isset($this->_route_config['list_table'])) {
2185
-            if (! class_exists($this->_route_config['list_table'])) {
2186
-                throw new EE_Error(
2187
-                    sprintf(
2188
-                        esc_html__(
2189
-                            '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.',
2190
-                            'event_espresso'
2191
-                        ),
2192
-                        $this->_route_config['list_table'],
2193
-                        get_class($this)
2194
-                    )
2195
-                );
2196
-            }
2197
-            $this->_list_table_object = LoaderFactory::getLoader()->getShared(
2198
-                $this->_route_config['list_table'],
2199
-                array($this)
2200
-            );
2201
-        }
2202
-    }
2203
-
2204
-
2205
-
2206
-    /**
2207
-     * get_list_table_view_RLs - get it? View RL ?? VU-RL???  URL ??
2208
-     *
2209
-     * @param array $extra_query_args                     Optional. An array of extra query args to add to the generated
2210
-     *                                                    urls.  The array should be indexed by the view it is being
2211
-     *                                                    added to.
2212
-     * @return array
2213
-     */
2214
-    public function get_list_table_view_RLs($extra_query_args = array())
2215
-    {
2216
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2217
-        if (empty($this->_views)) {
2218
-            $this->_views = array();
2219
-        }
2220
-        // cycle thru views
2221
-        foreach ($this->_views as $key => $view) {
2222
-            $query_args = array();
2223
-            // check for current view
2224
-            $this->_views[$key]['class']               = $this->_view === $view['slug'] ? 'current' : '';
2225
-            $query_args['action']                      = $this->_req_action;
2226
-            $query_args[$this->_req_action . '_nonce'] = wp_create_nonce($query_args['action'] . '_nonce');
2227
-            $query_args['status']                      = $view['slug'];
2228
-            //merge any other arguments sent in.
2229
-            if (isset($extra_query_args[$view['slug']])) {
2230
-                $query_args = array_merge($query_args, $extra_query_args[$view['slug']]);
2231
-            }
2232
-            $this->_views[$key]['url'] = EE_Admin_Page::add_query_args_and_nonce($query_args, $this->_admin_base_url);
2233
-        }
2234
-        return $this->_views;
2235
-    }
2236
-
2237
-
2238
-
2239
-    /**
2240
-     * _entries_per_page_dropdown
2241
-     * generates a drop down box for selecting the number of visible rows in an admin page list table
2242
-     *
2243
-     * @todo   : Note: ideally this should be added to the screen options dropdown as that would be consistent with how
2244
-     *         WP does it.
2245
-     * @param int $max_entries total number of rows in the table
2246
-     * @return string
2247
-     */
2248
-    protected function _entries_per_page_dropdown($max_entries = 0)
2249
-    {
2250
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2251
-        $values   = array(10, 25, 50, 100);
2252
-        $per_page = (! empty($this->_req_data['per_page'])) ? absint($this->_req_data['per_page']) : 10;
2253
-        if ($max_entries) {
2254
-            $values[] = $max_entries;
2255
-            sort($values);
2256
-        }
2257
-        $entries_per_page_dropdown = '
126
+	/**
127
+	 * @var string $_req_action
128
+	 */
129
+	protected $_req_action;
130
+
131
+	/**
132
+	 * @var string $_req_nonce
133
+	 */
134
+	protected $_req_nonce;
135
+
136
+	//search related
137
+	protected $_search_btn_label;
138
+
139
+	protected $_search_box_callback;
140
+
141
+	/**
142
+	 * WP Current Screen object
143
+	 *
144
+	 * @var WP_Screen
145
+	 */
146
+	protected $_current_screen;
147
+
148
+	//for holding EE_Admin_Hooks object when needed (set via set_hook_object())
149
+	protected $_hook_obj;
150
+
151
+	//for holding incoming request data
152
+	protected $_req_data;
153
+
154
+	// yes / no array for admin form fields
155
+	protected $_yes_no_values = array();
156
+
157
+	//some default things shared by all child classes
158
+	protected $_default_espresso_metaboxes;
159
+
160
+	/**
161
+	 *    EE_Registry Object
162
+	 *
163
+	 * @var    EE_Registry
164
+	 */
165
+	protected $EE = null;
166
+
167
+
168
+
169
+	/**
170
+	 * This is just a property that flags whether the given route is a caffeinated route or not.
171
+	 *
172
+	 * @var boolean
173
+	 */
174
+	protected $_is_caf = false;
175
+
176
+
177
+
178
+	/**
179
+	 * @Constructor
180
+	 * @param bool $routing indicate whether we want to just load the object and handle routing or just load the object.
181
+	 * @throws EE_Error
182
+	 * @throws InvalidArgumentException
183
+	 * @throws ReflectionException
184
+	 * @throws InvalidDataTypeException
185
+	 * @throws InvalidInterfaceException
186
+	 */
187
+	public function __construct($routing = true)
188
+	{
189
+		if (strpos($this->_get_dir(), 'caffeinated') !== false) {
190
+			$this->_is_caf = true;
191
+		}
192
+		$this->_yes_no_values = array(
193
+			array('id' => true, 'text' => esc_html__('Yes', 'event_espresso')),
194
+			array('id' => false, 'text' => esc_html__('No', 'event_espresso')),
195
+		);
196
+		//set the _req_data property.
197
+		$this->_req_data = array_merge($_GET, $_POST);
198
+		//routing enabled?
199
+		$this->_routing = $routing;
200
+		//set initial page props (child method)
201
+		$this->_init_page_props();
202
+		//set global defaults
203
+		$this->_set_defaults();
204
+		//set early because incoming requests could be ajax related and we need to register those hooks.
205
+		$this->_global_ajax_hooks();
206
+		$this->_ajax_hooks();
207
+		//other_page_hooks have to be early too.
208
+		$this->_do_other_page_hooks();
209
+		//This just allows us to have extending classes do something specific
210
+		// before the parent constructor runs _page_setup().
211
+		if (method_exists($this, '_before_page_setup')) {
212
+			$this->_before_page_setup();
213
+		}
214
+		//set up page dependencies
215
+		$this->_page_setup();
216
+	}
217
+
218
+
219
+
220
+	/**
221
+	 * _init_page_props
222
+	 * Child classes use to set at least the following properties:
223
+	 * $page_slug.
224
+	 * $page_label.
225
+	 *
226
+	 * @abstract
227
+	 * @return void
228
+	 */
229
+	abstract protected function _init_page_props();
230
+
231
+
232
+
233
+	/**
234
+	 * _ajax_hooks
235
+	 * child classes put all their add_action('wp_ajax_{name_of_hook}') hooks in here.
236
+	 * Note: within the ajax callback methods.
237
+	 *
238
+	 * @abstract
239
+	 * @return void
240
+	 */
241
+	abstract protected function _ajax_hooks();
242
+
243
+
244
+
245
+	/**
246
+	 * _define_page_props
247
+	 * child classes define page properties in here.  Must include at least:
248
+	 * $_admin_base_url = base_url for all admin pages
249
+	 * $_admin_page_title = default admin_page_title for admin pages
250
+	 * $_labels = array of default labels for various automatically generated elements:
251
+	 *    array(
252
+	 *        'buttons' => array(
253
+	 *            'add' => esc_html__('label for add new button'),
254
+	 *            'edit' => esc_html__('label for edit button'),
255
+	 *            'delete' => esc_html__('label for delete button')
256
+	 *            )
257
+	 *        )
258
+	 *
259
+	 * @abstract
260
+	 * @return void
261
+	 */
262
+	abstract protected function _define_page_props();
263
+
264
+
265
+
266
+	/**
267
+	 * _set_page_routes
268
+	 * child classes use this to define the page routes for all subpages handled by the class.  Page routes are
269
+	 * assigned to a action => method pairs in an array and to the $_page_routes property.  Each page route must also
270
+	 * have a 'default' route. Here's the format
271
+	 * $this->_page_routes = array(
272
+	 *        'default' => array(
273
+	 *            'func' => '_default_method_handling_route',
274
+	 *            'args' => array('array','of','args'),
275
+	 *            'noheader' => true, //add this in if this page route is processed before any headers are loaded (i.e.
276
+	 *            ajax request, backend processing)
277
+	 *            'headers_sent_route'=>'headers_route_reference', //add this if noheader=>true, and you want to load a
278
+	 *            headers route after.  The string you enter here should match the defined route reference for a
279
+	 *            headers sent route.
280
+	 *            'capability' => 'route_capability', //indicate a string for minimum capability required to access
281
+	 *            this route.
282
+	 *            'obj_id' => 10 // if this route has an object id, then this can include it (used for capability
283
+	 *            checks).
284
+	 *        ),
285
+	 *        'insert_item' => '_method_for_handling_insert_item' //this can be used if all we need to have is a
286
+	 *        handling method.
287
+	 *        )
288
+	 * )
289
+	 *
290
+	 * @abstract
291
+	 * @return void
292
+	 */
293
+	abstract protected function _set_page_routes();
294
+
295
+
296
+
297
+	/**
298
+	 * _set_page_config
299
+	 * child classes use this to define the _page_config array for all subpages handled by the class. Each key in the
300
+	 * array corresponds to the page_route for the loaded page. Format:
301
+	 * $this->_page_config = array(
302
+	 *        'default' => array(
303
+	 *            'labels' => array(
304
+	 *                'buttons' => array(
305
+	 *                    'add' => esc_html__('label for adding item'),
306
+	 *                    'edit' => esc_html__('label for editing item'),
307
+	 *                    'delete' => esc_html__('label for deleting item')
308
+	 *                ),
309
+	 *                'publishbox' => esc_html__('Localized Title for Publish metabox', 'event_espresso')
310
+	 *            ), //optional an array of custom labels for various automatically generated elements to use on the
311
+	 *            page. If this isn't present then the defaults will be used as set for the $this->_labels in
312
+	 *            _define_page_props() method
313
+	 *            'nav' => array(
314
+	 *                'label' => esc_html__('Label for Tab', 'event_espresso').
315
+	 *                'url' => 'http://someurl', //automatically generated UNLESS you define
316
+	 *                'css_class' => 'css-class', //automatically generated UNLESS you define
317
+	 *                'order' => 10, //required to indicate tab position.
318
+	 *                'persistent' => false //if you want the nav tab to ONLY display when the specific route is
319
+	 *                displayed then add this parameter.
320
+	 *            'list_table' => 'name_of_list_table' //string for list table class to be loaded for this admin_page.
321
+	 *            'metaboxes' => array('metabox1', 'metabox2'), //if present this key indicates we want to load
322
+	 *            metaboxes set for eventespresso admin pages.
323
+	 *            'has_metaboxes' => true, //this boolean flag can simply be used to indicate if the route will have
324
+	 *            metaboxes.  Typically this is used if the 'metaboxes' index is not used because metaboxes are added
325
+	 *            later.  We just use this flag to make sure the necessary js gets enqueued on page load.
326
+	 *            'has_help_popups' => false //defaults(true) //this boolean flag can simply be used to indicate if the
327
+	 *            given route has help popups setup and if it does then we need to make sure thickbox is enqueued.
328
+	 *            'columns' => array(4, 2), //this key triggers the setup of a page that uses columns (metaboxes).  The
329
+	 *            array indicates the max number of columns (4) and the default number of columns on page load (2).
330
+	 *            There is an option in the "screen_options" dropdown that is setup so users can pick what columns they
331
+	 *            want to display.
332
+	 *            'help_tabs' => array( //this is used for adding help tabs to a page
333
+	 *                'tab_id' => array(
334
+	 *                    'title' => 'tab_title',
335
+	 *                    'filename' => 'name_of_file_containing_content', //this is the primary method for setting
336
+	 *                    help tab content.  The fallback if it isn't present is to try a the callback.  Filename
337
+	 *                    should match a file in the admin folder's "help_tabs" dir (ie..
338
+	 *                    events/help_tabs/name_of_file_containing_content.help_tab.php)
339
+	 *                    'callback' => 'callback_method_for_content', //if 'filename' isn't present then system will
340
+	 *                    attempt to use the callback which should match the name of a method in the class
341
+	 *                    ),
342
+	 *                'tab2_id' => array(
343
+	 *                    'title' => 'tab2 title',
344
+	 *                    'filename' => 'file_name_2'
345
+	 *                    'callback' => 'callback_method_for_content',
346
+	 *                 ),
347
+	 *            'help_sidebar' => 'callback_for_sidebar_content', //this is used for setting up the sidebar in the
348
+	 *            help tab area on an admin page. @link
349
+	 *            http://make.wordpress.org/core/2011/12/06/help-and-screen-api-changes-in-3-3/
350
+	 *            'help_tour' => array(
351
+	 *                'name_of_help_tour_class', //all help tours shoudl be a child class of EE_Help_Tour and located
352
+	 *                in a folder for this admin page named "help_tours", a file name matching the key given here
353
+	 *                (name_of_help_tour_class.class.php), and class matching key given here (name_of_help_tour_class)
354
+	 *            ),
355
+	 *            'require_nonce' => TRUE //this is used if you want to set a route to NOT require a nonce (default is
356
+	 *            true if it isn't present).  To remove the requirement for a nonce check when this route is visited
357
+	 *            just set
358
+	 *            'require_nonce' to FALSE
359
+	 *            )
360
+	 * )
361
+	 *
362
+	 * @abstract
363
+	 * @return void
364
+	 */
365
+	abstract protected function _set_page_config();
366
+
367
+
368
+
369
+
370
+
371
+	/** end sample help_tour methods **/
372
+	/**
373
+	 * _add_screen_options
374
+	 * Child classes can add any extra wp_screen_options within this method using built-in WP functions/methods for
375
+	 * doing so. Note child classes can also define _add_screen_options_($this->_current_view) to limit screen options
376
+	 * to a particular view.
377
+	 *
378
+	 * @link   http://chrismarslender.com/wp-tutorials/wordpress-screen-options-tutorial/
379
+	 *         see also WP_Screen object documents...
380
+	 * @link   http://codex.wordpress.org/Class_Reference/WP_Screen
381
+	 * @abstract
382
+	 * @return void
383
+	 */
384
+	abstract protected function _add_screen_options();
385
+
386
+
387
+
388
+	/**
389
+	 * _add_feature_pointers
390
+	 * Child classes should use this method for implementing any "feature pointers" (using built-in WP styling js).
391
+	 * Note child classes can also define _add_feature_pointers_($this->_current_view) to limit screen options to a
392
+	 * particular view. Note: this is just a placeholder for now.  Implementation will come down the road See:
393
+	 * WP_Internal_Pointers class in wp-admin/includes/template.php for example (its a final class so can't be
394
+	 * extended) also see:
395
+	 *
396
+	 * @link   http://eamann.com/tech/wordpress-portland/
397
+	 * @abstract
398
+	 * @return void
399
+	 */
400
+	abstract protected function _add_feature_pointers();
401
+
402
+
403
+
404
+	/**
405
+	 * load_scripts_styles
406
+	 * child classes put their wp_enqueue_script and wp_enqueue_style hooks in here for anything they need loaded for
407
+	 * their pages/subpages.  Note this is for all pages/subpages of the system.  You can also load only specific
408
+	 * scripts/styles per view by putting them in a dynamic function in this format
409
+	 * (load_scripts_styles_{$this->_current_view}) which matches your page route (action request arg)
410
+	 *
411
+	 * @abstract
412
+	 * @return void
413
+	 */
414
+	abstract public function load_scripts_styles();
415
+
416
+
417
+
418
+	/**
419
+	 * admin_init
420
+	 * Anything that should be set/executed at 'admin_init' WP hook runtime should be put in here.  This will apply to
421
+	 * all pages/views loaded by child class.
422
+	 *
423
+	 * @abstract
424
+	 * @return void
425
+	 */
426
+	abstract public function admin_init();
427
+
428
+
429
+
430
+	/**
431
+	 * admin_notices
432
+	 * Anything triggered by the 'admin_notices' WP hook should be put in here.  This particular method will apply to
433
+	 * all pages/views loaded by child class.
434
+	 *
435
+	 * @abstract
436
+	 * @return void
437
+	 */
438
+	abstract public function admin_notices();
439
+
440
+
441
+
442
+	/**
443
+	 * admin_footer_scripts
444
+	 * Anything triggered by the 'admin_print_footer_scripts' WP hook should be put in here. This particular method
445
+	 * will apply to all pages/views loaded by child class.
446
+	 *
447
+	 * @return void
448
+	 */
449
+	abstract public function admin_footer_scripts();
450
+
451
+
452
+
453
+	/**
454
+	 * admin_footer
455
+	 * anything triggered by the 'admin_footer' WP action hook should be added to here. This particular method will
456
+	 * apply to all pages/views loaded by child class.
457
+	 *
458
+	 * @return void
459
+	 */
460
+	public function admin_footer()
461
+	{
462
+	}
463
+
464
+
465
+
466
+	/**
467
+	 * _global_ajax_hooks
468
+	 * all global add_action('wp_ajax_{name_of_hook}') hooks in here.
469
+	 * Note: within the ajax callback methods.
470
+	 *
471
+	 * @abstract
472
+	 * @return void
473
+	 */
474
+	protected function _global_ajax_hooks()
475
+	{
476
+		//for lazy loading of metabox content
477
+		add_action('wp_ajax_espresso-ajax-content', array($this, 'ajax_metabox_content'), 10);
478
+	}
479
+
480
+
481
+
482
+	public function ajax_metabox_content()
483
+	{
484
+		$contentid = isset($this->_req_data['contentid']) ? $this->_req_data['contentid'] : '';
485
+		$url       = isset($this->_req_data['contenturl']) ? $this->_req_data['contenturl'] : '';
486
+		self::cached_rss_display($contentid, $url);
487
+		wp_die();
488
+	}
489
+
490
+
491
+
492
+	/**
493
+	 * _page_setup
494
+	 * Makes sure any things that need to be loaded early get handled.  We also escape early here if the page requested
495
+	 * doesn't match the object.
496
+	 *
497
+	 * @final
498
+	 * @return void
499
+	 * @throws EE_Error
500
+	 * @throws InvalidArgumentException
501
+	 * @throws ReflectionException
502
+	 * @throws InvalidDataTypeException
503
+	 * @throws InvalidInterfaceException
504
+	 */
505
+	final protected function _page_setup()
506
+	{
507
+		//requires?
508
+		//admin_init stuff - global - we're setting this REALLY early so if EE_Admin pages have to hook into other WP pages they can.  But keep in mind, not everything is available from the EE_Admin Page object at this point.
509
+		add_action('admin_init', array($this, 'admin_init_global'), 5);
510
+		//next verify if we need to load anything...
511
+		$this->_current_page = ! empty($_GET['page']) ? sanitize_key($_GET['page']) : '';
512
+		$this->page_folder   = strtolower(
513
+			str_replace(array('_Admin_Page', 'Extend_'), '', get_class($this))
514
+		);
515
+		global $ee_menu_slugs;
516
+		$ee_menu_slugs = (array)$ee_menu_slugs;
517
+		if (! defined('DOING_AJAX') && (! $this->_current_page || ! isset($ee_menu_slugs[$this->_current_page]))) {
518
+			return;
519
+		}
520
+		// becuz WP List tables have two duplicate select inputs for choosing bulk actions, we need to copy the action from the second to the first
521
+		if (isset($this->_req_data['action2']) && $this->_req_data['action'] === '-1') {
522
+			$this->_req_data['action'] = ! empty($this->_req_data['action2']) && $this->_req_data['action2'] !== '-1'
523
+				? $this->_req_data['action2']
524
+				: $this->_req_data['action'];
525
+		}
526
+		// then set blank or -1 action values to 'default'
527
+		$this->_req_action = isset($this->_req_data['action'])
528
+							 && ! empty($this->_req_data['action'])
529
+							 && $this->_req_data['action'] !== '-1'
530
+			? sanitize_key($this->_req_data['action'])
531
+			: 'default';
532
+		// if action is 'default' after the above BUT we have  'route' var set, then let's use the route as the action.
533
+		//  This covers cases where we're coming in from a list table that isn't on the default route.
534
+		$this->_req_action = $this->_req_action === 'default' && isset($this->_req_data['route'])
535
+			? $this->_req_data['route'] : $this->_req_action;
536
+		//however if we are doing_ajax and we've got a 'route' set then that's what the req_action will be
537
+		$this->_req_action   = defined('DOING_AJAX') && isset($this->_req_data['route'])
538
+			? $this->_req_data['route']
539
+			: $this->_req_action;
540
+		$this->_current_view = $this->_req_action;
541
+		$this->_req_nonce    = $this->_req_action . '_nonce';
542
+		$this->_define_page_props();
543
+		$this->_current_page_view_url = add_query_arg(
544
+			array('page' => $this->_current_page, 'action' => $this->_current_view),
545
+			$this->_admin_base_url
546
+		);
547
+		//default things
548
+		$this->_default_espresso_metaboxes = array(
549
+			'_espresso_news_post_box',
550
+			'_espresso_links_post_box',
551
+			'_espresso_ratings_request',
552
+			'_espresso_sponsors_post_box',
553
+		);
554
+		//set page configs
555
+		$this->_set_page_routes();
556
+		$this->_set_page_config();
557
+		//let's include any referrer data in our default_query_args for this route for "stickiness".
558
+		if (isset($this->_req_data['wp_referer'])) {
559
+			$this->_default_route_query_args['wp_referer'] = $this->_req_data['wp_referer'];
560
+		}
561
+		//for caffeinated and other extended functionality.
562
+		//  If there is a _extend_page_config method
563
+		// then let's run that to modify the all the various page configuration arrays
564
+		if (method_exists($this, '_extend_page_config')) {
565
+			$this->_extend_page_config();
566
+		}
567
+		//for CPT and other extended functionality.
568
+		// If there is an _extend_page_config_for_cpt
569
+		// then let's run that to modify all the various page configuration arrays.
570
+		if (method_exists($this, '_extend_page_config_for_cpt')) {
571
+			$this->_extend_page_config_for_cpt();
572
+		}
573
+		//filter routes and page_config so addons can add their stuff. Filtering done per class
574
+		$this->_page_routes = apply_filters(
575
+			'FHEE__' . get_class($this) . '__page_setup__page_routes',
576
+			$this->_page_routes,
577
+			$this
578
+		);
579
+		$this->_page_config = apply_filters(
580
+			'FHEE__' . get_class($this) . '__page_setup__page_config',
581
+			$this->_page_config,
582
+			$this
583
+		);
584
+		//if AHEE__EE_Admin_Page__route_admin_request_$this->_current_view method is present
585
+		// then we call it hooked into the AHEE__EE_Admin_Page__route_admin_request action
586
+		if (
587
+			method_exists($this, 'AHEE__EE_Admin_Page__route_admin_request_' . $this->_current_view)
588
+		) {
589
+			add_action(
590
+				'AHEE__EE_Admin_Page__route_admin_request',
591
+				array($this, 'AHEE__EE_Admin_Page__route_admin_request_' . $this->_current_view),
592
+				10,
593
+				2
594
+			);
595
+		}
596
+		//next route only if routing enabled
597
+		if ($this->_routing && ! defined('DOING_AJAX')) {
598
+			$this->_verify_routes();
599
+			//next let's just check user_access and kill if no access
600
+			$this->check_user_access();
601
+			if ($this->_is_UI_request) {
602
+				//admin_init stuff - global, all views for this page class, specific view
603
+				add_action('admin_init', array($this, 'admin_init'), 10);
604
+				if (method_exists($this, 'admin_init_' . $this->_current_view)) {
605
+					add_action('admin_init', array($this, 'admin_init_' . $this->_current_view), 15);
606
+				}
607
+			} else {
608
+				//hijack regular WP loading and route admin request immediately
609
+				@ini_set('memory_limit', apply_filters('admin_memory_limit', WP_MAX_MEMORY_LIMIT));
610
+				$this->route_admin_request();
611
+			}
612
+		}
613
+	}
614
+
615
+
616
+
617
+	/**
618
+	 * Provides a way for related child admin pages to load stuff on the loaded admin page.
619
+	 *
620
+	 * @return void
621
+	 * @throws ReflectionException
622
+	 * @throws EE_Error
623
+	 */
624
+	private function _do_other_page_hooks()
625
+	{
626
+		$registered_pages = apply_filters('FHEE_do_other_page_hooks_' . $this->page_slug, array());
627
+		foreach ($registered_pages as $page) {
628
+			//now let's setup the file name and class that should be present
629
+			$classname = str_replace('.class.php', '', $page);
630
+			//autoloaders should take care of loading file
631
+			if (! class_exists($classname)) {
632
+				$error_msg[] = sprintf(
633
+					esc_html__(
634
+						'Something went wrong with loading the %s admin hooks page.',
635
+						'event_espresso'
636
+					),
637
+					$page
638
+				);
639
+				$error_msg[] = $error_msg[0]
640
+							   . "\r\n"
641
+							   . sprintf(
642
+								   esc_html__(
643
+									   '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',
644
+									   'event_espresso'
645
+								   ),
646
+								   $page,
647
+								   '<br />',
648
+								   '<strong>' . $classname . '</strong>'
649
+							   );
650
+				throw new EE_Error(implode('||', $error_msg));
651
+			}
652
+			$a = new ReflectionClass($classname);
653
+			//notice we are passing the instance of this class to the hook object.
654
+			$hookobj[] = $a->newInstance($this);
655
+		}
656
+	}
657
+
658
+
659
+
660
+	public function load_page_dependencies()
661
+	{
662
+		try {
663
+			$this->_load_page_dependencies();
664
+		} catch (EE_Error $e) {
665
+			$e->get_error();
666
+		}
667
+	}
668
+
669
+
670
+
671
+	/**
672
+	 * load_page_dependencies
673
+	 * loads things specific to this page class when its loaded.  Really helps with efficiency.
674
+	 *
675
+	 * @return void
676
+	 * @throws DomainException
677
+	 * @throws EE_Error
678
+	 * @throws InvalidArgumentException
679
+	 * @throws InvalidDataTypeException
680
+	 * @throws InvalidInterfaceException
681
+	 * @throws ReflectionException
682
+	 */
683
+	protected function _load_page_dependencies()
684
+	{
685
+		//let's set the current_screen and screen options to override what WP set
686
+		$this->_current_screen = get_current_screen();
687
+		//load admin_notices - global, page class, and view specific
688
+		add_action('admin_notices', array($this, 'admin_notices_global'), 5);
689
+		add_action('admin_notices', array($this, 'admin_notices'), 10);
690
+		if (method_exists($this, 'admin_notices_' . $this->_current_view)) {
691
+			add_action('admin_notices', array($this, 'admin_notices_' . $this->_current_view), 15);
692
+		}
693
+		//load network admin_notices - global, page class, and view specific
694
+		add_action('network_admin_notices', array($this, 'network_admin_notices_global'), 5);
695
+		if (method_exists($this, 'network_admin_notices_' . $this->_current_view)) {
696
+			add_action('network_admin_notices', array($this, 'network_admin_notices_' . $this->_current_view));
697
+		}
698
+		//this will save any per_page screen options if they are present
699
+		$this->_set_per_page_screen_options();
700
+		//setup list table properties
701
+		$this->_set_list_table();
702
+		// child classes can "register" a metabox to be automatically handled via the _page_config array property.
703
+		// However in some cases the metaboxes will need to be added within a route handling callback.
704
+		$this->_add_registered_meta_boxes();
705
+		$this->_add_screen_columns();
706
+		//add screen options - global, page child class, and view specific
707
+		$this->_add_global_screen_options();
708
+		$this->_add_screen_options();
709
+		$add_screen_options  = "_add_screen_options_{$this->_current_view}";
710
+		if (method_exists($this, $add_screen_options )) {
711
+			$this->{$add_screen_options}();
712
+		}
713
+		//add help tab(s) and tours- set via page_config and qtips.
714
+		$this->_add_help_tour();
715
+		$this->_add_help_tabs();
716
+		$this->_add_qtips();
717
+		//add feature_pointers - global, page child class, and view specific
718
+		$this->_add_feature_pointers();
719
+		$this->_add_global_feature_pointers();
720
+		$add_feature_pointer = "_add_feature_pointer_{$this->_current_view}";
721
+		if (method_exists($this, $add_feature_pointer )) {
722
+			$this->{$add_feature_pointer}();
723
+		}
724
+		//enqueue scripts/styles - global, page class, and view specific
725
+		add_action('admin_enqueue_scripts', array($this, 'load_global_scripts_styles'), 5);
726
+		add_action('admin_enqueue_scripts', array($this, 'load_scripts_styles'), 10);
727
+		if (method_exists($this, "load_scripts_styles_{$this->_current_view}")) {
728
+			add_action('admin_enqueue_scripts', array($this, "load_scripts_styles_{$this->_current_view}"), 15);
729
+		}
730
+		add_action('admin_enqueue_scripts', array($this, 'admin_footer_scripts_eei18n_js_strings'), 100);
731
+		// admin_print_footer_scripts - global, page child class, and view specific.
732
+		// NOTE, despite the name, whenever possible, scripts should NOT be loaded using this.
733
+		// In most cases that's doing_it_wrong().  But adding hidden container elements etc.
734
+		// is a good use case. Notice the late priority we're giving these
735
+		add_action('admin_print_footer_scripts', array($this, 'admin_footer_scripts_global'), 99);
736
+		add_action('admin_print_footer_scripts', array($this, 'admin_footer_scripts'), 100);
737
+		if (method_exists($this, "admin_footer_scripts_{$this->_current_view}")) {
738
+			add_action('admin_print_footer_scripts', array($this, "admin_footer_scripts_{$this->_current_view}"), 101);
739
+		}
740
+		//admin footer scripts
741
+		add_action('admin_footer', array($this, 'admin_footer_global'), 99);
742
+		add_action('admin_footer', array($this, 'admin_footer'), 100);
743
+		if (method_exists($this, "admin_footer_{$this->_current_view}")) {
744
+			add_action('admin_footer', array($this, "admin_footer_{$this->_current_view}"), 101);
745
+		}
746
+		do_action('FHEE__EE_Admin_Page___load_page_dependencies__after_load', $this->page_slug);
747
+		//targeted hook
748
+		do_action(
749
+			"FHEE__EE_Admin_Page___load_page_dependencies__after_load__{$this->page_slug}__{$this->_req_action}"
750
+
751
+		);
752
+	}
753
+
754
+
755
+
756
+	/**
757
+	 * _set_defaults
758
+	 * This sets some global defaults for class properties.
759
+	 */
760
+	private function _set_defaults()
761
+	{
762
+		$this->_current_screen = $this->_admin_page_title = $this->_req_action = $this->_req_nonce = null;
763
+		$this->_event = $this->_template_path = $this->_column_template_path = null;
764
+		$this->_nav_tabs = $this->_views = $this->_page_routes = array();
765
+		$this->_page_config = $this->_default_route_query_args = array();
766
+		$this->_default_nav_tab_name = 'overview';
767
+		//init template args
768
+		$this->_template_args = array(
769
+			'admin_page_header'  => '',
770
+			'admin_page_content' => '',
771
+			'post_body_content'  => '',
772
+			'before_list_table'  => '',
773
+			'after_list_table'   => '',
774
+		);
775
+	}
776
+
777
+
778
+
779
+	/**
780
+	 * route_admin_request
781
+	 *
782
+	 * @see    _route_admin_request()
783
+	 * @return exception|void error
784
+	 * @throws InvalidArgumentException
785
+	 * @throws InvalidInterfaceException
786
+	 * @throws InvalidDataTypeException
787
+	 * @throws EE_Error
788
+	 * @throws ReflectionException
789
+	 */
790
+	public function route_admin_request()
791
+	{
792
+		try {
793
+			$this->_route_admin_request();
794
+		} catch (EE_Error $e) {
795
+			$e->get_error();
796
+		}
797
+	}
798
+
799
+
800
+
801
+	public function set_wp_page_slug($wp_page_slug)
802
+	{
803
+		$this->_wp_page_slug = $wp_page_slug;
804
+		//if in network admin then we need to append "-network" to the page slug. Why? Because that's how WP rolls...
805
+		if (is_network_admin()) {
806
+			$this->_wp_page_slug .= '-network';
807
+		}
808
+	}
809
+
810
+
811
+
812
+	/**
813
+	 * _verify_routes
814
+	 * All this method does is verify the incoming request and make sure that routes exist for it.  We do this early so
815
+	 * we know if we need to drop out.
816
+	 *
817
+	 * @return bool
818
+	 * @throws EE_Error
819
+	 */
820
+	protected function _verify_routes()
821
+	{
822
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
823
+		if (! $this->_current_page && ! defined('DOING_AJAX')) {
824
+			return false;
825
+		}
826
+		$this->_route = false;
827
+		// check that the page_routes array is not empty
828
+		if (empty($this->_page_routes)) {
829
+			// user error msg
830
+			$error_msg = sprintf(
831
+				esc_html__('No page routes have been set for the %s admin page.', 'event_espresso'),
832
+				$this->_admin_page_title
833
+			);
834
+			// developer error msg
835
+			$error_msg .= '||' . $error_msg . esc_html__(
836
+				' Make sure the "set_page_routes()" method exists, and is setting the "_page_routes" array properly.',
837
+				'event_espresso'
838
+			);
839
+			throw new EE_Error($error_msg);
840
+		}
841
+		// and that the requested page route exists
842
+		if (array_key_exists($this->_req_action, $this->_page_routes)) {
843
+			$this->_route        = $this->_page_routes[$this->_req_action];
844
+			$this->_route_config = isset($this->_page_config[$this->_req_action])
845
+				? $this->_page_config[$this->_req_action] : array();
846
+		} else {
847
+			// user error msg
848
+			$error_msg = sprintf(
849
+				esc_html__(
850
+						'The requested page route does not exist for the %s admin page.',
851
+						'event_espresso'
852
+				),
853
+				$this->_admin_page_title
854
+			);
855
+			// developer error msg
856
+			$error_msg .= '||' . $error_msg . sprintf(
857
+					esc_html__(
858
+						' Create a key in the "_page_routes" array named "%s" and set its value to the appropriate method.',
859
+						'event_espresso'
860
+					),
861
+					$this->_req_action
862
+				);
863
+			throw new EE_Error($error_msg);
864
+		}
865
+		// and that a default route exists
866
+		if (! array_key_exists('default', $this->_page_routes)) {
867
+			// user error msg
868
+			$error_msg = sprintf(
869
+				esc_html__(
870
+						'A default page route has not been set for the % admin page.',
871
+						'event_espresso'
872
+				),
873
+				$this->_admin_page_title
874
+			);
875
+			// developer error msg
876
+			$error_msg .= '||' . $error_msg . esc_html__(
877
+				' Create a key in the "_page_routes" array named "default" and set its value to your default page method.',
878
+				'event_espresso'
879
+			);
880
+			throw new EE_Error($error_msg);
881
+		}
882
+		//first lets' catch if the UI request has EVER been set.
883
+		if ($this->_is_UI_request === null) {
884
+			//lets set if this is a UI request or not.
885
+			$this->_is_UI_request = ! isset($this->_req_data['noheader']) || $this->_req_data['noheader'] !== true;
886
+			//wait a minute... we might have a noheader in the route array
887
+			$this->_is_UI_request = is_array($this->_route)
888
+									&& isset($this->_route['noheader'])
889
+									&& $this->_route['noheader'] ? false : $this->_is_UI_request;
890
+		}
891
+		$this->_set_current_labels();
892
+		return true;
893
+	}
894
+
895
+
896
+
897
+	/**
898
+	 * this method simply verifies a given route and makes sure its an actual route available for the loaded page
899
+	 *
900
+	 * @param  string $route the route name we're verifying
901
+	 * @return mixed (bool|Exception)      we'll throw an exception if this isn't a valid route.
902
+	 * @throws EE_Error
903
+	 */
904
+	protected function _verify_route($route)
905
+	{
906
+		if (array_key_exists($this->_req_action, $this->_page_routes)) {
907
+			return true;
908
+		}
909
+		// user error msg
910
+		$error_msg = sprintf(
911
+			esc_html__('The given page route does not exist for the %s admin page.', 'event_espresso'),
912
+			$this->_admin_page_title
913
+		);
914
+		// developer error msg
915
+		$error_msg .= '||' . $error_msg . sprintf(
916
+				esc_html__(
917
+					' Check the route you are using in your method (%s) and make sure it matches a route set in your "_page_routes" array property',
918
+					'event_espresso'
919
+				),
920
+				$route
921
+			);
922
+		throw new EE_Error($error_msg);
923
+	}
924
+
925
+
926
+
927
+	/**
928
+	 * perform nonce verification
929
+	 * This method has be encapsulated here so that any ajax requests that bypass normal routes can verify their nonces
930
+	 * using this method (and save retyping!)
931
+	 *
932
+	 * @param  string $nonce     The nonce sent
933
+	 * @param  string $nonce_ref The nonce reference string (name0)
934
+	 * @return void
935
+	 * @throws EE_Error
936
+	 */
937
+	protected function _verify_nonce($nonce, $nonce_ref)
938
+	{
939
+		// verify nonce against expected value
940
+		if (! wp_verify_nonce($nonce, $nonce_ref)) {
941
+			// these are not the droids you are looking for !!!
942
+			$msg = sprintf(
943
+				esc_html__('%sNonce Fail.%s', 'event_espresso'),
944
+				'<a href="http://www.youtube.com/watch?v=56_S0WeTkzs">',
945
+				'</a>'
946
+			);
947
+			if (WP_DEBUG) {
948
+				$msg .= "\n  " . sprintf(
949
+						esc_html__(
950
+							'In order to dynamically generate nonces for your actions, use the %s::add_query_args_and_nonce() method. May the Nonce be with you!',
951
+							'event_espresso'
952
+						),
953
+						__CLASS__
954
+					);
955
+			}
956
+			if (! defined('DOING_AJAX')) {
957
+				wp_die($msg);
958
+			} else {
959
+				EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
960
+				$this->_return_json();
961
+			}
962
+		}
963
+	}
964
+
965
+
966
+
967
+	/**
968
+	 * _route_admin_request()
969
+	 * Meat and potatoes of the class.  Basically, this dude checks out what's being requested and sees if theres are
970
+	 * some doodads to work the magic and handle the flingjangy. Translation:  Checks if the requested action is listed
971
+	 * in the page routes and then will try to load the corresponding method.
972
+	 *
973
+	 * @return void
974
+	 * @throws EE_Error
975
+	 * @throws InvalidArgumentException
976
+	 * @throws InvalidDataTypeException
977
+	 * @throws InvalidInterfaceException
978
+	 * @throws ReflectionException
979
+	 */
980
+	protected function _route_admin_request()
981
+	{
982
+		if (! $this->_is_UI_request) {
983
+			$this->_verify_routes();
984
+		}
985
+		$nonce_check = isset($this->_route_config['require_nonce'])
986
+			? $this->_route_config['require_nonce']
987
+			: true;
988
+		if ($this->_req_action !== 'default' && $nonce_check) {
989
+			// set nonce from post data
990
+			$nonce = isset($this->_req_data[$this->_req_nonce])
991
+				? sanitize_text_field($this->_req_data[$this->_req_nonce])
992
+				: '';
993
+			$this->_verify_nonce($nonce, $this->_req_nonce);
994
+		}
995
+		//set the nav_tabs array but ONLY if this is  UI_request
996
+		if ($this->_is_UI_request) {
997
+			$this->_set_nav_tabs();
998
+		}
999
+		// grab callback function
1000
+		$func = is_array($this->_route) ? $this->_route['func'] : $this->_route;
1001
+		// check if callback has args
1002
+		$args      = is_array($this->_route) && isset($this->_route['args']) ? $this->_route['args'] : array();
1003
+		$error_msg = '';
1004
+		// action right before calling route
1005
+		// (hook is something like 'AHEE__Registrations_Admin_Page__route_admin_request')
1006
+		if (! did_action('AHEE__EE_Admin_Page__route_admin_request')) {
1007
+			do_action('AHEE__EE_Admin_Page__route_admin_request', $this->_current_view, $this);
1008
+		}
1009
+		// right before calling the route, let's remove _wp_http_referer from the
1010
+		// $_SERVER[REQUEST_URI] global (its now in _req_data for route processing).
1011
+		$_SERVER['REQUEST_URI'] = remove_query_arg(
1012
+				'_wp_http_referer',
1013
+				wp_unslash($_SERVER['REQUEST_URI'])
1014
+		);
1015
+		if (! empty($func)) {
1016
+			if (is_array($func)) {
1017
+				list($class, $method) = $func;
1018
+			} elseif (strpos($func, '::') !== false) {
1019
+				list($class, $method) = explode('::', $func);
1020
+			} else {
1021
+				$class  = $this;
1022
+				$method = $func;
1023
+			}
1024
+			if (! (is_object($class) && $class === $this)) {
1025
+				// send along this admin page object for access by addons.
1026
+				$args['admin_page_object'] = $this;
1027
+			}
1028
+			if (
1029
+				//is it a method on a class that doesn't work?
1030
+				(
1031
+					(
1032
+						method_exists($class, $method)
1033
+						&& call_user_func_array(array($class, $method), $args) === false
1034
+					)
1035
+					&& (
1036
+						//is it a standalone function that doesn't work?
1037
+						function_exists($method)
1038
+						&& call_user_func_array(
1039
+							$func,
1040
+							array_merge(array('admin_page_object' => $this), $args)
1041
+						   ) === false
1042
+					)
1043
+				)
1044
+				|| (
1045
+					//is it neither a class method NOR a standalone function?
1046
+					! method_exists($class, $method)
1047
+					&& ! function_exists($method)
1048
+				)
1049
+			) {
1050
+				// user error msg
1051
+				$error_msg = esc_html__(
1052
+					'An error occurred. The  requested page route could not be found.',
1053
+					'event_espresso'
1054
+				);
1055
+				// developer error msg
1056
+				$error_msg .= '||';
1057
+				$error_msg .= sprintf(
1058
+					esc_html__(
1059
+						'Page route "%s" could not be called. Check that the spelling for method names and actions in the "_page_routes" array are all correct.',
1060
+						'event_espresso'
1061
+					),
1062
+					$method
1063
+				);
1064
+			}
1065
+			if (! empty($error_msg)) {
1066
+				throw new EE_Error($error_msg);
1067
+			}
1068
+		}
1069
+		// if we've routed and this route has a no headers route AND a sent_headers_route,
1070
+		// then we need to reset the routing properties to the new route.
1071
+		//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.
1072
+		if ($this->_is_UI_request === false
1073
+			&& is_array($this->_route)
1074
+			&& ! empty($this->_route['headers_sent_route'])
1075
+		) {
1076
+			$this->_reset_routing_properties($this->_route['headers_sent_route']);
1077
+		}
1078
+	}
1079
+
1080
+
1081
+
1082
+	/**
1083
+	 * This method just allows the resetting of page properties in the case where a no headers
1084
+	 * route redirects to a headers route in its route config.
1085
+	 *
1086
+	 * @since   4.3.0
1087
+	 * @param  string $new_route New (non header) route to redirect to.
1088
+	 * @return   void
1089
+	 * @throws ReflectionException
1090
+	 * @throws InvalidArgumentException
1091
+	 * @throws InvalidInterfaceException
1092
+	 * @throws InvalidDataTypeException
1093
+	 * @throws EE_Error
1094
+	 */
1095
+	protected function _reset_routing_properties($new_route)
1096
+	{
1097
+		$this->_is_UI_request = true;
1098
+		//now we set the current route to whatever the headers_sent_route is set at
1099
+		$this->_req_data['action'] = $new_route;
1100
+		//rerun page setup
1101
+		$this->_page_setup();
1102
+	}
1103
+
1104
+
1105
+
1106
+	/**
1107
+	 * _add_query_arg
1108
+	 * adds nonce to array of arguments then calls WP add_query_arg function
1109
+	 *(internally just uses EEH_URL's function with the same name)
1110
+	 *
1111
+	 * @param array  $args
1112
+	 * @param string $url
1113
+	 * @param bool   $sticky                  if true, then the existing Request params will be appended to the
1114
+	 *                                        generated url in an associative array indexed by the key 'wp_referer';
1115
+	 *                                        Example usage: If the current page is:
1116
+	 *                                        http://mydomain.com/wp-admin/admin.php?page=espresso_registrations
1117
+	 *                                        &action=default&event_id=20&month_range=March%202015
1118
+	 *                                        &_wpnonce=5467821
1119
+	 *                                        and you call:
1120
+	 *                                        EE_Admin_Page::add_query_args_and_nonce(
1121
+	 *                                        array(
1122
+	 *                                        'action' => 'resend_something',
1123
+	 *                                        'page=>espresso_registrations'
1124
+	 *                                        ),
1125
+	 *                                        $some_url,
1126
+	 *                                        true
1127
+	 *                                        );
1128
+	 *                                        It will produce a url in this structure:
1129
+	 *                                        http://{$some_url}/?page=espresso_registrations&action=resend_something
1130
+	 *                                        &wp_referer[action]=default&wp_referer[event_id]=20&wpreferer[
1131
+	 *                                        month_range]=March%202015
1132
+	 * @param   bool $exclude_nonce           If true, the the nonce will be excluded from the generated nonce.
1133
+	 * @return string
1134
+	 */
1135
+	public static function add_query_args_and_nonce(
1136
+		$args = array(),
1137
+		$url = false,
1138
+		$sticky = false,
1139
+		$exclude_nonce = false
1140
+	) {
1141
+		//if there is a _wp_http_referer include the values from the request but only if sticky = true
1142
+		if ($sticky) {
1143
+			$request = $_REQUEST;
1144
+			unset($request['_wp_http_referer']);
1145
+			unset($request['wp_referer']);
1146
+			foreach ($request as $key => $value) {
1147
+				//do not add nonces
1148
+				if (strpos($key, 'nonce') !== false) {
1149
+					continue;
1150
+				}
1151
+				$args['wp_referer[' . $key . ']'] = $value;
1152
+			}
1153
+		}
1154
+		return EEH_URL::add_query_args_and_nonce($args, $url, $exclude_nonce);
1155
+	}
1156
+
1157
+
1158
+
1159
+	/**
1160
+	 * This returns a generated link that will load the related help tab.
1161
+	 *
1162
+	 * @param  string $help_tab_id the id for the connected help tab
1163
+	 * @param  string $icon_style  (optional) include css class for the style you want to use for the help icon.
1164
+	 * @param  string $help_text   (optional) send help text you want to use for the link if default not to be used
1165
+	 * @uses EEH_Template::get_help_tab_link()
1166
+	 * @return string              generated link
1167
+	 */
1168
+	protected function _get_help_tab_link($help_tab_id, $icon_style = '', $help_text = '')
1169
+	{
1170
+		return EEH_Template::get_help_tab_link(
1171
+			$help_tab_id,
1172
+			$this->page_slug,
1173
+			$this->_req_action,
1174
+			$icon_style,
1175
+			$help_text
1176
+		);
1177
+	}
1178
+
1179
+
1180
+
1181
+	/**
1182
+	 * _add_help_tabs
1183
+	 * Note child classes define their help tabs within the page_config array.
1184
+	 *
1185
+	 * @link   http://codex.wordpress.org/Function_Reference/add_help_tab
1186
+	 * @return void
1187
+	 * @throws DomainException
1188
+	 * @throws EE_Error
1189
+	 */
1190
+	protected function _add_help_tabs()
1191
+	{
1192
+		$tour_buttons = '';
1193
+		if (isset($this->_page_config[$this->_req_action])) {
1194
+			$config = $this->_page_config[$this->_req_action];
1195
+			//is there a help tour for the current route?  if there is let's setup the tour buttons
1196
+			if (isset($this->_help_tour[$this->_req_action])) {
1197
+				$tb           = array();
1198
+				$tour_buttons = '<div class="ee-abs-container"><div class="ee-help-tour-restart-buttons">';
1199
+				foreach ($this->_help_tour['tours'] as $tour) {
1200
+					//if this is the end tour then we don't need to setup a button
1201
+					if ($tour instanceof EE_Help_Tour_final_stop || ! $tour instanceof EE_Help_Tour) {
1202
+						continue;
1203
+					}
1204
+					$tb[] = '<button id="trigger-tour-'
1205
+							. $tour->get_slug()
1206
+							. '" class="button-primary trigger-ee-help-tour">'
1207
+							. $tour->get_label()
1208
+							. '</button>';
1209
+				}
1210
+				$tour_buttons .= implode('<br />', $tb);
1211
+				$tour_buttons .= '</div></div>';
1212
+			}
1213
+			// let's see if there is a help_sidebar set for the current route and we'll set that up for usage as well.
1214
+			if (is_array($config) && isset($config['help_sidebar'])) {
1215
+				//check that the callback given is valid
1216
+				if (! method_exists($this, $config['help_sidebar'])) {
1217
+					throw new EE_Error(
1218
+						sprintf(
1219
+							esc_html__(
1220
+								'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',
1221
+								'event_espresso'
1222
+							),
1223
+							$config['help_sidebar'],
1224
+							get_class($this)
1225
+						)
1226
+					);
1227
+				}
1228
+				$content = apply_filters(
1229
+					'FHEE__' . get_class($this) . '__add_help_tabs__help_sidebar',
1230
+					$this->{$config['help_sidebar']}()
1231
+				);
1232
+				$content .= $tour_buttons; //add help tour buttons.
1233
+				//do we have any help tours setup?  Cause if we do we want to add the buttons
1234
+				$this->_current_screen->set_help_sidebar($content);
1235
+			}
1236
+			//if we DON'T have config help sidebar and there ARE tour buttons then we'll just add the tour buttons to the sidebar.
1237
+			if (! isset($config['help_sidebar']) && ! empty($tour_buttons)) {
1238
+				$this->_current_screen->set_help_sidebar($tour_buttons);
1239
+			}
1240
+			//handle if no help_tabs are set so the sidebar will still show for the help tour buttons
1241
+			if (! isset($config['help_tabs']) && ! empty($tour_buttons)) {
1242
+				$_ht['id']      = $this->page_slug;
1243
+				$_ht['title']   = esc_html__('Help Tours', 'event_espresso');
1244
+				$_ht['content'] = '<p>' . esc_html__(
1245
+						'The buttons to the right allow you to start/restart any help tours available for this page',
1246
+						'event_espresso'
1247
+					) . '</p>';
1248
+				$this->_current_screen->add_help_tab($_ht);
1249
+			}
1250
+			if (! isset($config['help_tabs'])) {
1251
+				return;
1252
+			} //no help tabs for this route
1253
+			foreach ((array)$config['help_tabs'] as $tab_id => $cfg) {
1254
+				//we're here so there ARE help tabs!
1255
+				//make sure we've got what we need
1256
+				if (! isset($cfg['title'])) {
1257
+					throw new EE_Error(
1258
+						esc_html__(
1259
+							'The _page_config array is not set up properly for help tabs.  It is missing a title',
1260
+							'event_espresso'
1261
+						)
1262
+					);
1263
+				}
1264
+				if (! isset($cfg['filename']) && ! isset($cfg['callback']) && ! isset($cfg['content'])) {
1265
+					throw new EE_Error(
1266
+						esc_html__(
1267
+							'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',
1268
+							'event_espresso'
1269
+						)
1270
+					);
1271
+				}
1272
+				//first priority goes to content.
1273
+				if (! empty($cfg['content'])) {
1274
+					$content = ! empty($cfg['content']) ? $cfg['content'] : null;
1275
+					//second priority goes to filename
1276
+				} elseif (! empty($cfg['filename'])) {
1277
+					$file_path = $this->_get_dir() . '/help_tabs/' . $cfg['filename'] . '.help_tab.php';
1278
+					//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)
1279
+					$file_path = ! is_readable($file_path) ? EE_ADMIN_PAGES
1280
+															 . basename($this->_get_dir())
1281
+															 . '/help_tabs/'
1282
+															 . $cfg['filename']
1283
+															 . '.help_tab.php' : $file_path;
1284
+					//if file is STILL not readable then let's do a EE_Error so its more graceful than a fatal error.
1285
+					if (! isset($cfg['callback']) && ! is_readable($file_path)) {
1286
+						EE_Error::add_error(
1287
+							sprintf(
1288
+								esc_html__(
1289
+									'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',
1290
+									'event_espresso'
1291
+								),
1292
+								$tab_id,
1293
+								key($config),
1294
+								$file_path
1295
+							),
1296
+							__FILE__,
1297
+							__FUNCTION__,
1298
+							__LINE__
1299
+						);
1300
+						return;
1301
+					}
1302
+					$template_args['admin_page_obj'] = $this;
1303
+					$content = EEH_Template::display_template(
1304
+						$file_path,
1305
+						$template_args,
1306
+						true
1307
+					);
1308
+				} else {
1309
+					$content = '';
1310
+				}
1311
+				//check if callback is valid
1312
+				if (
1313
+					empty($content) && (
1314
+						! isset($cfg['callback']) || ! method_exists($this, $cfg['callback'])
1315
+					)
1316
+				) {
1317
+					EE_Error::add_error(
1318
+						sprintf(
1319
+							esc_html__(
1320
+								'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.',
1321
+								'event_espresso'
1322
+							),
1323
+							$cfg['title']
1324
+						),
1325
+						__FILE__,
1326
+						__FUNCTION__,
1327
+						__LINE__
1328
+					);
1329
+					return;
1330
+				}
1331
+				//setup config array for help tab method
1332
+				$id  = $this->page_slug . '-' . $this->_req_action . '-' . $tab_id;
1333
+				$_ht = array(
1334
+					'id'       => $id,
1335
+					'title'    => $cfg['title'],
1336
+					'callback' => isset($cfg['callback']) && empty($content) ? array($this, $cfg['callback']) : null,
1337
+					'content'  => $content,
1338
+				);
1339
+				$this->_current_screen->add_help_tab($_ht);
1340
+			}
1341
+		}
1342
+	}
1343
+
1344
+
1345
+
1346
+	/**
1347
+	 * This basically checks loaded $_page_config property to see if there are any help_tours defined.  "help_tours" is
1348
+	 * an array with properties for setting up usage of the joyride plugin
1349
+	 *
1350
+	 * @link   http://zurb.com/playground/jquery-joyride-feature-tour-plugin
1351
+	 * @see    instructions regarding the format and construction of the "help_tour" array element is found in the
1352
+	 *         _set_page_config() comments
1353
+	 * @return void
1354
+	 * @throws EE_Error
1355
+	 * @throws InvalidArgumentException
1356
+	 * @throws InvalidDataTypeException
1357
+	 * @throws InvalidInterfaceException
1358
+	 */
1359
+	protected function _add_help_tour()
1360
+	{
1361
+		$tours            = array();
1362
+		$this->_help_tour = array();
1363
+		//exit early if help tours are turned off globally
1364
+		if ((defined('EE_DISABLE_HELP_TOURS') && EE_DISABLE_HELP_TOURS)
1365
+			|| ! EE_Registry::instance()->CFG->admin->help_tour_activation
1366
+		) {
1367
+			return;
1368
+		}
1369
+		//loop through _page_config to find any help_tour defined
1370
+		foreach ($this->_page_config as $route => $config) {
1371
+			//we're only going to set things up for this route
1372
+			if ($route !== $this->_req_action) {
1373
+				continue;
1374
+			}
1375
+			if (isset($config['help_tour'])) {
1376
+				foreach ($config['help_tour'] as $tour) {
1377
+					$file_path = $this->_get_dir() . '/help_tours/' . $tour . '.class.php';
1378
+					// let's see if we can get that file...
1379
+					// if not its possible this is a decaf route not set in caffeinated
1380
+					// so lets try and get the caffeinated equivalent
1381
+					$file_path = ! is_readable($file_path) ? EE_ADMIN_PAGES
1382
+															 . basename($this->_get_dir())
1383
+															 . '/help_tours/'
1384
+															 . $tour
1385
+															 . '.class.php' : $file_path;
1386
+					//if file is STILL not readable then let's do a EE_Error so its more graceful than a fatal error.
1387
+					if (! is_readable($file_path)) {
1388
+						EE_Error::add_error(
1389
+							sprintf(
1390
+								esc_html__(
1391
+									'The file path given for the help tour (%s) is not a valid path.  Please check that the string you set for the help tour on this route (%s) is the correct spelling',
1392
+									'event_espresso'
1393
+								),
1394
+								$file_path,
1395
+								$tour
1396
+							),
1397
+							__FILE__,
1398
+							__FUNCTION__,
1399
+							__LINE__
1400
+						);
1401
+						return;
1402
+					}
1403
+					require_once $file_path;
1404
+					if (! class_exists($tour)) {
1405
+						$error_msg[] = sprintf(
1406
+							esc_html__('Something went wrong with loading the %s Help Tour Class.', 'event_espresso'),
1407
+							$tour
1408
+						);
1409
+						$error_msg[] = $error_msg[0] . "\r\n" . sprintf(
1410
+								esc_html__(
1411
+									'There is no class in place for the %s help tour.%s Make sure you have <strong>%s</strong> defined in the "help_tour" array for the %s route of the % admin page.',
1412
+									'event_espresso'
1413
+								),
1414
+								$tour,
1415
+								'<br />',
1416
+								$tour,
1417
+								$this->_req_action,
1418
+								get_class($this)
1419
+							);
1420
+						throw new EE_Error(implode('||', $error_msg));
1421
+					}
1422
+					$tour_obj                   = new $tour($this->_is_caf);
1423
+					$tours[]                    = $tour_obj;
1424
+					$this->_help_tour[$route][] = EEH_Template::help_tour_stops_generator($tour_obj);
1425
+				}
1426
+				//let's inject the end tour stop element common to all pages... this will only get seen once per machine.
1427
+				$end_stop_tour              = new EE_Help_Tour_final_stop($this->_is_caf);
1428
+				$tours[]                    = $end_stop_tour;
1429
+				$this->_help_tour[$route][] = EEH_Template::help_tour_stops_generator($end_stop_tour);
1430
+			}
1431
+		}
1432
+		if (! empty($tours)) {
1433
+			$this->_help_tour['tours'] = $tours;
1434
+		}
1435
+		// that's it!  Now that the $_help_tours property is set (or not)
1436
+		// the scripts and html should be taken care of automatically.
1437
+	}
1438
+
1439
+
1440
+
1441
+	/**
1442
+	 * This simply sets up any qtips that have been defined in the page config
1443
+	 *
1444
+	 * @return void
1445
+	 */
1446
+	protected function _add_qtips()
1447
+	{
1448
+		if (isset($this->_route_config['qtips'])) {
1449
+			$qtips = (array)$this->_route_config['qtips'];
1450
+			//load qtip loader
1451
+			$path = array(
1452
+				$this->_get_dir() . '/qtips/',
1453
+				EE_ADMIN_PAGES . basename($this->_get_dir()) . '/qtips/',
1454
+			);
1455
+			EEH_Qtip_Loader::instance()->register($qtips, $path);
1456
+		}
1457
+	}
1458
+
1459
+
1460
+
1461
+	/**
1462
+	 * _set_nav_tabs
1463
+	 * This sets up the nav tabs from the page_routes array.  This method can be overwritten by child classes if you
1464
+	 * wish to add additional tabs or modify accordingly.
1465
+	 *
1466
+	 * @return void
1467
+	 * @throws InvalidArgumentException
1468
+	 * @throws InvalidInterfaceException
1469
+	 * @throws InvalidDataTypeException
1470
+	 */
1471
+	protected function _set_nav_tabs()
1472
+	{
1473
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
1474
+		$i = 0;
1475
+		foreach ($this->_page_config as $slug => $config) {
1476
+			if (
1477
+				! is_array($config)
1478
+				|| (
1479
+					is_array($config)
1480
+					&& (
1481
+						(isset($config['nav']) && ! $config['nav'])
1482
+						|| ! isset($config['nav'])
1483
+					)
1484
+				)
1485
+			) {
1486
+				continue;
1487
+			}
1488
+			//no nav tab for this config
1489
+			//check for persistent flag
1490
+			if ($slug !== $this->_req_action && isset($config['nav']['persistent']) && ! $config['nav']['persistent']) {
1491
+				// nav tab is only to appear when route requested.
1492
+				continue;
1493
+			}
1494
+			if (! $this->check_user_access($slug, true)) {
1495
+				// no nav tab because current user does not have access.
1496
+				continue;
1497
+			}
1498
+			$css_class              = isset($config['css_class']) ? $config['css_class'] . ' ' : '';
1499
+			$this->_nav_tabs[$slug] = array(
1500
+				'url'       => isset($config['nav']['url'])
1501
+					? $config['nav']['url']
1502
+					: self::add_query_args_and_nonce(
1503
+						array('action' => $slug),
1504
+						$this->_admin_base_url
1505
+					),
1506
+				'link_text' => isset($config['nav']['label'])
1507
+					? $config['nav']['label']
1508
+					: ucwords(
1509
+						str_replace('_', ' ', $slug)
1510
+					),
1511
+				'css_class' => $this->_req_action === $slug ? $css_class . 'nav-tab-active' : $css_class,
1512
+				'order'     => isset($config['nav']['order']) ? $config['nav']['order'] : $i,
1513
+			);
1514
+			$i++;
1515
+		}
1516
+		//if $this->_nav_tabs is empty then lets set the default
1517
+		if (empty($this->_nav_tabs)) {
1518
+			$this->_nav_tabs[$this->_default_nav_tab_name] = array(
1519
+				'url'       => $this->_admin_base_url,
1520
+				'link_text' => ucwords(str_replace('_', ' ', $this->_default_nav_tab_name)),
1521
+				'css_class' => 'nav-tab-active',
1522
+				'order'     => 10,
1523
+			);
1524
+		}
1525
+		//now let's sort the tabs according to order
1526
+		usort($this->_nav_tabs, array($this, '_sort_nav_tabs'));
1527
+	}
1528
+
1529
+
1530
+
1531
+	/**
1532
+	 * _set_current_labels
1533
+	 * This method modifies the _labels property with any optional specific labels indicated in the _page_routes
1534
+	 * property array
1535
+	 *
1536
+	 * @return void
1537
+	 */
1538
+	private function _set_current_labels()
1539
+	{
1540
+		if (is_array($this->_route_config) && isset($this->_route_config['labels'])) {
1541
+			foreach ($this->_route_config['labels'] as $label => $text) {
1542
+				if (is_array($text)) {
1543
+					foreach ($text as $sublabel => $subtext) {
1544
+						$this->_labels[$label][$sublabel] = $subtext;
1545
+					}
1546
+				} else {
1547
+					$this->_labels[$label] = $text;
1548
+				}
1549
+			}
1550
+		}
1551
+	}
1552
+
1553
+
1554
+
1555
+	/**
1556
+	 *        verifies user access for this admin page
1557
+	 *
1558
+	 * @param string $route_to_check if present then the capability for the route matching this string is checked.
1559
+	 * @param bool   $verify_only    Default is FALSE which means if user check fails then wp_die().  Otherwise just
1560
+	 *                               return false if verify fail.
1561
+	 * @return bool
1562
+	 * @throws InvalidArgumentException
1563
+	 * @throws InvalidDataTypeException
1564
+	 * @throws InvalidInterfaceException
1565
+	 */
1566
+	public function check_user_access($route_to_check = '', $verify_only = false)
1567
+	{
1568
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
1569
+		$route_to_check = empty($route_to_check) ? $this->_req_action : $route_to_check;
1570
+		$capability     = ! empty($route_to_check) && isset($this->_page_routes[$route_to_check])
1571
+						  && is_array(
1572
+							  $this->_page_routes[$route_to_check]
1573
+						  )
1574
+						  && ! empty($this->_page_routes[$route_to_check]['capability'])
1575
+			? $this->_page_routes[$route_to_check]['capability'] : null;
1576
+		if (empty($capability) && empty($route_to_check)) {
1577
+			$capability = is_array($this->_route) && empty($this->_route['capability']) ? 'manage_options'
1578
+				: $this->_route['capability'];
1579
+		} else {
1580
+			$capability = empty($capability) ? 'manage_options' : $capability;
1581
+		}
1582
+		$id = is_array($this->_route) && ! empty($this->_route['obj_id']) ? $this->_route['obj_id'] : 0;
1583
+		if (
1584
+			! defined('DOING_AJAX')
1585
+			&& (
1586
+				! function_exists('is_admin')
1587
+				|| ! EE_Registry::instance()->CAP->current_user_can(
1588
+					$capability,
1589
+					$this->page_slug
1590
+					. '_'
1591
+					. $route_to_check,
1592
+					$id
1593
+				)
1594
+			)
1595
+		) {
1596
+			if ($verify_only) {
1597
+				return false;
1598
+			}
1599
+			if (is_user_logged_in()) {
1600
+				wp_die(__('You do not have access to this route.', 'event_espresso'));
1601
+			} else {
1602
+				return false;
1603
+			}
1604
+		}
1605
+		return true;
1606
+	}
1607
+
1608
+
1609
+
1610
+	/**
1611
+	 * admin_init_global
1612
+	 * This runs all the code that we want executed within the WP admin_init hook.
1613
+	 * This method executes for ALL EE Admin pages.
1614
+	 *
1615
+	 * @return void
1616
+	 */
1617
+	public function admin_init_global()
1618
+	{
1619
+	}
1620
+
1621
+
1622
+
1623
+	/**
1624
+	 * wp_loaded_global
1625
+	 * This runs all the code that we want executed within the WP wp_loaded hook.  This method is optional for an
1626
+	 * EE_Admin page and will execute on every EE Admin Page load
1627
+	 *
1628
+	 * @return void
1629
+	 */
1630
+	public function wp_loaded()
1631
+	{
1632
+	}
1633
+
1634
+
1635
+
1636
+	/**
1637
+	 * admin_notices
1638
+	 * Anything triggered by the 'admin_notices' WP hook should be put in here.  This particular method will apply on
1639
+	 * ALL EE_Admin pages.
1640
+	 *
1641
+	 * @return void
1642
+	 */
1643
+	public function admin_notices_global()
1644
+	{
1645
+		$this->_display_no_javascript_warning();
1646
+		$this->_display_espresso_notices();
1647
+	}
1648
+
1649
+
1650
+
1651
+	public function network_admin_notices_global()
1652
+	{
1653
+		$this->_display_no_javascript_warning();
1654
+		$this->_display_espresso_notices();
1655
+	}
1656
+
1657
+
1658
+
1659
+	/**
1660
+	 * admin_footer_scripts_global
1661
+	 * Anything triggered by the 'admin_print_footer_scripts' WP hook should be put in here. This particular method
1662
+	 * will apply on ALL EE_Admin pages.
1663
+	 *
1664
+	 * @return void
1665
+	 */
1666
+	public function admin_footer_scripts_global()
1667
+	{
1668
+		$this->_add_admin_page_ajax_loading_img();
1669
+		$this->_add_admin_page_overlay();
1670
+		//if metaboxes are present we need to add the nonce field
1671
+		if (
1672
+			 isset($this->_route_config['metaboxes'])
1673
+			 || isset($this->_route_config['list_table'])
1674
+			 || (isset($this->_route_config['has_metaboxes']) && $this->_route_config['has_metaboxes'])
1675
+		) {
1676
+			wp_nonce_field('closedpostboxes', 'closedpostboxesnonce', false);
1677
+			wp_nonce_field('meta-box-order', 'meta-box-order-nonce', false);
1678
+		}
1679
+	}
1680
+
1681
+
1682
+
1683
+	/**
1684
+	 * admin_footer_global
1685
+	 * Anything triggered by the wp 'admin_footer' wp hook should be put in here. This particular method will apply on
1686
+	 * ALL EE_Admin Pages.
1687
+	 *
1688
+	 * @return void
1689
+	 * @throws EE_Error
1690
+	 */
1691
+	public function admin_footer_global()
1692
+	{
1693
+		//dialog container for dialog helper
1694
+		$d_cont = '<div class="ee-admin-dialog-container auto-hide hidden">' . "\n";
1695
+		$d_cont .= '<div class="ee-notices"></div>';
1696
+		$d_cont .= '<div class="ee-admin-dialog-container-inner-content"></div>';
1697
+		$d_cont .= '</div>';
1698
+		echo $d_cont;
1699
+		//help tour stuff?
1700
+		if (isset($this->_help_tour[$this->_req_action])) {
1701
+			echo implode('<br />', $this->_help_tour[$this->_req_action]);
1702
+		}
1703
+		//current set timezone for timezone js
1704
+		echo '<span id="current_timezone" class="hidden">' . EEH_DTT_Helper::get_timezone() . '</span>';
1705
+	}
1706
+
1707
+
1708
+
1709
+	/**
1710
+	 * This function sees if there is a method for help popup content existing for the given route.  If there is then
1711
+	 * we'll use the retrieved array to output the content using the template. For child classes: If you want to have
1712
+	 * help popups then in your templates or your content you set "triggers" for the content using the
1713
+	 * "_set_help_trigger('help_trigger_id')" where "help_trigger_id" is what you will use later in your custom method
1714
+	 * for the help popup content on that page. Then in your Child_Admin_Page class you need to define a help popup
1715
+	 * method for the content in the format "_help_popup_content_{route_name}()"  So if you are setting help content
1716
+	 * for the
1717
+	 * 'edit_event' route you should have a method named "_help_popup_content_edit_route". In your defined
1718
+	 * "help_popup_content_..." method.  You must prepare and return an array in the following format array(
1719
+	 *    'help_trigger_id' => array(
1720
+	 *        'title' => esc_html__('localized title for popup', 'event_espresso'),
1721
+	 *        'content' => esc_html__('localized content for popup', 'event_espresso')
1722
+	 *    )
1723
+	 * );
1724
+	 * Then the EE_Admin_Parent will take care of making sure that is setup properly on the correct route.
1725
+	 *
1726
+	 * @param array $help_array
1727
+	 * @param bool  $display
1728
+	 * @return string content
1729
+	 * @throws DomainException
1730
+	 * @throws EE_Error
1731
+	 */
1732
+	protected function _set_help_popup_content($help_array = array(), $display = false)
1733
+	{
1734
+		$content       = '';
1735
+		$help_array    = empty($help_array) ? $this->_get_help_content() : $help_array;
1736
+		//loop through the array and setup content
1737
+		foreach ($help_array as $trigger => $help) {
1738
+			//make sure the array is setup properly
1739
+			if (! isset($help['title']) || ! isset($help['content'])) {
1740
+				throw new EE_Error(
1741
+					esc_html__(
1742
+						'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',
1743
+						'event_espresso'
1744
+					)
1745
+				);
1746
+			}
1747
+			//we're good so let'd setup the template vars and then assign parsed template content to our content.
1748
+			$template_args = array(
1749
+				'help_popup_id'      => $trigger,
1750
+				'help_popup_title'   => $help['title'],
1751
+				'help_popup_content' => $help['content'],
1752
+			);
1753
+			$content       .= EEH_Template::display_template(
1754
+				EE_ADMIN_TEMPLATE . 'admin_help_popup.template.php',
1755
+				$template_args,
1756
+				true
1757
+			);
1758
+		}
1759
+		if ($display) {
1760
+			echo $content;
1761
+			return '';
1762
+		}
1763
+		return $content;
1764
+	}
1765
+
1766
+
1767
+
1768
+	/**
1769
+	 * All this does is retrieve the help content array if set by the EE_Admin_Page child
1770
+	 *
1771
+	 * @return array properly formatted array for help popup content
1772
+	 * @throws EE_Error
1773
+	 */
1774
+	private function _get_help_content()
1775
+	{
1776
+		//what is the method we're looking for?
1777
+		$method_name = '_help_popup_content_' . $this->_req_action;
1778
+		//if method doesn't exist let's get out.
1779
+		if (! method_exists($this, $method_name)) {
1780
+			return array();
1781
+		}
1782
+		//k we're good to go let's retrieve the help array
1783
+		$help_array = call_user_func(array($this, $method_name));
1784
+		//make sure we've got an array!
1785
+		if (! is_array($help_array)) {
1786
+			throw new EE_Error(
1787
+				esc_html__(
1788
+					'Something went wrong with help popup content generation. Expecting an array and well, this ain\'t no array bub.',
1789
+					'event_espresso'
1790
+				)
1791
+			);
1792
+		}
1793
+		return $help_array;
1794
+	}
1795
+
1796
+
1797
+
1798
+	/**
1799
+	 * EE Admin Pages can use this to set a properly formatted trigger for a help popup.
1800
+	 * By default the trigger html is printed.  Otherwise it can be returned if the $display flag is set "false"
1801
+	 * See comments made on the _set_help_content method for understanding other parts to the help popup tool.
1802
+	 *
1803
+	 * @param string  $trigger_id reference for retrieving the trigger content for the popup
1804
+	 * @param boolean $display    if false then we return the trigger string
1805
+	 * @param array   $dimensions an array of dimensions for the box (array(h,w))
1806
+	 * @return string
1807
+	 * @throws DomainException
1808
+	 * @throws EE_Error
1809
+	 */
1810
+	protected function _set_help_trigger($trigger_id, $display = true, $dimensions = array('400', '640'))
1811
+	{
1812
+		if (defined('DOING_AJAX')) {
1813
+			return '';
1814
+		}
1815
+		//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
1816
+		$help_array   = $this->_get_help_content();
1817
+		$help_content = '';
1818
+		if (empty($help_array) || ! isset($help_array[$trigger_id])) {
1819
+			$help_array[$trigger_id] = array(
1820
+				'title'   => esc_html__('Missing Content', 'event_espresso'),
1821
+				'content' => esc_html__(
1822
+					'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.)',
1823
+					'event_espresso'
1824
+				),
1825
+			);
1826
+			$help_content            = $this->_set_help_popup_content($help_array, false);
1827
+		}
1828
+		//let's setup the trigger
1829
+		$content = '<a class="ee-dialog" href="?height='
1830
+				   . $dimensions[0]
1831
+				   . '&width='
1832
+				   . $dimensions[1]
1833
+				   . '&inlineId='
1834
+				   . $trigger_id
1835
+				   . '" target="_blank"><span class="question ee-help-popup-question"></span></a>';
1836
+		$content .= $help_content;
1837
+		if ($display) {
1838
+			echo $content;
1839
+			return  '';
1840
+		}
1841
+		return $content;
1842
+	}
1843
+
1844
+
1845
+
1846
+	/**
1847
+	 * _add_global_screen_options
1848
+	 * Add any extra wp_screen_options within this method using built-in WP functions/methods for doing so.
1849
+	 * This particular method will add_screen_options on ALL EE_Admin Pages
1850
+	 *
1851
+	 * @link   http://chrismarslender.com/wp-tutorials/wordpress-screen-options-tutorial/
1852
+	 *         see also WP_Screen object documents...
1853
+	 * @link   http://codex.wordpress.org/Class_Reference/WP_Screen
1854
+	 * @abstract
1855
+	 * @return void
1856
+	 */
1857
+	private function _add_global_screen_options()
1858
+	{
1859
+	}
1860
+
1861
+
1862
+
1863
+	/**
1864
+	 * _add_global_feature_pointers
1865
+	 * This method is used for implementing any "feature pointers" (using built-in WP styling js).
1866
+	 * This particular method will implement feature pointers for ALL EE_Admin pages.
1867
+	 * Note: this is just a placeholder for now.  Implementation will come down the road
1868
+	 *
1869
+	 * @see    WP_Internal_Pointers class in wp-admin/includes/template.php for example (its a final class so can't be
1870
+	 *         extended) also see:
1871
+	 * @link   http://eamann.com/tech/wordpress-portland/
1872
+	 * @abstract
1873
+	 * @return void
1874
+	 */
1875
+	private function _add_global_feature_pointers()
1876
+	{
1877
+	}
1878
+
1879
+
1880
+
1881
+	/**
1882
+	 * load_global_scripts_styles
1883
+	 * The scripts and styles enqueued in here will be loaded on every EE Admin page
1884
+	 *
1885
+	 * @return void
1886
+	 * @throws EE_Error
1887
+	 */
1888
+	public function load_global_scripts_styles()
1889
+	{
1890
+		/** STYLES **/
1891
+		// add debugging styles
1892
+		if (WP_DEBUG) {
1893
+			add_action('admin_head', array($this, 'add_xdebug_style'));
1894
+		}
1895
+		// register all styles
1896
+		wp_register_style(
1897
+			'espresso-ui-theme',
1898
+			EE_GLOBAL_ASSETS_URL . 'css/espresso-ui-theme/jquery-ui-1.10.3.custom.min.css',
1899
+			array(),
1900
+			EVENT_ESPRESSO_VERSION
1901
+		);
1902
+		wp_register_style('ee-admin-css', EE_ADMIN_URL . 'assets/ee-admin-page.css', array(), EVENT_ESPRESSO_VERSION);
1903
+		//helpers styles
1904
+		wp_register_style(
1905
+			'ee-text-links',
1906
+			EE_PLUGIN_DIR_URL . 'core/helpers/assets/ee_text_list_helper.css',
1907
+			array(),
1908
+			EVENT_ESPRESSO_VERSION
1909
+		);
1910
+		/** SCRIPTS **/
1911
+		//register all scripts
1912
+		wp_register_script(
1913
+			'ee-dialog',
1914
+			EE_ADMIN_URL . 'assets/ee-dialog-helper.js',
1915
+			array('jquery', 'jquery-ui-draggable'),
1916
+			EVENT_ESPRESSO_VERSION,
1917
+			true
1918
+		);
1919
+		wp_register_script(
1920
+			'ee_admin_js',
1921
+			EE_ADMIN_URL . 'assets/ee-admin-page.js',
1922
+			array('espresso_core', 'ee-parse-uri', 'ee-dialog'),
1923
+			EVENT_ESPRESSO_VERSION,
1924
+			true
1925
+		);
1926
+		wp_register_script(
1927
+			'jquery-ui-timepicker-addon',
1928
+			EE_GLOBAL_ASSETS_URL . 'scripts/jquery-ui-timepicker-addon.js',
1929
+			array('jquery-ui-datepicker', 'jquery-ui-slider'),
1930
+			EVENT_ESPRESSO_VERSION,
1931
+			true
1932
+		);
1933
+		add_filter('FHEE_load_joyride', '__return_true');
1934
+		//script for sorting tables
1935
+		wp_register_script(
1936
+			'espresso_ajax_table_sorting',
1937
+			EE_ADMIN_URL . 'assets/espresso_ajax_table_sorting.js',
1938
+			array('ee_admin_js', 'jquery-ui-sortable'),
1939
+			EVENT_ESPRESSO_VERSION,
1940
+			true
1941
+		);
1942
+		//script for parsing uri's
1943
+		wp_register_script(
1944
+			'ee-parse-uri',
1945
+			EE_GLOBAL_ASSETS_URL . 'scripts/parseuri.js',
1946
+			array(),
1947
+			EVENT_ESPRESSO_VERSION,
1948
+			true
1949
+		);
1950
+		//and parsing associative serialized form elements
1951
+		wp_register_script(
1952
+			'ee-serialize-full-array',
1953
+			EE_GLOBAL_ASSETS_URL . 'scripts/jquery.serializefullarray.js',
1954
+			array('jquery'),
1955
+			EVENT_ESPRESSO_VERSION,
1956
+			true
1957
+		);
1958
+		//helpers scripts
1959
+		wp_register_script(
1960
+			'ee-text-links',
1961
+			EE_PLUGIN_DIR_URL . 'core/helpers/assets/ee_text_list_helper.js',
1962
+			array('jquery'),
1963
+			EVENT_ESPRESSO_VERSION,
1964
+			true
1965
+		);
1966
+		wp_register_script(
1967
+			'ee-moment-core',
1968
+			EE_THIRD_PARTY_URL . 'moment/moment-with-locales.min.js',
1969
+			array(),
1970
+			EVENT_ESPRESSO_VERSION,
1971
+			true
1972
+		);
1973
+		wp_register_script(
1974
+			'ee-moment',
1975
+			EE_THIRD_PARTY_URL . 'moment/moment-timezone-with-data.min.js',
1976
+			array('ee-moment-core'),
1977
+			EVENT_ESPRESSO_VERSION,
1978
+			true
1979
+		);
1980
+		wp_register_script(
1981
+			'ee-datepicker',
1982
+			EE_ADMIN_URL . 'assets/ee-datepicker.js',
1983
+			array('jquery-ui-timepicker-addon', 'ee-moment'),
1984
+			EVENT_ESPRESSO_VERSION,
1985
+			true
1986
+		);
1987
+		//google charts
1988
+		wp_register_script(
1989
+			'google-charts',
1990
+			'https://www.gstatic.com/charts/loader.js',
1991
+			array(),
1992
+			EVENT_ESPRESSO_VERSION,
1993
+			false
1994
+		);
1995
+		// ENQUEUE ALL BASICS BY DEFAULT
1996
+		wp_enqueue_style('ee-admin-css');
1997
+		wp_enqueue_script('ee_admin_js');
1998
+		wp_enqueue_script('ee-accounting');
1999
+		wp_enqueue_script('jquery-validate');
2000
+		//taking care of metaboxes
2001
+		if (
2002
+			empty($this->_cpt_route)
2003
+			&& (isset($this->_route_config['metaboxes']) || isset($this->_route_config['has_metaboxes']))
2004
+		) {
2005
+			wp_enqueue_script('dashboard');
2006
+		}
2007
+		// LOCALIZED DATA
2008
+		//localize script for ajax lazy loading
2009
+		$lazy_loader_container_ids = apply_filters(
2010
+			'FHEE__EE_Admin_Page_Core__load_global_scripts_styles__loader_containers',
2011
+			array('espresso_news_post_box_content')
2012
+		);
2013
+		wp_localize_script('ee_admin_js', 'eeLazyLoadingContainers', $lazy_loader_container_ids);
2014
+		/**
2015
+		 * help tour stuff
2016
+		 */
2017
+		if (! empty($this->_help_tour)) {
2018
+			//register the js for kicking things off
2019
+			wp_enqueue_script(
2020
+				'ee-help-tour',
2021
+				EE_ADMIN_URL . 'assets/ee-help-tour.js',
2022
+				array('jquery-joyride'),
2023
+				EVENT_ESPRESSO_VERSION,
2024
+				true
2025
+			);
2026
+			$tours = array();
2027
+			//setup tours for the js tour object
2028
+			foreach ($this->_help_tour['tours'] as $tour) {
2029
+				if ($tour instanceof EE_Help_Tour) {
2030
+					$tours[] = array(
2031
+						'id'      => $tour->get_slug(),
2032
+						'options' => $tour->get_options(),
2033
+					);
2034
+				}
2035
+			}
2036
+			wp_localize_script('ee-help-tour', 'EE_HELP_TOUR', array('tours' => $tours));
2037
+			//admin_footer_global will take care of making sure our help_tour skeleton gets printed via the info stored in $this->_help_tour
2038
+		}
2039
+	}
2040
+
2041
+
2042
+
2043
+	/**
2044
+	 *        admin_footer_scripts_eei18n_js_strings
2045
+	 *
2046
+	 * @return        void
2047
+	 */
2048
+	public function admin_footer_scripts_eei18n_js_strings()
2049
+	{
2050
+		EE_Registry::$i18n_js_strings['ajax_url']       = WP_AJAX_URL;
2051
+		EE_Registry::$i18n_js_strings['confirm_delete'] = esc_html__(
2052
+			'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!!!',
2053
+			'event_espresso'
2054
+		);
2055
+		EE_Registry::$i18n_js_strings['January']        = esc_html__('January', 'event_espresso');
2056
+		EE_Registry::$i18n_js_strings['February']       = esc_html__('February', 'event_espresso');
2057
+		EE_Registry::$i18n_js_strings['March']          = esc_html__('March', 'event_espresso');
2058
+		EE_Registry::$i18n_js_strings['April']          = esc_html__('April', 'event_espresso');
2059
+		EE_Registry::$i18n_js_strings['May']            = esc_html__('May', 'event_espresso');
2060
+		EE_Registry::$i18n_js_strings['June']           = esc_html__('June', 'event_espresso');
2061
+		EE_Registry::$i18n_js_strings['July']           = esc_html__('July', 'event_espresso');
2062
+		EE_Registry::$i18n_js_strings['August']         = esc_html__('August', 'event_espresso');
2063
+		EE_Registry::$i18n_js_strings['September']      = esc_html__('September', 'event_espresso');
2064
+		EE_Registry::$i18n_js_strings['October']        = esc_html__('October', 'event_espresso');
2065
+		EE_Registry::$i18n_js_strings['November']       = esc_html__('November', 'event_espresso');
2066
+		EE_Registry::$i18n_js_strings['December']       = esc_html__('December', 'event_espresso');
2067
+		EE_Registry::$i18n_js_strings['Jan']            = esc_html__('Jan', 'event_espresso');
2068
+		EE_Registry::$i18n_js_strings['Feb']            = esc_html__('Feb', 'event_espresso');
2069
+		EE_Registry::$i18n_js_strings['Mar']            = esc_html__('Mar', 'event_espresso');
2070
+		EE_Registry::$i18n_js_strings['Apr']            = esc_html__('Apr', 'event_espresso');
2071
+		EE_Registry::$i18n_js_strings['May']            = esc_html__('May', 'event_espresso');
2072
+		EE_Registry::$i18n_js_strings['Jun']            = esc_html__('Jun', 'event_espresso');
2073
+		EE_Registry::$i18n_js_strings['Jul']            = esc_html__('Jul', 'event_espresso');
2074
+		EE_Registry::$i18n_js_strings['Aug']            = esc_html__('Aug', 'event_espresso');
2075
+		EE_Registry::$i18n_js_strings['Sep']            = esc_html__('Sep', 'event_espresso');
2076
+		EE_Registry::$i18n_js_strings['Oct']            = esc_html__('Oct', 'event_espresso');
2077
+		EE_Registry::$i18n_js_strings['Nov']            = esc_html__('Nov', 'event_espresso');
2078
+		EE_Registry::$i18n_js_strings['Dec']            = esc_html__('Dec', 'event_espresso');
2079
+		EE_Registry::$i18n_js_strings['Sunday']         = esc_html__('Sunday', 'event_espresso');
2080
+		EE_Registry::$i18n_js_strings['Monday']         = esc_html__('Monday', 'event_espresso');
2081
+		EE_Registry::$i18n_js_strings['Tuesday']        = esc_html__('Tuesday', 'event_espresso');
2082
+		EE_Registry::$i18n_js_strings['Wednesday']      = esc_html__('Wednesday', 'event_espresso');
2083
+		EE_Registry::$i18n_js_strings['Thursday']       = esc_html__('Thursday', 'event_espresso');
2084
+		EE_Registry::$i18n_js_strings['Friday']         = esc_html__('Friday', 'event_espresso');
2085
+		EE_Registry::$i18n_js_strings['Saturday']       = esc_html__('Saturday', 'event_espresso');
2086
+		EE_Registry::$i18n_js_strings['Sun']            = esc_html__('Sun', 'event_espresso');
2087
+		EE_Registry::$i18n_js_strings['Mon']            = esc_html__('Mon', 'event_espresso');
2088
+		EE_Registry::$i18n_js_strings['Tue']            = esc_html__('Tue', 'event_espresso');
2089
+		EE_Registry::$i18n_js_strings['Wed']            = esc_html__('Wed', 'event_espresso');
2090
+		EE_Registry::$i18n_js_strings['Thu']            = esc_html__('Thu', 'event_espresso');
2091
+		EE_Registry::$i18n_js_strings['Fri']            = esc_html__('Fri', 'event_espresso');
2092
+		EE_Registry::$i18n_js_strings['Sat']            = esc_html__('Sat', 'event_espresso');
2093
+	}
2094
+
2095
+
2096
+
2097
+	/**
2098
+	 *        load enhanced xdebug styles for ppl with failing eyesight
2099
+	 *
2100
+	 * @return        void
2101
+	 */
2102
+	public function add_xdebug_style()
2103
+	{
2104
+		echo '<style>.xdebug-error { font-size:1.5em; }</style>';
2105
+	}
2106
+
2107
+
2108
+	/************************/
2109
+	/** LIST TABLE METHODS **/
2110
+	/************************/
2111
+	/**
2112
+	 * this sets up the list table if the current view requires it.
2113
+	 *
2114
+	 * @return void
2115
+	 * @throws EE_Error
2116
+	 */
2117
+	protected function _set_list_table()
2118
+	{
2119
+		//first is this a list_table view?
2120
+		if (! isset($this->_route_config['list_table'])) {
2121
+			return;
2122
+		} //not a list_table view so get out.
2123
+		// list table functions are per view specific (because some admin pages might have more than one list table!)
2124
+		$list_table_view = '_set_list_table_views_' . $this->_req_action;
2125
+		if (! method_exists($this, $list_table_view) || $this->{$list_table_view}() === false) {
2126
+			//user error msg
2127
+			$error_msg = esc_html__(
2128
+				'An error occurred. The requested list table views could not be found.',
2129
+				'event_espresso'
2130
+			);
2131
+			//developer error msg
2132
+			$error_msg .= '||' . sprintf(
2133
+					esc_html__(
2134
+						'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.',
2135
+						'event_espresso'
2136
+					),
2137
+					$this->_req_action,
2138
+					$list_table_view
2139
+				);
2140
+			throw new EE_Error($error_msg);
2141
+		}
2142
+		//let's provide the ability to filter the views per PAGE AND ROUTE, per PAGE, and globally
2143
+		$this->_views = apply_filters(
2144
+			'FHEE_list_table_views_' . $this->page_slug . '_' . $this->_req_action,
2145
+			$this->_views
2146
+		);
2147
+		$this->_views = apply_filters('FHEE_list_table_views_' . $this->page_slug, $this->_views);
2148
+		$this->_views = apply_filters('FHEE_list_table_views', $this->_views);
2149
+		$this->_set_list_table_view();
2150
+		$this->_set_list_table_object();
2151
+	}
2152
+
2153
+
2154
+
2155
+	/**
2156
+	 * set current view for List Table
2157
+	 *
2158
+	 * @return void
2159
+	 */
2160
+	protected function _set_list_table_view()
2161
+	{
2162
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2163
+		// looking at active items or dumpster diving ?
2164
+		if (! isset($this->_req_data['status']) || ! array_key_exists($this->_req_data['status'], $this->_views)) {
2165
+			$this->_view = isset($this->_views['in_use']) ? 'in_use' : 'all';
2166
+		} else {
2167
+			$this->_view = sanitize_key($this->_req_data['status']);
2168
+		}
2169
+	}
2170
+
2171
+
2172
+	/**
2173
+	 * _set_list_table_object
2174
+	 * WP_List_Table objects need to be loaded fairly early so automatic stuff WP does is taken care of.
2175
+	 *
2176
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2177
+	 * @throws \InvalidArgumentException
2178
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2179
+	 * @throws EE_Error
2180
+	 * @throws InvalidInterfaceException
2181
+	 */
2182
+	protected function _set_list_table_object()
2183
+	{
2184
+		if (isset($this->_route_config['list_table'])) {
2185
+			if (! class_exists($this->_route_config['list_table'])) {
2186
+				throw new EE_Error(
2187
+					sprintf(
2188
+						esc_html__(
2189
+							'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.',
2190
+							'event_espresso'
2191
+						),
2192
+						$this->_route_config['list_table'],
2193
+						get_class($this)
2194
+					)
2195
+				);
2196
+			}
2197
+			$this->_list_table_object = LoaderFactory::getLoader()->getShared(
2198
+				$this->_route_config['list_table'],
2199
+				array($this)
2200
+			);
2201
+		}
2202
+	}
2203
+
2204
+
2205
+
2206
+	/**
2207
+	 * get_list_table_view_RLs - get it? View RL ?? VU-RL???  URL ??
2208
+	 *
2209
+	 * @param array $extra_query_args                     Optional. An array of extra query args to add to the generated
2210
+	 *                                                    urls.  The array should be indexed by the view it is being
2211
+	 *                                                    added to.
2212
+	 * @return array
2213
+	 */
2214
+	public function get_list_table_view_RLs($extra_query_args = array())
2215
+	{
2216
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2217
+		if (empty($this->_views)) {
2218
+			$this->_views = array();
2219
+		}
2220
+		// cycle thru views
2221
+		foreach ($this->_views as $key => $view) {
2222
+			$query_args = array();
2223
+			// check for current view
2224
+			$this->_views[$key]['class']               = $this->_view === $view['slug'] ? 'current' : '';
2225
+			$query_args['action']                      = $this->_req_action;
2226
+			$query_args[$this->_req_action . '_nonce'] = wp_create_nonce($query_args['action'] . '_nonce');
2227
+			$query_args['status']                      = $view['slug'];
2228
+			//merge any other arguments sent in.
2229
+			if (isset($extra_query_args[$view['slug']])) {
2230
+				$query_args = array_merge($query_args, $extra_query_args[$view['slug']]);
2231
+			}
2232
+			$this->_views[$key]['url'] = EE_Admin_Page::add_query_args_and_nonce($query_args, $this->_admin_base_url);
2233
+		}
2234
+		return $this->_views;
2235
+	}
2236
+
2237
+
2238
+
2239
+	/**
2240
+	 * _entries_per_page_dropdown
2241
+	 * generates a drop down box for selecting the number of visible rows in an admin page list table
2242
+	 *
2243
+	 * @todo   : Note: ideally this should be added to the screen options dropdown as that would be consistent with how
2244
+	 *         WP does it.
2245
+	 * @param int $max_entries total number of rows in the table
2246
+	 * @return string
2247
+	 */
2248
+	protected function _entries_per_page_dropdown($max_entries = 0)
2249
+	{
2250
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2251
+		$values   = array(10, 25, 50, 100);
2252
+		$per_page = (! empty($this->_req_data['per_page'])) ? absint($this->_req_data['per_page']) : 10;
2253
+		if ($max_entries) {
2254
+			$values[] = $max_entries;
2255
+			sort($values);
2256
+		}
2257
+		$entries_per_page_dropdown = '
2258 2258
 			<div id="entries-per-page-dv" class="alignleft actions">
2259 2259
 				<label class="hide-if-no-js">
2260 2260
 					Show
2261 2261
 					<select id="entries-per-page-slct" name="entries-per-page-slct">';
2262
-        foreach ($values as $value) {
2263
-            if ($value < $max_entries) {
2264
-                $selected                  = $value === $per_page ? ' selected="' . $per_page . '"' : '';
2265
-                $entries_per_page_dropdown .= '
2262
+		foreach ($values as $value) {
2263
+			if ($value < $max_entries) {
2264
+				$selected                  = $value === $per_page ? ' selected="' . $per_page . '"' : '';
2265
+				$entries_per_page_dropdown .= '
2266 2266
 						<option value="' . $value . '"' . $selected . '>' . $value . '&nbsp;&nbsp;</option>';
2267
-            }
2268
-        }
2269
-        $selected                  = $max_entries === $per_page ? ' selected="' . $per_page . '"' : '';
2270
-        $entries_per_page_dropdown .= '
2267
+			}
2268
+		}
2269
+		$selected                  = $max_entries === $per_page ? ' selected="' . $per_page . '"' : '';
2270
+		$entries_per_page_dropdown .= '
2271 2271
 						<option value="' . $max_entries . '"' . $selected . '>All&nbsp;&nbsp;</option>';
2272
-        $entries_per_page_dropdown .= '
2272
+		$entries_per_page_dropdown .= '
2273 2273
 					</select>
2274 2274
 					entries
2275 2275
 				</label>
2276 2276
 				<input id="entries-per-page-btn" class="button-secondary" type="submit" value="Go" >
2277 2277
 			</div>
2278 2278
 		';
2279
-        return $entries_per_page_dropdown;
2280
-    }
2281
-
2282
-
2283
-
2284
-    /**
2285
-     *        _set_search_attributes
2286
-     *
2287
-     * @return        void
2288
-     */
2289
-    public function _set_search_attributes()
2290
-    {
2291
-        $this->_template_args['search']['btn_label'] = sprintf(
2292
-            esc_html__('Search %s', 'event_espresso'),
2293
-            empty($this->_search_btn_label) ? $this->page_label
2294
-                : $this->_search_btn_label
2295
-        );
2296
-        $this->_template_args['search']['callback']  = 'search_' . $this->page_slug;
2297
-    }
2298
-
2299
-
2300
-
2301
-    /*** END LIST TABLE METHODS **/
2302
-
2303
-
2304
-
2305
-    /**
2306
-     * _add_registered_metaboxes
2307
-     *  this loads any registered metaboxes via the 'metaboxes' index in the _page_config property array.
2308
-     *
2309
-     * @link   http://codex.wordpress.org/Function_Reference/add_meta_box
2310
-     * @return void
2311
-     * @throws EE_Error
2312
-     */
2313
-    private function _add_registered_meta_boxes()
2314
-    {
2315
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2316
-        //we only add meta boxes if the page_route calls for it
2317
-        if (is_array($this->_route_config) && isset($this->_route_config['metaboxes'])
2318
-            && is_array(
2319
-                $this->_route_config['metaboxes']
2320
-            )
2321
-        ) {
2322
-            // this simply loops through the callbacks provided
2323
-            // and checks if there is a corresponding callback registered by the child
2324
-            // if there is then we go ahead and process the metabox loader.
2325
-            foreach ($this->_route_config['metaboxes'] as $metabox_callback) {
2326
-                // first check for Closures
2327
-                if ($metabox_callback instanceof Closure) {
2328
-                    $result = $metabox_callback();
2329
-                } elseif (is_array($metabox_callback) && isset($metabox_callback[0], $metabox_callback[1])) {
2330
-                    $result = call_user_func(array($metabox_callback[0], $metabox_callback[1]));
2331
-                } else {
2332
-                    $result = call_user_func(array($this, &$metabox_callback));
2333
-                }
2334
-                if ($result === false) {
2335
-                    // user error msg
2336
-                    $error_msg = esc_html__(
2337
-                            'An error occurred. The  requested metabox could not be found.',
2338
-                            'event_espresso'
2339
-                    );
2340
-                    // developer error msg
2341
-                    $error_msg .= '||' . sprintf(
2342
-                            esc_html__(
2343
-                                '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.',
2344
-                                'event_espresso'
2345
-                            ),
2346
-                            $metabox_callback
2347
-                        );
2348
-                    throw new EE_Error($error_msg);
2349
-                }
2350
-            }
2351
-        }
2352
-    }
2353
-
2354
-
2355
-
2356
-    /**
2357
-     * _add_screen_columns
2358
-     * This will check the _page_config array and if there is "columns" key index indicated, we'll set the template as
2359
-     * the dynamic column template and we'll setup the column options for the page.
2360
-     *
2361
-     * @return void
2362
-     */
2363
-    private function _add_screen_columns()
2364
-    {
2365
-        if (
2366
-            is_array($this->_route_config)
2367
-            && isset($this->_route_config['columns'])
2368
-            && is_array($this->_route_config['columns'])
2369
-            && count($this->_route_config['columns']) === 2
2370
-        ) {
2371
-            add_screen_option(
2372
-                'layout_columns',
2373
-                array(
2374
-                    'max'     => (int)$this->_route_config['columns'][0],
2375
-                    'default' => (int)$this->_route_config['columns'][1],
2376
-                )
2377
-            );
2378
-            $this->_template_args['num_columns']                 = $this->_route_config['columns'][0];
2379
-            $screen_id                                           = $this->_current_screen->id;
2380
-            $screen_columns                                      = (int)get_user_option("screen_layout_{$screen_id}");
2381
-            $total_columns                                       = ! empty($screen_columns)
2382
-                ? $screen_columns
2383
-                : $this->_route_config['columns'][1];
2384
-            $this->_template_args['current_screen_widget_class'] = 'columns-' . $total_columns;
2385
-            $this->_template_args['current_page']                = $this->_wp_page_slug;
2386
-            $this->_template_args['screen']                      = $this->_current_screen;
2387
-            $this->_column_template_path                         = EE_ADMIN_TEMPLATE
2388
-                                                                   . 'admin_details_metabox_column_wrapper.template.php';
2389
-            // finally if we don't have has_metaboxes set in the route config
2390
-            // let's make sure it IS set other wise the necessary hidden fields for this won't be loaded.
2391
-            $this->_route_config['has_metaboxes'] = true;
2392
-        }
2393
-    }
2394
-
2395
-
2396
-
2397
-    /** GLOBALLY AVAILABLE METABOXES **/
2398
-
2399
-
2400
-    /**
2401
-     * In this section we put any globally available EE metaboxes for all EE Admin pages.  They are called by simply
2402
-     * referencing the callback in the _page_config array property.  This way you can be very specific about what pages
2403
-     * these get loaded on.
2404
-     */
2405
-    private function _espresso_news_post_box()
2406
-    {
2407
-        $news_box_title = apply_filters(
2408
-            'FHEE__EE_Admin_Page___espresso_news_post_box__news_box_title',
2409
-            esc_html__('New @ Event Espresso', 'event_espresso')
2410
-        );
2411
-        add_meta_box(
2412
-            'espresso_news_post_box',
2413
-            $news_box_title,
2414
-            array(
2415
-                $this,
2416
-                'espresso_news_post_box',
2417
-            ),
2418
-            $this->_wp_page_slug,
2419
-            'side'
2420
-        );
2421
-    }
2422
-
2423
-
2424
-
2425
-    /**
2426
-     * Code for setting up espresso ratings request metabox.
2427
-     */
2428
-    protected function _espresso_ratings_request()
2429
-    {
2430
-        if (! apply_filters('FHEE_show_ratings_request_meta_box', true)) {
2431
-            return;
2432
-        }
2433
-        $ratings_box_title = apply_filters(
2434
-            'FHEE__EE_Admin_Page___espresso_news_post_box__news_box_title',
2435
-            esc_html__('Keep Event Espresso Decaf Free', 'event_espresso')
2436
-        );
2437
-        add_meta_box(
2438
-            'espresso_ratings_request',
2439
-            $ratings_box_title,
2440
-            array(
2441
-                $this,
2442
-                'espresso_ratings_request',
2443
-            ),
2444
-            $this->_wp_page_slug,
2445
-            'side'
2446
-        );
2447
-    }
2448
-
2449
-
2450
-
2451
-    /**
2452
-     * Code for setting up espresso ratings request metabox content.
2453
-     *
2454
-     * @throws DomainException
2455
-     */
2456
-    public function espresso_ratings_request()
2457
-    {
2458
-        EEH_Template::display_template(
2459
-            EE_ADMIN_TEMPLATE . 'espresso_ratings_request_content.template.php',
2460
-                array()
2461
-        );
2462
-    }
2463
-
2464
-
2465
-
2466
-    public static function cached_rss_display($rss_id, $url)
2467
-    {
2468
-        $loading    = '<p class="widget-loading hide-if-no-js">'
2469
-                      . __('Loading&#8230;')
2470
-                      . '</p><p class="hide-if-js">'
2471
-                      . esc_html__('This widget requires JavaScript.')
2472
-                      . '</p>';
2473
-        $pre        = '<div class="espresso-rss-display">' . "\n\t";
2474
-        $pre        .= '<span id="' . $rss_id . '_url" class="hidden">' . $url . '</span>';
2475
-        $post       = '</div>' . "\n";
2476
-        $cache_key  = 'ee_rss_' . md5($rss_id);
2477
-        $output = get_transient($cache_key);
2478
-        if ($output !== false) {
2479
-            echo $pre . $output . $post;
2480
-            return true;
2481
-        }
2482
-        if (! (defined('DOING_AJAX') && DOING_AJAX)) {
2483
-            echo $pre . $loading . $post;
2484
-            return false;
2485
-        }
2486
-        ob_start();
2487
-        wp_widget_rss_output($url, array('show_date' => 0, 'items' => 5));
2488
-        set_transient($cache_key, ob_get_flush(), 12 * HOUR_IN_SECONDS);
2489
-        return true;
2490
-    }
2491
-
2492
-
2493
-
2494
-    public function espresso_news_post_box()
2495
-    {
2496
-        ?>
2279
+		return $entries_per_page_dropdown;
2280
+	}
2281
+
2282
+
2283
+
2284
+	/**
2285
+	 *        _set_search_attributes
2286
+	 *
2287
+	 * @return        void
2288
+	 */
2289
+	public function _set_search_attributes()
2290
+	{
2291
+		$this->_template_args['search']['btn_label'] = sprintf(
2292
+			esc_html__('Search %s', 'event_espresso'),
2293
+			empty($this->_search_btn_label) ? $this->page_label
2294
+				: $this->_search_btn_label
2295
+		);
2296
+		$this->_template_args['search']['callback']  = 'search_' . $this->page_slug;
2297
+	}
2298
+
2299
+
2300
+
2301
+	/*** END LIST TABLE METHODS **/
2302
+
2303
+
2304
+
2305
+	/**
2306
+	 * _add_registered_metaboxes
2307
+	 *  this loads any registered metaboxes via the 'metaboxes' index in the _page_config property array.
2308
+	 *
2309
+	 * @link   http://codex.wordpress.org/Function_Reference/add_meta_box
2310
+	 * @return void
2311
+	 * @throws EE_Error
2312
+	 */
2313
+	private function _add_registered_meta_boxes()
2314
+	{
2315
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2316
+		//we only add meta boxes if the page_route calls for it
2317
+		if (is_array($this->_route_config) && isset($this->_route_config['metaboxes'])
2318
+			&& is_array(
2319
+				$this->_route_config['metaboxes']
2320
+			)
2321
+		) {
2322
+			// this simply loops through the callbacks provided
2323
+			// and checks if there is a corresponding callback registered by the child
2324
+			// if there is then we go ahead and process the metabox loader.
2325
+			foreach ($this->_route_config['metaboxes'] as $metabox_callback) {
2326
+				// first check for Closures
2327
+				if ($metabox_callback instanceof Closure) {
2328
+					$result = $metabox_callback();
2329
+				} elseif (is_array($metabox_callback) && isset($metabox_callback[0], $metabox_callback[1])) {
2330
+					$result = call_user_func(array($metabox_callback[0], $metabox_callback[1]));
2331
+				} else {
2332
+					$result = call_user_func(array($this, &$metabox_callback));
2333
+				}
2334
+				if ($result === false) {
2335
+					// user error msg
2336
+					$error_msg = esc_html__(
2337
+							'An error occurred. The  requested metabox could not be found.',
2338
+							'event_espresso'
2339
+					);
2340
+					// developer error msg
2341
+					$error_msg .= '||' . sprintf(
2342
+							esc_html__(
2343
+								'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.',
2344
+								'event_espresso'
2345
+							),
2346
+							$metabox_callback
2347
+						);
2348
+					throw new EE_Error($error_msg);
2349
+				}
2350
+			}
2351
+		}
2352
+	}
2353
+
2354
+
2355
+
2356
+	/**
2357
+	 * _add_screen_columns
2358
+	 * This will check the _page_config array and if there is "columns" key index indicated, we'll set the template as
2359
+	 * the dynamic column template and we'll setup the column options for the page.
2360
+	 *
2361
+	 * @return void
2362
+	 */
2363
+	private function _add_screen_columns()
2364
+	{
2365
+		if (
2366
+			is_array($this->_route_config)
2367
+			&& isset($this->_route_config['columns'])
2368
+			&& is_array($this->_route_config['columns'])
2369
+			&& count($this->_route_config['columns']) === 2
2370
+		) {
2371
+			add_screen_option(
2372
+				'layout_columns',
2373
+				array(
2374
+					'max'     => (int)$this->_route_config['columns'][0],
2375
+					'default' => (int)$this->_route_config['columns'][1],
2376
+				)
2377
+			);
2378
+			$this->_template_args['num_columns']                 = $this->_route_config['columns'][0];
2379
+			$screen_id                                           = $this->_current_screen->id;
2380
+			$screen_columns                                      = (int)get_user_option("screen_layout_{$screen_id}");
2381
+			$total_columns                                       = ! empty($screen_columns)
2382
+				? $screen_columns
2383
+				: $this->_route_config['columns'][1];
2384
+			$this->_template_args['current_screen_widget_class'] = 'columns-' . $total_columns;
2385
+			$this->_template_args['current_page']                = $this->_wp_page_slug;
2386
+			$this->_template_args['screen']                      = $this->_current_screen;
2387
+			$this->_column_template_path                         = EE_ADMIN_TEMPLATE
2388
+																   . 'admin_details_metabox_column_wrapper.template.php';
2389
+			// finally if we don't have has_metaboxes set in the route config
2390
+			// let's make sure it IS set other wise the necessary hidden fields for this won't be loaded.
2391
+			$this->_route_config['has_metaboxes'] = true;
2392
+		}
2393
+	}
2394
+
2395
+
2396
+
2397
+	/** GLOBALLY AVAILABLE METABOXES **/
2398
+
2399
+
2400
+	/**
2401
+	 * In this section we put any globally available EE metaboxes for all EE Admin pages.  They are called by simply
2402
+	 * referencing the callback in the _page_config array property.  This way you can be very specific about what pages
2403
+	 * these get loaded on.
2404
+	 */
2405
+	private function _espresso_news_post_box()
2406
+	{
2407
+		$news_box_title = apply_filters(
2408
+			'FHEE__EE_Admin_Page___espresso_news_post_box__news_box_title',
2409
+			esc_html__('New @ Event Espresso', 'event_espresso')
2410
+		);
2411
+		add_meta_box(
2412
+			'espresso_news_post_box',
2413
+			$news_box_title,
2414
+			array(
2415
+				$this,
2416
+				'espresso_news_post_box',
2417
+			),
2418
+			$this->_wp_page_slug,
2419
+			'side'
2420
+		);
2421
+	}
2422
+
2423
+
2424
+
2425
+	/**
2426
+	 * Code for setting up espresso ratings request metabox.
2427
+	 */
2428
+	protected function _espresso_ratings_request()
2429
+	{
2430
+		if (! apply_filters('FHEE_show_ratings_request_meta_box', true)) {
2431
+			return;
2432
+		}
2433
+		$ratings_box_title = apply_filters(
2434
+			'FHEE__EE_Admin_Page___espresso_news_post_box__news_box_title',
2435
+			esc_html__('Keep Event Espresso Decaf Free', 'event_espresso')
2436
+		);
2437
+		add_meta_box(
2438
+			'espresso_ratings_request',
2439
+			$ratings_box_title,
2440
+			array(
2441
+				$this,
2442
+				'espresso_ratings_request',
2443
+			),
2444
+			$this->_wp_page_slug,
2445
+			'side'
2446
+		);
2447
+	}
2448
+
2449
+
2450
+
2451
+	/**
2452
+	 * Code for setting up espresso ratings request metabox content.
2453
+	 *
2454
+	 * @throws DomainException
2455
+	 */
2456
+	public function espresso_ratings_request()
2457
+	{
2458
+		EEH_Template::display_template(
2459
+			EE_ADMIN_TEMPLATE . 'espresso_ratings_request_content.template.php',
2460
+				array()
2461
+		);
2462
+	}
2463
+
2464
+
2465
+
2466
+	public static function cached_rss_display($rss_id, $url)
2467
+	{
2468
+		$loading    = '<p class="widget-loading hide-if-no-js">'
2469
+					  . __('Loading&#8230;')
2470
+					  . '</p><p class="hide-if-js">'
2471
+					  . esc_html__('This widget requires JavaScript.')
2472
+					  . '</p>';
2473
+		$pre        = '<div class="espresso-rss-display">' . "\n\t";
2474
+		$pre        .= '<span id="' . $rss_id . '_url" class="hidden">' . $url . '</span>';
2475
+		$post       = '</div>' . "\n";
2476
+		$cache_key  = 'ee_rss_' . md5($rss_id);
2477
+		$output = get_transient($cache_key);
2478
+		if ($output !== false) {
2479
+			echo $pre . $output . $post;
2480
+			return true;
2481
+		}
2482
+		if (! (defined('DOING_AJAX') && DOING_AJAX)) {
2483
+			echo $pre . $loading . $post;
2484
+			return false;
2485
+		}
2486
+		ob_start();
2487
+		wp_widget_rss_output($url, array('show_date' => 0, 'items' => 5));
2488
+		set_transient($cache_key, ob_get_flush(), 12 * HOUR_IN_SECONDS);
2489
+		return true;
2490
+	}
2491
+
2492
+
2493
+
2494
+	public function espresso_news_post_box()
2495
+	{
2496
+		?>
2497 2497
         <div class="padding">
2498 2498
             <div id="espresso_news_post_box_content" class="infolinks">
2499 2499
                 <?php
2500
-                // Get RSS Feed(s)
2501
-                self::cached_rss_display(
2502
-                    'espresso_news_post_box_content',
2503
-                    urlencode(
2504
-                        apply_filters(
2505
-                            'FHEE__EE_Admin_Page__espresso_news_post_box__feed_url',
2506
-                            'http://eventespresso.com/feed/'
2507
-                        )
2508
-                    )
2509
-                );
2510
-                ?>
2500
+				// Get RSS Feed(s)
2501
+				self::cached_rss_display(
2502
+					'espresso_news_post_box_content',
2503
+					urlencode(
2504
+						apply_filters(
2505
+							'FHEE__EE_Admin_Page__espresso_news_post_box__feed_url',
2506
+							'http://eventespresso.com/feed/'
2507
+						)
2508
+					)
2509
+				);
2510
+				?>
2511 2511
             </div>
2512 2512
             <?php do_action('AHEE__EE_Admin_Page__espresso_news_post_box__after_content'); ?>
2513 2513
         </div>
2514 2514
         <?php
2515
-    }
2516
-
2517
-
2518
-
2519
-    private function _espresso_links_post_box()
2520
-    {
2521
-        //Hiding until we actually have content to put in here...
2522
-        //add_meta_box('espresso_links_post_box', esc_html__('Helpful Plugin Links', 'event_espresso'), array( $this, 'espresso_links_post_box'), $this->_wp_page_slug, 'side');
2523
-    }
2524
-
2525
-
2526
-
2527
-    public function espresso_links_post_box()
2528
-    {
2529
-        //Hiding until we actually have content to put in here...
2530
-        // EEH_Template::display_template(
2531
-        //     EE_ADMIN_TEMPLATE . 'admin_general_metabox_contents_espresso_links.template.php'
2532
-        // );
2533
-    }
2534
-
2535
-
2536
-
2537
-    protected function _espresso_sponsors_post_box()
2538
-    {
2539
-        if (apply_filters('FHEE_show_sponsors_meta_box', true)) {
2540
-            add_meta_box(
2541
-                'espresso_sponsors_post_box',
2542
-                esc_html__('Event Espresso Highlights', 'event_espresso'),
2543
-                array($this, 'espresso_sponsors_post_box'),
2544
-                $this->_wp_page_slug,
2545
-                'side'
2546
-            );
2547
-        }
2548
-    }
2549
-
2550
-
2551
-
2552
-    public function espresso_sponsors_post_box()
2553
-    {
2554
-        EEH_Template::display_template(
2555
-            EE_ADMIN_TEMPLATE . 'admin_general_metabox_contents_espresso_sponsors.template.php'
2556
-        );
2557
-    }
2558
-
2559
-
2560
-
2561
-    private function _publish_post_box()
2562
-    {
2563
-        $meta_box_ref = 'espresso_' . $this->page_slug . '_editor_overview';
2564
-        // if there is a array('label' => array('publishbox' => 'some title') ) present in the _page_config array
2565
-        // then we'll use that for the metabox label.
2566
-        // Otherwise we'll just use publish (publishbox itself could be an array of labels indexed by routes)
2567
-        if (! empty($this->_labels['publishbox'])) {
2568
-            $box_label = is_array($this->_labels['publishbox']) ? $this->_labels['publishbox'][$this->_req_action]
2569
-                : $this->_labels['publishbox'];
2570
-        } else {
2571
-            $box_label = esc_html__('Publish', 'event_espresso');
2572
-        }
2573
-        $box_label = apply_filters(
2574
-            'FHEE__EE_Admin_Page___publish_post_box__box_label',
2575
-            $box_label,
2576
-            $this->_req_action,
2577
-            $this
2578
-        );
2579
-        add_meta_box(
2580
-            $meta_box_ref,
2581
-            $box_label,
2582
-            array($this, 'editor_overview'),
2583
-            $this->_current_screen->id,
2584
-            'side',
2585
-            'high'
2586
-        );
2587
-    }
2588
-
2589
-
2590
-
2591
-    public function editor_overview()
2592
-    {
2593
-        //if we have extra content set let's add it in if not make sure its empty
2594
-        $this->_template_args['publish_box_extra_content'] = isset($this->_template_args['publish_box_extra_content'])
2595
-            ? $this->_template_args['publish_box_extra_content']
2596
-            : '';
2597
-        echo EEH_Template::display_template(
2598
-            EE_ADMIN_TEMPLATE . 'admin_details_publish_metabox.template.php',
2599
-            $this->_template_args,
2600
-            true
2601
-        );
2602
-    }
2603
-
2604
-
2605
-    /** end of globally available metaboxes section **/
2606
-
2607
-
2608
-
2609
-    /**
2610
-     * Public wrapper for the protected method.  Allows plugins/addons to externally call the
2611
-     * protected method.
2612
-     *
2613
-     * @see   $this->_set_publish_post_box_vars for param details
2614
-     * @since 4.6.0
2615
-     * @param string $name
2616
-     * @param int    $id
2617
-     * @param bool   $delete
2618
-     * @param string $save_close_redirect_URL
2619
-     * @param bool   $both_btns
2620
-     * @throws EE_Error
2621
-     * @throws InvalidArgumentException
2622
-     * @throws InvalidDataTypeException
2623
-     * @throws InvalidInterfaceException
2624
-     */
2625
-    public function set_publish_post_box_vars(
2626
-        $name = '',
2627
-        $id = 0,
2628
-        $delete = false,
2629
-        $save_close_redirect_URL = '',
2630
-        $both_btns = true
2631
-    ) {
2632
-        $this->_set_publish_post_box_vars(
2633
-            $name,
2634
-            $id,
2635
-            $delete,
2636
-            $save_close_redirect_URL,
2637
-            $both_btns
2638
-        );
2639
-    }
2640
-
2641
-
2642
-
2643
-    /**
2644
-     * Sets the _template_args arguments used by the _publish_post_box shortcut
2645
-     * Note: currently there is no validation for this.  However if you want the delete button, the
2646
-     * save, and save and close buttons to work properly, then you will want to include a
2647
-     * values for the name and id arguments.
2648
-     *
2649
-     * @todo  Add in validation for name/id arguments.
2650
-     * @param    string  $name                    key used for the action ID (i.e. event_id)
2651
-     * @param    int     $id                      id attached to the item published
2652
-     * @param    string  $delete                  page route callback for the delete action
2653
-     * @param    string  $save_close_redirect_URL custom URL to redirect to after Save & Close has been completed
2654
-     * @param    boolean $both_btns               whether to display BOTH the "Save & Close" and "Save" buttons or just
2655
-     *                                            the Save button
2656
-     * @throws EE_Error
2657
-     * @throws InvalidArgumentException
2658
-     * @throws InvalidDataTypeException
2659
-     * @throws InvalidInterfaceException
2660
-     */
2661
-    protected function _set_publish_post_box_vars(
2662
-        $name = '',
2663
-        $id = 0,
2664
-        $delete = '',
2665
-        $save_close_redirect_URL = '',
2666
-        $both_btns = true
2667
-    ) {
2668
-        // if Save & Close, use a custom redirect URL or default to the main page?
2669
-        $save_close_redirect_URL = ! empty($save_close_redirect_URL)
2670
-            ? $save_close_redirect_URL
2671
-            : $this->_admin_base_url;
2672
-        // create the Save & Close and Save buttons
2673
-        $this->_set_save_buttons($both_btns, array(), array(), $save_close_redirect_URL);
2674
-        //if we have extra content set let's add it in if not make sure its empty
2675
-        $this->_template_args['publish_box_extra_content'] = isset($this->_template_args['publish_box_extra_content'])
2676
-            ? $this->_template_args['publish_box_extra_content']
2677
-            : '';
2678
-        if ($delete && ! empty($id)) {
2679
-            //make sure we have a default if just true is sent.
2680
-            $delete           = ! empty($delete) ? $delete : 'delete';
2681
-            $delete_link_args = array($name => $id);
2682
-            $delete           = $this->get_action_link_or_button(
2683
-                $delete,
2684
-                $delete,
2685
-                $delete_link_args,
2686
-                'submitdelete deletion',
2687
-                '',
2688
-                false
2689
-            );
2690
-        }
2691
-        $this->_template_args['publish_delete_link'] = ! empty($id) ? $delete : '';
2692
-        if (! empty($name) && ! empty($id)) {
2693
-            $hidden_field_arr[$name] = array(
2694
-                'type'  => 'hidden',
2695
-                'value' => $id,
2696
-            );
2697
-            $hf                      = $this->_generate_admin_form_fields($hidden_field_arr, 'array');
2698
-        } else {
2699
-            $hf = '';
2700
-        }
2701
-        // add hidden field
2702
-        $this->_template_args['publish_hidden_fields'] = is_array($hf) && ! empty($name)
2703
-            ? $hf[$name]['field']
2704
-            : $hf;
2705
-    }
2706
-
2707
-
2708
-
2709
-    /**
2710
-     * displays an error message to ppl who have javascript disabled
2711
-     *
2712
-     * @return void
2713
-     */
2714
-    private function _display_no_javascript_warning()
2715
-    {
2716
-        ?>
2515
+	}
2516
+
2517
+
2518
+
2519
+	private function _espresso_links_post_box()
2520
+	{
2521
+		//Hiding until we actually have content to put in here...
2522
+		//add_meta_box('espresso_links_post_box', esc_html__('Helpful Plugin Links', 'event_espresso'), array( $this, 'espresso_links_post_box'), $this->_wp_page_slug, 'side');
2523
+	}
2524
+
2525
+
2526
+
2527
+	public function espresso_links_post_box()
2528
+	{
2529
+		//Hiding until we actually have content to put in here...
2530
+		// EEH_Template::display_template(
2531
+		//     EE_ADMIN_TEMPLATE . 'admin_general_metabox_contents_espresso_links.template.php'
2532
+		// );
2533
+	}
2534
+
2535
+
2536
+
2537
+	protected function _espresso_sponsors_post_box()
2538
+	{
2539
+		if (apply_filters('FHEE_show_sponsors_meta_box', true)) {
2540
+			add_meta_box(
2541
+				'espresso_sponsors_post_box',
2542
+				esc_html__('Event Espresso Highlights', 'event_espresso'),
2543
+				array($this, 'espresso_sponsors_post_box'),
2544
+				$this->_wp_page_slug,
2545
+				'side'
2546
+			);
2547
+		}
2548
+	}
2549
+
2550
+
2551
+
2552
+	public function espresso_sponsors_post_box()
2553
+	{
2554
+		EEH_Template::display_template(
2555
+			EE_ADMIN_TEMPLATE . 'admin_general_metabox_contents_espresso_sponsors.template.php'
2556
+		);
2557
+	}
2558
+
2559
+
2560
+
2561
+	private function _publish_post_box()
2562
+	{
2563
+		$meta_box_ref = 'espresso_' . $this->page_slug . '_editor_overview';
2564
+		// if there is a array('label' => array('publishbox' => 'some title') ) present in the _page_config array
2565
+		// then we'll use that for the metabox label.
2566
+		// Otherwise we'll just use publish (publishbox itself could be an array of labels indexed by routes)
2567
+		if (! empty($this->_labels['publishbox'])) {
2568
+			$box_label = is_array($this->_labels['publishbox']) ? $this->_labels['publishbox'][$this->_req_action]
2569
+				: $this->_labels['publishbox'];
2570
+		} else {
2571
+			$box_label = esc_html__('Publish', 'event_espresso');
2572
+		}
2573
+		$box_label = apply_filters(
2574
+			'FHEE__EE_Admin_Page___publish_post_box__box_label',
2575
+			$box_label,
2576
+			$this->_req_action,
2577
+			$this
2578
+		);
2579
+		add_meta_box(
2580
+			$meta_box_ref,
2581
+			$box_label,
2582
+			array($this, 'editor_overview'),
2583
+			$this->_current_screen->id,
2584
+			'side',
2585
+			'high'
2586
+		);
2587
+	}
2588
+
2589
+
2590
+
2591
+	public function editor_overview()
2592
+	{
2593
+		//if we have extra content set let's add it in if not make sure its empty
2594
+		$this->_template_args['publish_box_extra_content'] = isset($this->_template_args['publish_box_extra_content'])
2595
+			? $this->_template_args['publish_box_extra_content']
2596
+			: '';
2597
+		echo EEH_Template::display_template(
2598
+			EE_ADMIN_TEMPLATE . 'admin_details_publish_metabox.template.php',
2599
+			$this->_template_args,
2600
+			true
2601
+		);
2602
+	}
2603
+
2604
+
2605
+	/** end of globally available metaboxes section **/
2606
+
2607
+
2608
+
2609
+	/**
2610
+	 * Public wrapper for the protected method.  Allows plugins/addons to externally call the
2611
+	 * protected method.
2612
+	 *
2613
+	 * @see   $this->_set_publish_post_box_vars for param details
2614
+	 * @since 4.6.0
2615
+	 * @param string $name
2616
+	 * @param int    $id
2617
+	 * @param bool   $delete
2618
+	 * @param string $save_close_redirect_URL
2619
+	 * @param bool   $both_btns
2620
+	 * @throws EE_Error
2621
+	 * @throws InvalidArgumentException
2622
+	 * @throws InvalidDataTypeException
2623
+	 * @throws InvalidInterfaceException
2624
+	 */
2625
+	public function set_publish_post_box_vars(
2626
+		$name = '',
2627
+		$id = 0,
2628
+		$delete = false,
2629
+		$save_close_redirect_URL = '',
2630
+		$both_btns = true
2631
+	) {
2632
+		$this->_set_publish_post_box_vars(
2633
+			$name,
2634
+			$id,
2635
+			$delete,
2636
+			$save_close_redirect_URL,
2637
+			$both_btns
2638
+		);
2639
+	}
2640
+
2641
+
2642
+
2643
+	/**
2644
+	 * Sets the _template_args arguments used by the _publish_post_box shortcut
2645
+	 * Note: currently there is no validation for this.  However if you want the delete button, the
2646
+	 * save, and save and close buttons to work properly, then you will want to include a
2647
+	 * values for the name and id arguments.
2648
+	 *
2649
+	 * @todo  Add in validation for name/id arguments.
2650
+	 * @param    string  $name                    key used for the action ID (i.e. event_id)
2651
+	 * @param    int     $id                      id attached to the item published
2652
+	 * @param    string  $delete                  page route callback for the delete action
2653
+	 * @param    string  $save_close_redirect_URL custom URL to redirect to after Save & Close has been completed
2654
+	 * @param    boolean $both_btns               whether to display BOTH the "Save & Close" and "Save" buttons or just
2655
+	 *                                            the Save button
2656
+	 * @throws EE_Error
2657
+	 * @throws InvalidArgumentException
2658
+	 * @throws InvalidDataTypeException
2659
+	 * @throws InvalidInterfaceException
2660
+	 */
2661
+	protected function _set_publish_post_box_vars(
2662
+		$name = '',
2663
+		$id = 0,
2664
+		$delete = '',
2665
+		$save_close_redirect_URL = '',
2666
+		$both_btns = true
2667
+	) {
2668
+		// if Save & Close, use a custom redirect URL or default to the main page?
2669
+		$save_close_redirect_URL = ! empty($save_close_redirect_URL)
2670
+			? $save_close_redirect_URL
2671
+			: $this->_admin_base_url;
2672
+		// create the Save & Close and Save buttons
2673
+		$this->_set_save_buttons($both_btns, array(), array(), $save_close_redirect_URL);
2674
+		//if we have extra content set let's add it in if not make sure its empty
2675
+		$this->_template_args['publish_box_extra_content'] = isset($this->_template_args['publish_box_extra_content'])
2676
+			? $this->_template_args['publish_box_extra_content']
2677
+			: '';
2678
+		if ($delete && ! empty($id)) {
2679
+			//make sure we have a default if just true is sent.
2680
+			$delete           = ! empty($delete) ? $delete : 'delete';
2681
+			$delete_link_args = array($name => $id);
2682
+			$delete           = $this->get_action_link_or_button(
2683
+				$delete,
2684
+				$delete,
2685
+				$delete_link_args,
2686
+				'submitdelete deletion',
2687
+				'',
2688
+				false
2689
+			);
2690
+		}
2691
+		$this->_template_args['publish_delete_link'] = ! empty($id) ? $delete : '';
2692
+		if (! empty($name) && ! empty($id)) {
2693
+			$hidden_field_arr[$name] = array(
2694
+				'type'  => 'hidden',
2695
+				'value' => $id,
2696
+			);
2697
+			$hf                      = $this->_generate_admin_form_fields($hidden_field_arr, 'array');
2698
+		} else {
2699
+			$hf = '';
2700
+		}
2701
+		// add hidden field
2702
+		$this->_template_args['publish_hidden_fields'] = is_array($hf) && ! empty($name)
2703
+			? $hf[$name]['field']
2704
+			: $hf;
2705
+	}
2706
+
2707
+
2708
+
2709
+	/**
2710
+	 * displays an error message to ppl who have javascript disabled
2711
+	 *
2712
+	 * @return void
2713
+	 */
2714
+	private function _display_no_javascript_warning()
2715
+	{
2716
+		?>
2717 2717
         <noscript>
2718 2718
             <div id="no-js-message" class="error">
2719 2719
                 <p style="font-size:1.3em;">
2720 2720
                     <span style="color:red;"><?php esc_html_e('Warning!', 'event_espresso'); ?></span>
2721 2721
                     <?php esc_html_e(
2722
-                        '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.',
2723
-                        'event_espresso'
2724
-                    ); ?>
2722
+						'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.',
2723
+						'event_espresso'
2724
+					); ?>
2725 2725
                 </p>
2726 2726
             </div>
2727 2727
         </noscript>
2728 2728
         <?php
2729
-    }
2729
+	}
2730 2730
 
2731 2731
 
2732 2732
 
2733
-    /**
2734
-     * displays espresso success and/or error notices
2735
-     *
2736
-     * @return void
2737
-     */
2738
-    private function _display_espresso_notices()
2739
-    {
2740
-        $notices = $this->_get_transient(true);
2741
-        echo stripslashes($notices);
2742
-    }
2733
+	/**
2734
+	 * displays espresso success and/or error notices
2735
+	 *
2736
+	 * @return void
2737
+	 */
2738
+	private function _display_espresso_notices()
2739
+	{
2740
+		$notices = $this->_get_transient(true);
2741
+		echo stripslashes($notices);
2742
+	}
2743 2743
 
2744 2744
 
2745 2745
 
2746
-    /**
2747
-     * spinny things pacify the masses
2748
-     *
2749
-     * @return void
2750
-     */
2751
-    protected function _add_admin_page_ajax_loading_img()
2752
-    {
2753
-        ?>
2746
+	/**
2747
+	 * spinny things pacify the masses
2748
+	 *
2749
+	 * @return void
2750
+	 */
2751
+	protected function _add_admin_page_ajax_loading_img()
2752
+	{
2753
+		?>
2754 2754
         <div id="espresso-ajax-loading" class="ajax-loading-grey">
2755 2755
             <span class="ee-spinner ee-spin"></span><span class="hidden"><?php esc_html_e(
2756
-                    'loading...',
2757
-                    'event_espresso'
2758
-                ); ?></span>
2756
+					'loading...',
2757
+					'event_espresso'
2758
+				); ?></span>
2759 2759
         </div>
2760 2760
         <?php
2761
-    }
2761
+	}
2762 2762
 
2763 2763
 
2764 2764
 
2765
-    /**
2766
-     * add admin page overlay for modal boxes
2767
-     *
2768
-     * @return void
2769
-     */
2770
-    protected function _add_admin_page_overlay()
2771
-    {
2772
-        ?>
2765
+	/**
2766
+	 * add admin page overlay for modal boxes
2767
+	 *
2768
+	 * @return void
2769
+	 */
2770
+	protected function _add_admin_page_overlay()
2771
+	{
2772
+		?>
2773 2773
         <div id="espresso-admin-page-overlay-dv" class=""></div>
2774 2774
         <?php
2775
-    }
2776
-
2777
-
2778
-
2779
-    /**
2780
-     * facade for add_meta_box
2781
-     *
2782
-     * @param string  $action        where the metabox get's displayed
2783
-     * @param string  $title         Title of Metabox (output in metabox header)
2784
-     * @param string  $callback      If not empty and $create_fun is set to false then we'll use a custom callback
2785
-     *                               instead of the one created in here.
2786
-     * @param array   $callback_args an array of args supplied for the metabox
2787
-     * @param string  $column        what metabox column
2788
-     * @param string  $priority      give this metabox a priority (using accepted priorities for wp meta boxes)
2789
-     * @param boolean $create_func   default is true.  Basically we can say we don't WANT to have the runtime function
2790
-     *                               created but just set our own callback for wp's add_meta_box.
2791
-     * @throws \DomainException
2792
-     */
2793
-    public function _add_admin_page_meta_box(
2794
-        $action,
2795
-        $title,
2796
-        $callback,
2797
-        $callback_args,
2798
-        $column = 'normal',
2799
-        $priority = 'high',
2800
-        $create_func = true
2801
-    ) {
2802
-        do_action('AHEE_log', __FILE__, __FUNCTION__, $callback);
2803
-        //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.
2804
-        if (empty($callback_args) && $create_func) {
2805
-            $callback_args = array(
2806
-                'template_path' => $this->_template_path,
2807
-                'template_args' => $this->_template_args,
2808
-            );
2809
-        }
2810
-        //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)
2811
-        $call_back_func = $create_func
2812
-            ? function ($post, $metabox)
2813
-            {
2814
-                do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2815
-                echo EEH_Template::display_template(
2816
-                    $metabox['args']['template_path'],
2817
-                    $metabox['args']['template_args'],
2818
-                    true
2819
-                );
2820
-            }
2821
-            : $callback;
2822
-        add_meta_box(
2823
-            str_replace('_', '-', $action) . '-mbox',
2824
-            $title,
2825
-            $call_back_func,
2826
-            $this->_wp_page_slug,
2827
-            $column,
2828
-            $priority,
2829
-            $callback_args
2830
-        );
2831
-    }
2832
-
2833
-
2834
-
2835
-    /**
2836
-     * generates HTML wrapper for and admin details page that contains metaboxes in columns
2837
-     *
2838
-     * @throws DomainException
2839
-     * @throws EE_Error
2840
-     */
2841
-    public function display_admin_page_with_metabox_columns()
2842
-    {
2843
-        $this->_template_args['post_body_content']  = $this->_template_args['admin_page_content'];
2844
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
2845
-            $this->_column_template_path,
2846
-            $this->_template_args,
2847
-            true
2848
-        );
2849
-        //the final wrapper
2850
-        $this->admin_page_wrapper();
2851
-    }
2852
-
2853
-
2854
-
2855
-    /**
2856
-     * generates  HTML wrapper for an admin details page
2857
-     *
2858
-     * @return void
2859
-     * @throws EE_Error
2860
-     * @throws DomainException
2861
-     */
2862
-    public function display_admin_page_with_sidebar()
2863
-    {
2864
-        $this->_display_admin_page(true);
2865
-    }
2866
-
2867
-
2868
-
2869
-    /**
2870
-     * generates  HTML wrapper for an admin details page (except no sidebar)
2871
-     *
2872
-     * @return void
2873
-     * @throws EE_Error
2874
-     * @throws DomainException
2875
-     */
2876
-    public function display_admin_page_with_no_sidebar()
2877
-    {
2878
-        $this->_display_admin_page();
2879
-    }
2880
-
2881
-
2882
-
2883
-    /**
2884
-     * generates HTML wrapper for an EE about admin page (no sidebar)
2885
-     *
2886
-     * @return void
2887
-     * @throws EE_Error
2888
-     * @throws DomainException
2889
-     */
2890
-    public function display_about_admin_page()
2891
-    {
2892
-        $this->_display_admin_page(false, true);
2893
-    }
2894
-
2895
-
2896
-
2897
-    /**
2898
-     * display_admin_page
2899
-     * contains the code for actually displaying an admin page
2900
-     *
2901
-     * @param  boolean $sidebar true with sidebar, false without
2902
-     * @param  boolean $about   use the about admin wrapper instead of the default.
2903
-     * @return void
2904
-     * @throws DomainException
2905
-     * @throws EE_Error
2906
-     */
2907
-    private function _display_admin_page($sidebar = false, $about = false)
2908
-    {
2909
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2910
-        //custom remove metaboxes hook to add or remove any metaboxes to/from Admin pages.
2911
-        do_action('AHEE__EE_Admin_Page___display_admin_page__modify_metaboxes');
2912
-        // set current wp page slug - looks like: event-espresso_page_event_categories
2913
-        // keep in mind "event-espresso" COULD be something else if the top level menu label has been translated.
2914
-        $this->_template_args['current_page']              = $this->_wp_page_slug;
2915
-        $this->_template_args['admin_page_wrapper_div_id'] = $this->_cpt_route
2916
-            ? 'poststuff'
2917
-            : 'espresso-default-admin';
2918
-        $template_path                                     = $sidebar
2919
-            ? EE_ADMIN_TEMPLATE . 'admin_details_wrapper.template.php'
2920
-            : EE_ADMIN_TEMPLATE . 'admin_details_wrapper_no_sidebar.template.php';
2921
-        if (defined('DOING_AJAX') && DOING_AJAX) {
2922
-            $template_path = EE_ADMIN_TEMPLATE . 'admin_details_wrapper_no_sidebar_ajax.template.php';
2923
-        }
2924
-        $template_path                                     = ! empty($this->_column_template_path)
2925
-            ? $this->_column_template_path : $template_path;
2926
-        $this->_template_args['post_body_content']         = isset($this->_template_args['admin_page_content'])
2927
-            ? $this->_template_args['admin_page_content']
2928
-            : '';
2929
-        $this->_template_args['before_admin_page_content'] = isset($this->_template_args['before_admin_page_content'])
2930
-            ? $this->_template_args['before_admin_page_content']
2931
-            : '';
2932
-        $this->_template_args['after_admin_page_content']  = isset($this->_template_args['after_admin_page_content'])
2933
-            ? $this->_template_args['after_admin_page_content']
2934
-            : '';
2935
-        $this->_template_args['admin_page_content']        = EEH_Template::display_template(
2936
-            $template_path,
2937
-            $this->_template_args,
2938
-            true
2939
-        );
2940
-        // the final template wrapper
2941
-        $this->admin_page_wrapper($about);
2942
-    }
2943
-
2944
-
2945
-
2946
-    /**
2947
-     * This is used to display caf preview pages.
2948
-     *
2949
-     * @since 4.3.2
2950
-     * @param string $utm_campaign_source what is the key used for google analytics link
2951
-     * @param bool   $display_sidebar     whether to use the sidebar template or the full template for the page.  TRUE
2952
-     *                                    = SHOW sidebar, FALSE = no sidebar. Default no sidebar.
2953
-     * @return void
2954
-     * @throws DomainException
2955
-     * @throws EE_Error
2956
-     * @throws InvalidArgumentException
2957
-     * @throws InvalidDataTypeException
2958
-     * @throws InvalidInterfaceException
2959
-     */
2960
-    public function display_admin_caf_preview_page($utm_campaign_source = '', $display_sidebar = true)
2961
-    {
2962
-        //let's generate a default preview action button if there isn't one already present.
2963
-        $this->_labels['buttons']['buy_now']           = esc_html__(
2964
-            'Upgrade to Event Espresso 4 Right Now',
2965
-            'event_espresso'
2966
-        );
2967
-        $buy_now_url                                   = add_query_arg(
2968
-            array(
2969
-                'ee_ver'       => 'ee4',
2970
-                'utm_source'   => 'ee4_plugin_admin',
2971
-                'utm_medium'   => 'link',
2972
-                'utm_campaign' => $utm_campaign_source,
2973
-                'utm_content'  => 'buy_now_button',
2974
-            ),
2975
-            'http://eventespresso.com/pricing/'
2976
-        );
2977
-        $this->_template_args['preview_action_button'] = ! isset($this->_template_args['preview_action_button'])
2978
-            ? $this->get_action_link_or_button(
2979
-                '',
2980
-                'buy_now',
2981
-                array(),
2982
-                'button-primary button-large',
2983
-                $buy_now_url,
2984
-                true
2985
-            )
2986
-            : $this->_template_args['preview_action_button'];
2987
-        $this->_template_args['admin_page_content']    = EEH_Template::display_template(
2988
-            EE_ADMIN_TEMPLATE . 'admin_caf_full_page_preview.template.php',
2989
-            $this->_template_args,
2990
-            true
2991
-        );
2992
-        $this->_display_admin_page($display_sidebar);
2993
-    }
2994
-
2995
-
2996
-
2997
-    /**
2998
-     * display_admin_list_table_page_with_sidebar
2999
-     * generates HTML wrapper for an admin_page with list_table
3000
-     *
3001
-     * @return void
3002
-     * @throws EE_Error
3003
-     * @throws DomainException
3004
-     */
3005
-    public function display_admin_list_table_page_with_sidebar()
3006
-    {
3007
-        $this->_display_admin_list_table_page(true);
3008
-    }
3009
-
3010
-
3011
-
3012
-    /**
3013
-     * display_admin_list_table_page_with_no_sidebar
3014
-     * generates HTML wrapper for an admin_page with list_table (but with no sidebar)
3015
-     *
3016
-     * @return void
3017
-     * @throws EE_Error
3018
-     * @throws DomainException
3019
-     */
3020
-    public function display_admin_list_table_page_with_no_sidebar()
3021
-    {
3022
-        $this->_display_admin_list_table_page();
3023
-    }
3024
-
3025
-
3026
-
3027
-    /**
3028
-     * generates html wrapper for an admin_list_table page
3029
-     *
3030
-     * @param boolean $sidebar whether to display with sidebar or not.
3031
-     * @return void
3032
-     * @throws DomainException
3033
-     * @throws EE_Error
3034
-     */
3035
-    private function _display_admin_list_table_page($sidebar = false)
3036
-    {
3037
-        //setup search attributes
3038
-        $this->_set_search_attributes();
3039
-        $this->_template_args['current_page']     = $this->_wp_page_slug;
3040
-        $template_path                            = EE_ADMIN_TEMPLATE . 'admin_list_wrapper.template.php';
3041
-        $this->_template_args['table_url']        = defined('DOING_AJAX')
3042
-            ? add_query_arg(array('noheader' => 'true', 'route' => $this->_req_action), $this->_admin_base_url)
3043
-            : add_query_arg(array('route' => $this->_req_action), $this->_admin_base_url);
3044
-        $this->_template_args['list_table']       = $this->_list_table_object;
3045
-        $this->_template_args['current_route']    = $this->_req_action;
3046
-        $this->_template_args['list_table_class'] = get_class($this->_list_table_object);
3047
-        $ajax_sorting_callback                    = $this->_list_table_object->get_ajax_sorting_callback();
3048
-        if (! empty($ajax_sorting_callback)) {
3049
-            $sortable_list_table_form_fields = wp_nonce_field(
3050
-                $ajax_sorting_callback . '_nonce',
3051
-                $ajax_sorting_callback . '_nonce',
3052
-                false,
3053
-                false
3054
-            );
3055
-            //			$reorder_action = 'espresso_' . $ajax_sorting_callback . '_nonce';
3056
-            //			$sortable_list_table_form_fields = wp_nonce_field( $reorder_action, 'ajax_table_sort_nonce', FALSE, FALSE );
3057
-            $sortable_list_table_form_fields .= '<input type="hidden" id="ajax_table_sort_page" name="ajax_table_sort_page" value="'
3058
-                                                . $this->page_slug
3059
-                                                . '" />';
3060
-            $sortable_list_table_form_fields .= '<input type="hidden" id="ajax_table_sort_action" name="ajax_table_sort_action" value="'
3061
-                                                . $ajax_sorting_callback
3062
-                                                . '" />';
3063
-        } else {
3064
-            $sortable_list_table_form_fields = '';
3065
-        }
3066
-        $this->_template_args['sortable_list_table_form_fields'] = $sortable_list_table_form_fields;
3067
-        $hidden_form_fields                                      = isset($this->_template_args['list_table_hidden_fields'])
3068
-            ? $this->_template_args['list_table_hidden_fields']
3069
-            : '';
3070
-        $nonce_ref                                               = $this->_req_action . '_nonce';
3071
-        $hidden_form_fields                                      .= '<input type="hidden" name="'
3072
-                                                                    . $nonce_ref
3073
-                                                                    . '" value="'
3074
-                                                                    . wp_create_nonce($nonce_ref)
3075
-                                                                    . '">';
3076
-        $this->_template_args['list_table_hidden_fields']        = $hidden_form_fields;
3077
-        //display message about search results?
3078
-        $this->_template_args['before_list_table'] .= ! empty($this->_req_data['s'])
3079
-            ? '<p class="ee-search-results">' . sprintf(
3080
-                esc_html__('Displaying search results for the search string: %1$s', 'event_espresso'),
3081
-                trim($this->_req_data['s'], '%')
3082
-            ) . '</p>'
3083
-            : '';
3084
-        // filter before_list_table template arg
3085
-        $this->_template_args['before_list_table'] = apply_filters(
3086
-            'FHEE__EE_Admin_Page___display_admin_list_table_page__before_list_table__template_arg',
3087
-            $this->_template_args['before_list_table'],
3088
-            $this->page_slug,
3089
-            $this->_req_data,
3090
-            $this->_req_action
3091
-        );
3092
-        // convert to array and filter again
3093
-        // arrays are easier to inject new items in a specific location,
3094
-        // but would not be backwards compatible, so we have to add a new filter
3095
-        $this->_template_args['before_list_table'] = implode(
3096
-            " \n",
3097
-            (array)apply_filters(
3098
-                'FHEE__EE_Admin_Page___display_admin_list_table_page__before_list_table__template_args_array',
3099
-                (array)$this->_template_args['before_list_table'],
3100
-                $this->page_slug,
3101
-                $this->_req_data,
3102
-                $this->_req_action
3103
-            )
3104
-        );
3105
-        // filter after_list_table template arg
3106
-        $this->_template_args['after_list_table'] = apply_filters(
3107
-            'FHEE__EE_Admin_Page___display_admin_list_table_page__after_list_table__template_arg',
3108
-            $this->_template_args['after_list_table'],
3109
-            $this->page_slug,
3110
-            $this->_req_data,
3111
-            $this->_req_action
3112
-        );
3113
-        // convert to array and filter again
3114
-        // arrays are easier to inject new items in a specific location,
3115
-        // but would not be backwards compatible, so we have to add a new filter
3116
-        $this->_template_args['after_list_table']   = implode(
3117
-            " \n",
3118
-            (array)apply_filters(
3119
-                'FHEE__EE_Admin_Page___display_admin_list_table_page__after_list_table__template_args_array',
3120
-                (array)$this->_template_args['after_list_table'],
3121
-                $this->page_slug,
3122
-                $this->_req_data,
3123
-                $this->_req_action
3124
-            )
3125
-        );
3126
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
3127
-            $template_path,
3128
-            $this->_template_args,
3129
-            true
3130
-        );
3131
-        // the final template wrapper
3132
-        if ($sidebar) {
3133
-            $this->display_admin_page_with_sidebar();
3134
-        } else {
3135
-            $this->display_admin_page_with_no_sidebar();
3136
-        }
3137
-    }
3138
-
3139
-
3140
-
3141
-    /**
3142
-     * This just prepares a legend using the given items and the admin_details_legend.template.php file and returns the
3143
-     * html string for the legend.
3144
-     * $items are expected in an array in the following format:
3145
-     * $legend_items = array(
3146
-     *        'item_id' => array(
3147
-     *            'icon' => 'http://url_to_icon_being_described.png',
3148
-     *            'desc' => esc_html__('localized description of item');
3149
-     *        )
3150
-     * );
3151
-     *
3152
-     * @param  array $items see above for format of array
3153
-     * @return string html string of legend
3154
-     * @throws DomainException
3155
-     */
3156
-    protected function _display_legend($items)
3157
-    {
3158
-        $this->_template_args['items'] = apply_filters(
3159
-            'FHEE__EE_Admin_Page___display_legend__items',
3160
-            (array)$items,
3161
-            $this
3162
-        );
3163
-        return EEH_Template::display_template(
3164
-            EE_ADMIN_TEMPLATE . 'admin_details_legend.template.php',
3165
-            $this->_template_args,
3166
-            true
3167
-        );
3168
-    }
3169
-
3170
-
3171
-    /**
3172
-     * This is used whenever we're DOING_AJAX to return a formatted json array that our calling javascript can expect
3173
-     * The returned json object is created from an array in the following format:
3174
-     * array(
3175
-     *  'error' => FALSE, //(default FALSE), contains any errors and/or exceptions (exceptions return json early),
3176
-     *  'success' => FALSE, //(default FALSE) - contains any special success message.
3177
-     *  'notices' => '', // - contains any EE_Error formatted notices
3178
-     *  'content' => 'string can be html', //this is a string of formatted content (can be html)
3179
-     *  'data' => array() //this can be any key/value pairs that a method returns for later json parsing by the js.
3180
-     *  We're also going to include the template args with every package (so js can pick out any specific template args
3181
-     *  that might be included in here)
3182
-     * )
3183
-     * The json object is populated by whatever is set in the $_template_args property.
3184
-     *
3185
-     * @param bool  $sticky_notices    Used to indicate whether you want to ensure notices are added to a transient
3186
-     *                                 instead of displayed.
3187
-     * @param array $notices_arguments Use this to pass any additional args on to the _process_notices.
3188
-     * @return void
3189
-     * @throws EE_Error
3190
-     */
3191
-    protected function _return_json($sticky_notices = false, $notices_arguments = array())
3192
-    {
3193
-        //make sure any EE_Error notices have been handled.
3194
-        $this->_process_notices($notices_arguments, true, $sticky_notices);
3195
-        $data = isset($this->_template_args['data']) ? $this->_template_args['data'] : array();
3196
-        unset($this->_template_args['data']);
3197
-        $json = array(
3198
-            'error'     => isset($this->_template_args['error']) ? $this->_template_args['error'] : false,
3199
-            'success'   => isset($this->_template_args['success']) ? $this->_template_args['success'] : false,
3200
-            'errors'    => isset($this->_template_args['errors']) ? $this->_template_args['errors'] : false,
3201
-            'attention' => isset($this->_template_args['attention']) ? $this->_template_args['attention'] : false,
3202
-            'notices'   => EE_Error::get_notices(),
3203
-            'content'   => isset($this->_template_args['admin_page_content'])
3204
-                ? $this->_template_args['admin_page_content'] : '',
3205
-            'data'      => array_merge($data, array('template_args' => $this->_template_args)),
3206
-            'isEEajax'  => true
3207
-            //special flag so any ajax.Success methods in js can identify this return package as a EEajax package.
3208
-        );
3209
-        // make sure there are no php errors or headers_sent.  Then we can set correct json header.
3210
-        if (null === error_get_last() || ! headers_sent()) {
3211
-            header('Content-Type: application/json; charset=UTF-8');
3212
-        }
3213
-        echo wp_json_encode($json);
3214
-        exit();
3215
-    }
3216
-
3217
-
3218
-
3219
-    /**
3220
-     * Simply a wrapper for the protected method so we can call this outside the class (ONLY when doing ajax)
3221
-     *
3222
-     * @return void
3223
-     * @throws EE_Error
3224
-     */
3225
-    public function return_json()
3226
-    {
3227
-        if (defined('DOING_AJAX') && DOING_AJAX) {
3228
-            $this->_return_json();
3229
-        } else {
3230
-            throw new EE_Error(
3231
-                sprintf(
3232
-                    esc_html__('The public %s method can only be called when DOING_AJAX = TRUE', 'event_espresso'),
3233
-                    __FUNCTION__
3234
-                )
3235
-            );
3236
-        }
3237
-    }
3238
-
3239
-
3240
-
3241
-    /**
3242
-     * This provides a way for child hook classes to send along themselves by reference so methods/properties within
3243
-     * them can be accessed by EE_Admin_child pages. This is assigned to the $_hook_obj property.
3244
-     *
3245
-     * @param EE_Admin_Hooks $hook_obj This will be the object for the EE_Admin_Hooks child
3246
-     */
3247
-    public function set_hook_object(EE_Admin_Hooks $hook_obj)
3248
-    {
3249
-        $this->_hook_obj = $hook_obj;
3250
-    }
3251
-
3252
-
3253
-
3254
-    /**
3255
-     *        generates  HTML wrapper with Tabbed nav for an admin page
3256
-     *
3257
-     * @param  boolean $about whether to use the special about page wrapper or default.
3258
-     * @return void
3259
-     * @throws DomainException
3260
-     * @throws EE_Error
3261
-     */
3262
-    public function admin_page_wrapper($about = false)
3263
-    {
3264
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3265
-        $this->_nav_tabs                                   = $this->_get_main_nav_tabs();
3266
-        $this->_template_args['nav_tabs']                  = $this->_nav_tabs;
3267
-        $this->_template_args['admin_page_title']          = $this->_admin_page_title;
3268
-        $this->_template_args['before_admin_page_content'] = apply_filters(
3269
-            "FHEE_before_admin_page_content{$this->_current_page}{$this->_current_view}",
3270
-            isset($this->_template_args['before_admin_page_content'])
3271
-                ? $this->_template_args['before_admin_page_content']
3272
-                : ''
3273
-        );
3274
-        $this->_template_args['after_admin_page_content']  = apply_filters(
3275
-            "FHEE_after_admin_page_content{$this->_current_page}{$this->_current_view}",
3276
-            isset($this->_template_args['after_admin_page_content'])
3277
-                ? $this->_template_args['after_admin_page_content']
3278
-                : ''
3279
-        );
3280
-        $this->_template_args['after_admin_page_content']  .= $this->_set_help_popup_content();
3281
-        // load settings page wrapper template
3282
-        $template_path = ! defined('DOING_AJAX')
3283
-            ? EE_ADMIN_TEMPLATE . 'admin_wrapper.template.php'
3284
-            : EE_ADMIN_TEMPLATE
3285
-              . 'admin_wrapper_ajax.template.php';
3286
-        //about page?
3287
-        $template_path = $about
3288
-            ? EE_ADMIN_TEMPLATE . 'about_admin_wrapper.template.php'
3289
-            : $template_path;
3290
-        if (defined('DOING_AJAX')) {
3291
-            $this->_template_args['admin_page_content'] = EEH_Template::display_template(
3292
-                $template_path,
3293
-                $this->_template_args,
3294
-                true
3295
-            );
3296
-            $this->_return_json();
3297
-        } else {
3298
-            EEH_Template::display_template($template_path, $this->_template_args);
3299
-        }
3300
-    }
3301
-
3302
-
3303
-
3304
-    /**
3305
-     * This returns the admin_nav tabs html using the configuration in the _nav_tabs property
3306
-     *
3307
-     * @return string html
3308
-     * @throws EE_Error
3309
-     */
3310
-    protected function _get_main_nav_tabs()
3311
-    {
3312
-        // let's generate the html using the EEH_Tabbed_Content helper.
3313
-        // We do this here so that it's possible for child classes to add in nav tabs dynamically at the last minute
3314
-        // (rather than setting in the page_routes array)
3315
-        return EEH_Tabbed_Content::display_admin_nav_tabs($this->_nav_tabs);
3316
-    }
3317
-
3318
-
3319
-
3320
-    /**
3321
-     *        sort nav tabs
3322
-     *
3323
-     * @param $a
3324
-     * @param $b
3325
-     * @return int
3326
-     */
3327
-    private function _sort_nav_tabs($a, $b)
3328
-    {
3329
-        if ($a['order'] === $b['order']) {
3330
-            return 0;
3331
-        }
3332
-        return ($a['order'] < $b['order']) ? -1 : 1;
3333
-    }
3334
-
3335
-
3336
-
3337
-    /**
3338
-     *    generates HTML for the forms used on admin pages
3339
-     *
3340
-     * @param    array $input_vars - array of input field details
3341
-     * @param string   $generator  (options are 'string' or 'array', basically use this to indicate which generator to
3342
-     *                             use)
3343
-     * @param bool     $id
3344
-     * @return string
3345
-     * @uses   EEH_Form_Fields::get_form_fields (/helper/EEH_Form_Fields.helper.php)
3346
-     * @uses   EEH_Form_Fields::get_form_fields_array (/helper/EEH_Form_Fields.helper.php)
3347
-     */
3348
-    protected function _generate_admin_form_fields($input_vars = array(), $generator = 'string', $id = false)
3349
-    {
3350
-        $content = $generator === 'string'
3351
-            ? EEH_Form_Fields::get_form_fields($input_vars, $id)
3352
-            : EEH_Form_Fields::get_form_fields_array($input_vars);
3353
-        return $content;
3354
-    }
3355
-
3356
-
3357
-
3358
-    /**
3359
-     * generates the "Save" and "Save & Close" buttons for edit forms
3360
-     *
3361
-     * @param bool             $both     if true then both buttons will be generated.  If false then just the "Save &
3362
-     *                                   Close" button.
3363
-     * @param array            $text     if included, generator will use the given text for the buttons ( array([0] =>
3364
-     *                                   'Save', [1] => 'save & close')
3365
-     * @param array            $actions  if included allows us to set the actions that each button will carry out (i.e.
3366
-     *                                   via the "name" value in the button).  We can also use this to just dump
3367
-     *                                   default actions by submitting some other value.
3368
-     * @param bool|string|null $referrer if false then we just do the default action on save and close.  Other wise it
3369
-     *                                   will use the $referrer string. IF null, then we don't do ANYTHING on save and
3370
-     *                                   close (normal form handling).
3371
-     */
3372
-    protected function _set_save_buttons($both = true, $text = array(), $actions = array(), $referrer = null)
3373
-    {
3374
-        //make sure $text and $actions are in an array
3375
-        $text          = (array)$text;
3376
-        $actions       = (array)$actions;
3377
-        $referrer_url  = empty($referrer)
3378
-            ? '<input type="hidden" id="save_and_close_referrer" name="save_and_close_referrer" value="'
3379
-              . $_SERVER['REQUEST_URI']
3380
-              . '" />'
3381
-            : '<input type="hidden" id="save_and_close_referrer" name="save_and_close_referrer" value="'
3382
-              . $referrer
3383
-              . '" />';
3384
-        $button_text   = ! empty($text)
3385
-            ? $text
3386
-            : array(
3387
-                esc_html__('Save', 'event_espresso'),
3388
-                esc_html__('Save and Close', 'event_espresso'),
3389
-            );
3390
-        $default_names = array('save', 'save_and_close');
3391
-        //add in a hidden index for the current page (so save and close redirects properly)
3392
-        $this->_template_args['save_buttons'] = $referrer_url;
3393
-        foreach ($button_text as $key => $button) {
3394
-            $ref                                  = $default_names[$key];
3395
-            $this->_template_args['save_buttons'] .= '<input type="submit" class="button-primary '
3396
-                                                     . $ref
3397
-                                                     . '" value="'
3398
-                                                     . $button
3399
-                                                     . '" name="'
3400
-                                                     . (! empty($actions) ? $actions[$key] : $ref)
3401
-                                                     . '" id="'
3402
-                                                     . $this->_current_view . '_' . $ref
3403
-                                                     . '" />';
3404
-            if (! $both) {
3405
-                break;
3406
-            }
3407
-        }
3408
-    }
3409
-
3410
-
3411
-
3412
-    /**
3413
-     * Wrapper for the protected function.  Allows plugins/addons to call this to set the form tags.
3414
-     *
3415
-     * @see   $this->_set_add_edit_form_tags() for details on params
3416
-     * @since 4.6.0
3417
-     * @param string $route
3418
-     * @param array  $additional_hidden_fields
3419
-     */
3420
-    public function set_add_edit_form_tags($route = '', $additional_hidden_fields = array())
3421
-    {
3422
-        $this->_set_add_edit_form_tags($route, $additional_hidden_fields);
3423
-    }
3424
-
3425
-
3426
-
3427
-    /**
3428
-     * set form open and close tags on add/edit pages.
3429
-     *
3430
-     * @param string $route                    the route you want the form to direct to
3431
-     * @param array  $additional_hidden_fields any additional hidden fields required in the form header
3432
-     * @return void
3433
-     */
3434
-    protected function _set_add_edit_form_tags($route = '', $additional_hidden_fields = array())
3435
-    {
3436
-        if (empty($route)) {
3437
-            $user_msg = esc_html__(
3438
-                'An error occurred. No action was set for this page\'s form.',
3439
-                'event_espresso'
3440
-            );
3441
-            $dev_msg  = $user_msg . "\n" . sprintf(
3442
-                    esc_html__('The $route argument is required for the %s->%s method.', 'event_espresso'),
3443
-                    __FUNCTION__,
3444
-                    __CLASS__
3445
-                );
3446
-            EE_Error::add_error($user_msg . '||' . $dev_msg, __FILE__, __FUNCTION__, __LINE__);
3447
-        }
3448
-        // open form
3449
-        $this->_template_args['before_admin_page_content'] = '<form name="form" method="post" action="'
3450
-                                                             . $this->_admin_base_url
3451
-                                                             . '" id="'
3452
-                                                             . $route
3453
-                                                             . '_event_form" >';
3454
-        // add nonce
3455
-        $nonce = wp_nonce_field($route . '_nonce', $route . '_nonce', false, false);
3456
-        //		$nonce = wp_nonce_field( $route . '_nonce', '_wpnonce', FALSE, FALSE );
3457
-        $this->_template_args['before_admin_page_content'] .= "\n\t" . $nonce;
3458
-        // add REQUIRED form action
3459
-        $hidden_fields = array(
3460
-            'action' => array('type' => 'hidden', 'value' => $route),
3461
-        );
3462
-        // merge arrays
3463
-        $hidden_fields = is_array($additional_hidden_fields)
3464
-            ? array_merge($hidden_fields, $additional_hidden_fields)
3465
-            : $hidden_fields;
3466
-        // generate form fields
3467
-        $form_fields = $this->_generate_admin_form_fields($hidden_fields, 'array');
3468
-        // add fields to form
3469
-        foreach ((array)$form_fields as $field_name => $form_field) {
3470
-            $this->_template_args['before_admin_page_content'] .= "\n\t" . $form_field['field'];
3471
-        }
3472
-        // close form
3473
-        $this->_template_args['after_admin_page_content'] = '</form>';
3474
-    }
3475
-
3476
-
3477
-
3478
-    /**
3479
-     * Public Wrapper for _redirect_after_action() method since its
3480
-     * discovered it would be useful for external code to have access.
3481
-     *
3482
-     * @see   EE_Admin_Page::_redirect_after_action() for params.
3483
-     * @since 4.5.0
3484
-     * @param bool   $success
3485
-     * @param string $what
3486
-     * @param string $action_desc
3487
-     * @param array  $query_args
3488
-     * @param bool   $override_overwrite
3489
-     * @throws EE_Error
3490
-     */
3491
-    public function redirect_after_action(
3492
-        $success = false,
3493
-        $what = 'item',
3494
-        $action_desc = 'processed',
3495
-        $query_args = array(),
3496
-        $override_overwrite = false
3497
-    ) {
3498
-        $this->_redirect_after_action(
3499
-            $success,
3500
-            $what,
3501
-            $action_desc,
3502
-            $query_args,
3503
-            $override_overwrite
3504
-        );
3505
-    }
3506
-
3507
-
3508
-
3509
-    /**
3510
-     *    _redirect_after_action
3511
-     *
3512
-     * @param int    $success            - whether success was for two or more records, or just one, or none
3513
-     * @param string $what               - what the action was performed on
3514
-     * @param string $action_desc        - what was done ie: updated, deleted, etc
3515
-     * @param array  $query_args         - an array of query_args to be added to the URL to redirect to after the admin
3516
-     *                                   action is completed
3517
-     * @param BOOL   $override_overwrite by default all EE_Error::success messages are overwritten, this allows you to
3518
-     *                                   override this so that they show.
3519
-     * @return void
3520
-     * @throws EE_Error
3521
-     */
3522
-    protected function _redirect_after_action(
3523
-        $success = 0,
3524
-        $what = 'item',
3525
-        $action_desc = 'processed',
3526
-        $query_args = array(),
3527
-        $override_overwrite = false
3528
-    ) {
3529
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3530
-        //class name for actions/filters.
3531
-        $classname = get_class($this);
3532
-        // set redirect url.
3533
-        // Note if there is a "page" index in the $query_args then we go with vanilla admin.php route,
3534
-        // otherwise we go with whatever is set as the _admin_base_url
3535
-        $redirect_url = isset($query_args['page']) ? admin_url('admin.php') : $this->_admin_base_url;
3536
-        $notices      = EE_Error::get_notices(false);
3537
-        // overwrite default success messages //BUT ONLY if overwrite not overridden
3538
-        if (! $override_overwrite || ! empty($notices['errors'])) {
3539
-            EE_Error::overwrite_success();
3540
-        }
3541
-        if (! empty($what) && ! empty($action_desc)  && empty($notices['errors'])) {
3542
-            // how many records affected ? more than one record ? or just one ?
3543
-            if ($success > 1) {
3544
-                // set plural msg
3545
-                EE_Error::add_success(
3546
-                    sprintf(
3547
-                        esc_html__('The "%s" have been successfully %s.', 'event_espresso'),
3548
-                        $what,
3549
-                        $action_desc
3550
-                    ),
3551
-                    __FILE__,
3552
-                    __FUNCTION__,
3553
-                    __LINE__
3554
-                );
3555
-            } elseif ($success === 1) {
3556
-                // set singular msg
3557
-                EE_Error::add_success(
3558
-                    sprintf(
3559
-                        esc_html__('The "%s" has been successfully %s.', 'event_espresso'),
3560
-                        $what,
3561
-                        $action_desc
3562
-                    ),
3563
-                    __FILE__,
3564
-                    __FUNCTION__,
3565
-                    __LINE__
3566
-                );
3567
-            }
3568
-        }
3569
-        // check that $query_args isn't something crazy
3570
-        if (! is_array($query_args)) {
3571
-            $query_args = array();
3572
-        }
3573
-        /**
3574
-         * Allow injecting actions before the query_args are modified for possible different
3575
-         * redirections on save and close actions
3576
-         *
3577
-         * @since 4.2.0
3578
-         * @param array $query_args       The original query_args array coming into the
3579
-         *                                method.
3580
-         */
3581
-        do_action(
3582
-            "AHEE__{$classname}___redirect_after_action__before_redirect_modification_{$this->_req_action}",
3583
-            $query_args
3584
-        );
3585
-        //calculate where we're going (if we have a "save and close" button pushed)
3586
-        if (isset($this->_req_data['save_and_close'], $this->_req_data['save_and_close_referrer'])) {
3587
-            // even though we have the save_and_close referrer, we need to parse the url for the action in order to generate a nonce
3588
-            $parsed_url = parse_url($this->_req_data['save_and_close_referrer']);
3589
-            // regenerate query args array from referrer URL
3590
-            parse_str($parsed_url['query'], $query_args);
3591
-            // correct page and action will be in the query args now
3592
-            $redirect_url = admin_url('admin.php');
3593
-        }
3594
-        //merge any default query_args set in _default_route_query_args property
3595
-        if (! empty($this->_default_route_query_args) && ! $this->_is_UI_request) {
3596
-            $args_to_merge = array();
3597
-            foreach ($this->_default_route_query_args as $query_param => $query_value) {
3598
-                //is there a wp_referer array in our _default_route_query_args property?
3599
-                if ($query_param === 'wp_referer') {
3600
-                    $query_value = (array)$query_value;
3601
-                    foreach ($query_value as $reference => $value) {
3602
-                        if (strpos($reference, 'nonce') !== false) {
3603
-                            continue;
3604
-                        }
3605
-                        //finally we will override any arguments in the referer with
3606
-                        //what might be set on the _default_route_query_args array.
3607
-                        if (isset($this->_default_route_query_args[$reference])) {
3608
-                            $args_to_merge[$reference] = urlencode($this->_default_route_query_args[$reference]);
3609
-                        } else {
3610
-                            $args_to_merge[$reference] = urlencode($value);
3611
-                        }
3612
-                    }
3613
-                    continue;
3614
-                }
3615
-                $args_to_merge[$query_param] = $query_value;
3616
-            }
3617
-            //now let's merge these arguments but override with what was specifically sent in to the
3618
-            //redirect.
3619
-            $query_args = array_merge($args_to_merge, $query_args);
3620
-        }
3621
-        $this->_process_notices($query_args);
3622
-        // generate redirect url
3623
-        // if redirecting to anything other than the main page, add a nonce
3624
-        if (isset($query_args['action'])) {
3625
-            // manually generate wp_nonce and merge that with the query vars
3626
-            // becuz the wp_nonce_url function wrecks havoc on some vars
3627
-            $query_args['_wpnonce'] = wp_create_nonce($query_args['action'] . '_nonce');
3628
-        }
3629
-        // we're adding some hooks and filters in here for processing any things just before redirects
3630
-        // (example: an admin page has done an insert or update and we want to run something after that).
3631
-        do_action('AHEE_redirect_' . $classname . $this->_req_action, $query_args);
3632
-        $redirect_url = apply_filters(
3633
-            'FHEE_redirect_' . $classname . $this->_req_action,
3634
-            self::add_query_args_and_nonce($query_args, $redirect_url),
3635
-            $query_args
3636
-        );
3637
-        // check if we're doing ajax.  If we are then lets just return the results and js can handle how it wants.
3638
-        if (defined('DOING_AJAX')) {
3639
-            $default_data                    = array(
3640
-                'close'        => true,
3641
-                'redirect_url' => $redirect_url,
3642
-                'where'        => 'main',
3643
-                'what'         => 'append',
3644
-            );
3645
-            $this->_template_args['success'] = $success;
3646
-            $this->_template_args['data']    = ! empty($this->_template_args['data']) ? array_merge(
3647
-                $default_data,
3648
-                $this->_template_args['data']
3649
-            ) : $default_data;
3650
-            $this->_return_json();
3651
-        }
3652
-        wp_safe_redirect($redirect_url);
3653
-        exit();
3654
-    }
3655
-
3656
-
3657
-
3658
-    /**
3659
-     * process any notices before redirecting (or returning ajax request)
3660
-     * This method sets the $this->_template_args['notices'] attribute;
3661
-     *
3662
-     * @param  array $query_args        any query args that need to be used for notice transient ('action')
3663
-     * @param bool   $skip_route_verify This is typically used when we are processing notices REALLY early and
3664
-     *                                  page_routes haven't been defined yet.
3665
-     * @param bool   $sticky_notices    This is used to flag that regardless of whether this is doing_ajax or not, we
3666
-     *                                  still save a transient for the notice.
3667
-     * @return void
3668
-     * @throws EE_Error
3669
-     */
3670
-    protected function _process_notices($query_args = array(), $skip_route_verify = false, $sticky_notices = true)
3671
-    {
3672
-        //first let's set individual error properties if doing_ajax and the properties aren't already set.
3673
-        if (defined('DOING_AJAX') && DOING_AJAX) {
3674
-            $notices = EE_Error::get_notices(false);
3675
-            if (empty($this->_template_args['success'])) {
3676
-                $this->_template_args['success'] = isset($notices['success']) ? $notices['success'] : false;
3677
-            }
3678
-            if (empty($this->_template_args['errors'])) {
3679
-                $this->_template_args['errors'] = isset($notices['errors']) ? $notices['errors'] : false;
3680
-            }
3681
-            if (empty($this->_template_args['attention'])) {
3682
-                $this->_template_args['attention'] = isset($notices['attention']) ? $notices['attention'] : false;
3683
-            }
3684
-        }
3685
-        $this->_template_args['notices'] = EE_Error::get_notices();
3686
-        //IF this isn't ajax we need to create a transient for the notices using the route (however, overridden if $sticky_notices == true)
3687
-        if (! defined('DOING_AJAX') || $sticky_notices) {
3688
-            $route = isset($query_args['action']) ? $query_args['action'] : 'default';
3689
-            $this->_add_transient(
3690
-                $route,
3691
-                $this->_template_args['notices'],
3692
-                true,
3693
-                $skip_route_verify
3694
-            );
3695
-        }
3696
-    }
3697
-
3698
-
3699
-
3700
-    /**
3701
-     * get_action_link_or_button
3702
-     * returns the button html for adding, editing, or deleting an item (depending on given type)
3703
-     *
3704
-     * @param string $action        use this to indicate which action the url is generated with.
3705
-     * @param string $type          accepted strings must be defined in the $_labels['button'] array(as the key)
3706
-     *                              property.
3707
-     * @param array  $extra_request if the button requires extra params you can include them in $key=>$value pairs.
3708
-     * @param string $class         Use this to give the class for the button. Defaults to 'button-primary'
3709
-     * @param string $base_url      If this is not provided
3710
-     *                              the _admin_base_url will be used as the default for the button base_url.
3711
-     *                              Otherwise this value will be used.
3712
-     * @param bool   $exclude_nonce If true then no nonce will be in the generated button link.
3713
-     * @return string
3714
-     * @throws InvalidArgumentException
3715
-     * @throws InvalidInterfaceException
3716
-     * @throws InvalidDataTypeException
3717
-     * @throws EE_Error
3718
-     */
3719
-    public function get_action_link_or_button(
3720
-        $action,
3721
-        $type = 'add',
3722
-        $extra_request = array(),
3723
-        $class = 'button-primary',
3724
-        $base_url = '',
3725
-        $exclude_nonce = false
3726
-    ) {
3727
-        //first let's validate the action (if $base_url is FALSE otherwise validation will happen further along)
3728
-        if (empty($base_url) && ! isset($this->_page_routes[$action])) {
3729
-            throw new EE_Error(
3730
-                sprintf(
3731
-                    esc_html__(
3732
-                        'There is no page route for given action for the button.  This action was given: %s',
3733
-                        'event_espresso'
3734
-                    ),
3735
-                    $action
3736
-                )
3737
-            );
3738
-        }
3739
-        if (! isset($this->_labels['buttons'][$type])) {
3740
-            throw new EE_Error(
3741
-                sprintf(
3742
-                    __(
3743
-                        'There is no label for the given button type (%s). Labels are set in the <code>_page_config</code> property.',
3744
-                        'event_espresso'
3745
-                    ),
3746
-                    $type
3747
-                )
3748
-            );
3749
-        }
3750
-        //finally check user access for this button.
3751
-        $has_access = $this->check_user_access($action, true);
3752
-        if (! $has_access) {
3753
-            return '';
3754
-        }
3755
-        $_base_url  = ! $base_url ? $this->_admin_base_url : $base_url;
3756
-        $query_args = array(
3757
-            'action' => $action,
3758
-        );
3759
-        //merge extra_request args but make sure our original action takes precedence and doesn't get overwritten.
3760
-        if (! empty($extra_request)) {
3761
-            $query_args = array_merge($extra_request, $query_args);
3762
-        }
3763
-        $url = self::add_query_args_and_nonce($query_args, $_base_url, false, $exclude_nonce);
3764
-        return EEH_Template::get_button_or_link($url, $this->_labels['buttons'][$type], $class);
3765
-    }
3766
-
3767
-
3768
-
3769
-    /**
3770
-     * _per_page_screen_option
3771
-     * Utility function for adding in a per_page_option in the screen_options_dropdown.
3772
-     *
3773
-     * @return void
3774
-     * @throws InvalidArgumentException
3775
-     * @throws InvalidInterfaceException
3776
-     * @throws InvalidDataTypeException
3777
-     */
3778
-    protected function _per_page_screen_option()
3779
-    {
3780
-        $option = 'per_page';
3781
-        $args   = array(
3782
-            'label'   => esc_html__(
3783
-                    apply_filters(
3784
-                        'FHEE__EE_Admin_Page___per_page_screen_options___label',
3785
-                        $this->_admin_page_title,
3786
-                        $this
3787
-                    )
3788
-            ),
3789
-            'default' => (int) apply_filters(
3790
-                    'FHEE__EE_Admin_Page___per_page_screen_options__default',
3791
-                    10
3792
-            ),
3793
-            'option'  => $this->_current_page . '_' . $this->_current_view . '_per_page',
3794
-        );
3795
-        //ONLY add the screen option if the user has access to it.
3796
-        if ($this->check_user_access($this->_current_view, true)) {
3797
-            add_screen_option($option, $args);
3798
-        }
3799
-    }
3800
-
3801
-
3802
-
3803
-    /**
3804
-     * set_per_page_screen_option
3805
-     * All this does is make sure that WordPress saves any per_page screen options (if set) for the current page.
3806
-     * we have to do this rather than running inside the 'set-screen-options' hook because it runs earlier than
3807
-     * admin_menu.
3808
-     *
3809
-     * @return void
3810
-     */
3811
-    private function _set_per_page_screen_options()
3812
-    {
3813
-        if (isset($_POST['wp_screen_options']) && is_array($_POST['wp_screen_options'])) {
3814
-            check_admin_referer('screen-options-nonce', 'screenoptionnonce');
3815
-            if (! $user = wp_get_current_user()) {
3816
-                return;
3817
-            }
3818
-            $option = $_POST['wp_screen_options']['option'];
3819
-            $value  = $_POST['wp_screen_options']['value'];
3820
-            if ($option != sanitize_key($option)) {
3821
-                return;
3822
-            }
3823
-            $map_option = $option;
3824
-            $option     = str_replace('-', '_', $option);
3825
-            switch ($map_option) {
3826
-                case $this->_current_page . '_' . $this->_current_view . '_per_page':
3827
-                    $value = (int)$value;
3828
-                    $max_value = apply_filters(
3829
-                        'FHEE__EE_Admin_Page___set_per_page_screen_options__max_value',
3830
-                        999,
3831
-                        $this->_current_page,
3832
-                        $this->_current_view
3833
-                    );
3834
-                    if ($value < 1) {
3835
-                        return;
3836
-                    }
3837
-                    $value = min($value, $max_value);
3838
-                    break;
3839
-                default:
3840
-                    $value = apply_filters(
3841
-                        'FHEE__EE_Admin_Page___set_per_page_screen_options__value',
3842
-                        false,
3843
-                        $option,
3844
-                        $value
3845
-                    );
3846
-                    if (false === $value) {
3847
-                        return;
3848
-                    }
3849
-                    break;
3850
-            }
3851
-            update_user_meta($user->ID, $option, $value);
3852
-            wp_safe_redirect(remove_query_arg(array('pagenum', 'apage', 'paged'), wp_get_referer()));
3853
-            exit;
3854
-        }
3855
-    }
3856
-
3857
-
3858
-
3859
-    /**
3860
-     * This just allows for setting the $_template_args property if it needs to be set outside the object
3861
-     *
3862
-     * @param array $data array that will be assigned to template args.
3863
-     */
3864
-    public function set_template_args($data)
3865
-    {
3866
-        $this->_template_args = array_merge($this->_template_args, (array)$data);
3867
-    }
3868
-
3869
-
3870
-
3871
-    /**
3872
-     * This makes available the WP transient system for temporarily moving data between routes
3873
-     *
3874
-     * @param string $route             the route that should receive the transient
3875
-     * @param array  $data              the data that gets sent
3876
-     * @param bool   $notices           If this is for notices then we use this to indicate so, otherwise its just a
3877
-     *                                  normal route transient.
3878
-     * @param bool   $skip_route_verify Used to indicate we want to skip route verification.  This is usually ONLY used
3879
-     *                                  when we are adding a transient before page_routes have been defined.
3880
-     * @return void
3881
-     * @throws EE_Error
3882
-     */
3883
-    protected function _add_transient($route, $data, $notices = false, $skip_route_verify = false)
3884
-    {
3885
-        $user_id = get_current_user_id();
3886
-        if (! $skip_route_verify) {
3887
-            $this->_verify_route($route);
3888
-        }
3889
-        //now let's set the string for what kind of transient we're setting
3890
-        $transient = $notices
3891
-            ? 'ee_rte_n_tx_' . $route . '_' . $user_id
3892
-            : 'rte_tx_' . $route . '_' . $user_id;
3893
-        $data      = $notices ? array('notices' => $data) : $data;
3894
-        //is there already a transient for this route?  If there is then let's ADD to that transient
3895
-        $existing = is_multisite() && is_network_admin()
3896
-            ? get_site_transient($transient)
3897
-            : get_transient($transient);
3898
-        if ($existing) {
3899
-            $data = array_merge((array)$data, (array)$existing);
3900
-        }
3901
-        if (is_multisite() && is_network_admin()) {
3902
-            set_site_transient($transient, $data, 8);
3903
-        } else {
3904
-            set_transient($transient, $data, 8);
3905
-        }
3906
-    }
3907
-
3908
-
3909
-
3910
-    /**
3911
-     * this retrieves the temporary transient that has been set for moving data between routes.
3912
-     *
3913
-     * @param bool   $notices true we get notices transient. False we just return normal route transient
3914
-     * @param string $route
3915
-     * @return mixed data
3916
-     */
3917
-    protected function _get_transient($notices = false, $route = '')
3918
-    {
3919
-        $user_id   = get_current_user_id();
3920
-        $route     = ! $route ? $this->_req_action : $route;
3921
-        $transient = $notices
3922
-            ? 'ee_rte_n_tx_' . $route . '_' . $user_id
3923
-            : 'rte_tx_' . $route . '_' . $user_id;
3924
-        $data      = is_multisite() && is_network_admin()
3925
-            ? get_site_transient($transient)
3926
-            : get_transient($transient);
3927
-        //delete transient after retrieval (just in case it hasn't expired);
3928
-        if (is_multisite() && is_network_admin()) {
3929
-            delete_site_transient($transient);
3930
-        } else {
3931
-            delete_transient($transient);
3932
-        }
3933
-        return $notices && isset($data['notices']) ? $data['notices'] : $data;
3934
-    }
3935
-
3936
-
3937
-
3938
-    /**
3939
-     * The purpose of this method is just to run garbage collection on any EE transients that might have expired but
3940
-     * would not be called later. This will be assigned to run on a specific EE Admin page. (place the method in the
3941
-     * default route callback on the EE_Admin page you want it run.)
3942
-     *
3943
-     * @return void
3944
-     */
3945
-    protected function _transient_garbage_collection()
3946
-    {
3947
-        global $wpdb;
3948
-        //retrieve all existing transients
3949
-        $query = "SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE '%rte_tx_%' OR option_name LIKE '%rte_n_tx_%'";
3950
-        if ($results = $wpdb->get_results($query)) {
3951
-            foreach ($results as $result) {
3952
-                $transient = str_replace('_transient_', '', $result->option_name);
3953
-                get_transient($transient);
3954
-                if (is_multisite() && is_network_admin()) {
3955
-                    get_site_transient($transient);
3956
-                }
3957
-            }
3958
-        }
3959
-    }
3960
-
3961
-
3962
-
3963
-    /**
3964
-     * get_view
3965
-     *
3966
-     * @return string content of _view property
3967
-     */
3968
-    public function get_view()
3969
-    {
3970
-        return $this->_view;
3971
-    }
3972
-
3973
-
3974
-
3975
-    /**
3976
-     * getter for the protected $_views property
3977
-     *
3978
-     * @return array
3979
-     */
3980
-    public function get_views()
3981
-    {
3982
-        return $this->_views;
3983
-    }
3984
-
3985
-
3986
-
3987
-    /**
3988
-     * get_current_page
3989
-     *
3990
-     * @return string _current_page property value
3991
-     */
3992
-    public function get_current_page()
3993
-    {
3994
-        return $this->_current_page;
3995
-    }
3996
-
3997
-
3998
-
3999
-    /**
4000
-     * get_current_view
4001
-     *
4002
-     * @return string _current_view property value
4003
-     */
4004
-    public function get_current_view()
4005
-    {
4006
-        return $this->_current_view;
4007
-    }
4008
-
4009
-
4010
-
4011
-    /**
4012
-     * get_current_screen
4013
-     *
4014
-     * @return object The current WP_Screen object
4015
-     */
4016
-    public function get_current_screen()
4017
-    {
4018
-        return $this->_current_screen;
4019
-    }
4020
-
4021
-
4022
-
4023
-    /**
4024
-     * get_current_page_view_url
4025
-     *
4026
-     * @return string This returns the url for the current_page_view.
4027
-     */
4028
-    public function get_current_page_view_url()
4029
-    {
4030
-        return $this->_current_page_view_url;
4031
-    }
4032
-
4033
-
4034
-
4035
-    /**
4036
-     * just returns the _req_data property
4037
-     *
4038
-     * @return array
4039
-     */
4040
-    public function get_request_data()
4041
-    {
4042
-        return $this->_req_data;
4043
-    }
4044
-
4045
-
4046
-
4047
-    /**
4048
-     * returns the _req_data protected property
4049
-     *
4050
-     * @return string
4051
-     */
4052
-    public function get_req_action()
4053
-    {
4054
-        return $this->_req_action;
4055
-    }
4056
-
4057
-
4058
-
4059
-    /**
4060
-     * @return bool  value of $_is_caf property
4061
-     */
4062
-    public function is_caf()
4063
-    {
4064
-        return $this->_is_caf;
4065
-    }
4066
-
4067
-
4068
-
4069
-    /**
4070
-     * @return mixed
4071
-     */
4072
-    public function default_espresso_metaboxes()
4073
-    {
4074
-        return $this->_default_espresso_metaboxes;
4075
-    }
4076
-
4077
-
4078
-
4079
-    /**
4080
-     * @return mixed
4081
-     */
4082
-    public function admin_base_url()
4083
-    {
4084
-        return $this->_admin_base_url;
4085
-    }
2775
+	}
2776
+
2777
+
2778
+
2779
+	/**
2780
+	 * facade for add_meta_box
2781
+	 *
2782
+	 * @param string  $action        where the metabox get's displayed
2783
+	 * @param string  $title         Title of Metabox (output in metabox header)
2784
+	 * @param string  $callback      If not empty and $create_fun is set to false then we'll use a custom callback
2785
+	 *                               instead of the one created in here.
2786
+	 * @param array   $callback_args an array of args supplied for the metabox
2787
+	 * @param string  $column        what metabox column
2788
+	 * @param string  $priority      give this metabox a priority (using accepted priorities for wp meta boxes)
2789
+	 * @param boolean $create_func   default is true.  Basically we can say we don't WANT to have the runtime function
2790
+	 *                               created but just set our own callback for wp's add_meta_box.
2791
+	 * @throws \DomainException
2792
+	 */
2793
+	public function _add_admin_page_meta_box(
2794
+		$action,
2795
+		$title,
2796
+		$callback,
2797
+		$callback_args,
2798
+		$column = 'normal',
2799
+		$priority = 'high',
2800
+		$create_func = true
2801
+	) {
2802
+		do_action('AHEE_log', __FILE__, __FUNCTION__, $callback);
2803
+		//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.
2804
+		if (empty($callback_args) && $create_func) {
2805
+			$callback_args = array(
2806
+				'template_path' => $this->_template_path,
2807
+				'template_args' => $this->_template_args,
2808
+			);
2809
+		}
2810
+		//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)
2811
+		$call_back_func = $create_func
2812
+			? function ($post, $metabox)
2813
+			{
2814
+				do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2815
+				echo EEH_Template::display_template(
2816
+					$metabox['args']['template_path'],
2817
+					$metabox['args']['template_args'],
2818
+					true
2819
+				);
2820
+			}
2821
+			: $callback;
2822
+		add_meta_box(
2823
+			str_replace('_', '-', $action) . '-mbox',
2824
+			$title,
2825
+			$call_back_func,
2826
+			$this->_wp_page_slug,
2827
+			$column,
2828
+			$priority,
2829
+			$callback_args
2830
+		);
2831
+	}
2832
+
2833
+
2834
+
2835
+	/**
2836
+	 * generates HTML wrapper for and admin details page that contains metaboxes in columns
2837
+	 *
2838
+	 * @throws DomainException
2839
+	 * @throws EE_Error
2840
+	 */
2841
+	public function display_admin_page_with_metabox_columns()
2842
+	{
2843
+		$this->_template_args['post_body_content']  = $this->_template_args['admin_page_content'];
2844
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
2845
+			$this->_column_template_path,
2846
+			$this->_template_args,
2847
+			true
2848
+		);
2849
+		//the final wrapper
2850
+		$this->admin_page_wrapper();
2851
+	}
2852
+
2853
+
2854
+
2855
+	/**
2856
+	 * generates  HTML wrapper for an admin details page
2857
+	 *
2858
+	 * @return void
2859
+	 * @throws EE_Error
2860
+	 * @throws DomainException
2861
+	 */
2862
+	public function display_admin_page_with_sidebar()
2863
+	{
2864
+		$this->_display_admin_page(true);
2865
+	}
2866
+
2867
+
2868
+
2869
+	/**
2870
+	 * generates  HTML wrapper for an admin details page (except no sidebar)
2871
+	 *
2872
+	 * @return void
2873
+	 * @throws EE_Error
2874
+	 * @throws DomainException
2875
+	 */
2876
+	public function display_admin_page_with_no_sidebar()
2877
+	{
2878
+		$this->_display_admin_page();
2879
+	}
2880
+
2881
+
2882
+
2883
+	/**
2884
+	 * generates HTML wrapper for an EE about admin page (no sidebar)
2885
+	 *
2886
+	 * @return void
2887
+	 * @throws EE_Error
2888
+	 * @throws DomainException
2889
+	 */
2890
+	public function display_about_admin_page()
2891
+	{
2892
+		$this->_display_admin_page(false, true);
2893
+	}
2894
+
2895
+
2896
+
2897
+	/**
2898
+	 * display_admin_page
2899
+	 * contains the code for actually displaying an admin page
2900
+	 *
2901
+	 * @param  boolean $sidebar true with sidebar, false without
2902
+	 * @param  boolean $about   use the about admin wrapper instead of the default.
2903
+	 * @return void
2904
+	 * @throws DomainException
2905
+	 * @throws EE_Error
2906
+	 */
2907
+	private function _display_admin_page($sidebar = false, $about = false)
2908
+	{
2909
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2910
+		//custom remove metaboxes hook to add or remove any metaboxes to/from Admin pages.
2911
+		do_action('AHEE__EE_Admin_Page___display_admin_page__modify_metaboxes');
2912
+		// set current wp page slug - looks like: event-espresso_page_event_categories
2913
+		// keep in mind "event-espresso" COULD be something else if the top level menu label has been translated.
2914
+		$this->_template_args['current_page']              = $this->_wp_page_slug;
2915
+		$this->_template_args['admin_page_wrapper_div_id'] = $this->_cpt_route
2916
+			? 'poststuff'
2917
+			: 'espresso-default-admin';
2918
+		$template_path                                     = $sidebar
2919
+			? EE_ADMIN_TEMPLATE . 'admin_details_wrapper.template.php'
2920
+			: EE_ADMIN_TEMPLATE . 'admin_details_wrapper_no_sidebar.template.php';
2921
+		if (defined('DOING_AJAX') && DOING_AJAX) {
2922
+			$template_path = EE_ADMIN_TEMPLATE . 'admin_details_wrapper_no_sidebar_ajax.template.php';
2923
+		}
2924
+		$template_path                                     = ! empty($this->_column_template_path)
2925
+			? $this->_column_template_path : $template_path;
2926
+		$this->_template_args['post_body_content']         = isset($this->_template_args['admin_page_content'])
2927
+			? $this->_template_args['admin_page_content']
2928
+			: '';
2929
+		$this->_template_args['before_admin_page_content'] = isset($this->_template_args['before_admin_page_content'])
2930
+			? $this->_template_args['before_admin_page_content']
2931
+			: '';
2932
+		$this->_template_args['after_admin_page_content']  = isset($this->_template_args['after_admin_page_content'])
2933
+			? $this->_template_args['after_admin_page_content']
2934
+			: '';
2935
+		$this->_template_args['admin_page_content']        = EEH_Template::display_template(
2936
+			$template_path,
2937
+			$this->_template_args,
2938
+			true
2939
+		);
2940
+		// the final template wrapper
2941
+		$this->admin_page_wrapper($about);
2942
+	}
2943
+
2944
+
2945
+
2946
+	/**
2947
+	 * This is used to display caf preview pages.
2948
+	 *
2949
+	 * @since 4.3.2
2950
+	 * @param string $utm_campaign_source what is the key used for google analytics link
2951
+	 * @param bool   $display_sidebar     whether to use the sidebar template or the full template for the page.  TRUE
2952
+	 *                                    = SHOW sidebar, FALSE = no sidebar. Default no sidebar.
2953
+	 * @return void
2954
+	 * @throws DomainException
2955
+	 * @throws EE_Error
2956
+	 * @throws InvalidArgumentException
2957
+	 * @throws InvalidDataTypeException
2958
+	 * @throws InvalidInterfaceException
2959
+	 */
2960
+	public function display_admin_caf_preview_page($utm_campaign_source = '', $display_sidebar = true)
2961
+	{
2962
+		//let's generate a default preview action button if there isn't one already present.
2963
+		$this->_labels['buttons']['buy_now']           = esc_html__(
2964
+			'Upgrade to Event Espresso 4 Right Now',
2965
+			'event_espresso'
2966
+		);
2967
+		$buy_now_url                                   = add_query_arg(
2968
+			array(
2969
+				'ee_ver'       => 'ee4',
2970
+				'utm_source'   => 'ee4_plugin_admin',
2971
+				'utm_medium'   => 'link',
2972
+				'utm_campaign' => $utm_campaign_source,
2973
+				'utm_content'  => 'buy_now_button',
2974
+			),
2975
+			'http://eventespresso.com/pricing/'
2976
+		);
2977
+		$this->_template_args['preview_action_button'] = ! isset($this->_template_args['preview_action_button'])
2978
+			? $this->get_action_link_or_button(
2979
+				'',
2980
+				'buy_now',
2981
+				array(),
2982
+				'button-primary button-large',
2983
+				$buy_now_url,
2984
+				true
2985
+			)
2986
+			: $this->_template_args['preview_action_button'];
2987
+		$this->_template_args['admin_page_content']    = EEH_Template::display_template(
2988
+			EE_ADMIN_TEMPLATE . 'admin_caf_full_page_preview.template.php',
2989
+			$this->_template_args,
2990
+			true
2991
+		);
2992
+		$this->_display_admin_page($display_sidebar);
2993
+	}
2994
+
2995
+
2996
+
2997
+	/**
2998
+	 * display_admin_list_table_page_with_sidebar
2999
+	 * generates HTML wrapper for an admin_page with list_table
3000
+	 *
3001
+	 * @return void
3002
+	 * @throws EE_Error
3003
+	 * @throws DomainException
3004
+	 */
3005
+	public function display_admin_list_table_page_with_sidebar()
3006
+	{
3007
+		$this->_display_admin_list_table_page(true);
3008
+	}
3009
+
3010
+
3011
+
3012
+	/**
3013
+	 * display_admin_list_table_page_with_no_sidebar
3014
+	 * generates HTML wrapper for an admin_page with list_table (but with no sidebar)
3015
+	 *
3016
+	 * @return void
3017
+	 * @throws EE_Error
3018
+	 * @throws DomainException
3019
+	 */
3020
+	public function display_admin_list_table_page_with_no_sidebar()
3021
+	{
3022
+		$this->_display_admin_list_table_page();
3023
+	}
3024
+
3025
+
3026
+
3027
+	/**
3028
+	 * generates html wrapper for an admin_list_table page
3029
+	 *
3030
+	 * @param boolean $sidebar whether to display with sidebar or not.
3031
+	 * @return void
3032
+	 * @throws DomainException
3033
+	 * @throws EE_Error
3034
+	 */
3035
+	private function _display_admin_list_table_page($sidebar = false)
3036
+	{
3037
+		//setup search attributes
3038
+		$this->_set_search_attributes();
3039
+		$this->_template_args['current_page']     = $this->_wp_page_slug;
3040
+		$template_path                            = EE_ADMIN_TEMPLATE . 'admin_list_wrapper.template.php';
3041
+		$this->_template_args['table_url']        = defined('DOING_AJAX')
3042
+			? add_query_arg(array('noheader' => 'true', 'route' => $this->_req_action), $this->_admin_base_url)
3043
+			: add_query_arg(array('route' => $this->_req_action), $this->_admin_base_url);
3044
+		$this->_template_args['list_table']       = $this->_list_table_object;
3045
+		$this->_template_args['current_route']    = $this->_req_action;
3046
+		$this->_template_args['list_table_class'] = get_class($this->_list_table_object);
3047
+		$ajax_sorting_callback                    = $this->_list_table_object->get_ajax_sorting_callback();
3048
+		if (! empty($ajax_sorting_callback)) {
3049
+			$sortable_list_table_form_fields = wp_nonce_field(
3050
+				$ajax_sorting_callback . '_nonce',
3051
+				$ajax_sorting_callback . '_nonce',
3052
+				false,
3053
+				false
3054
+			);
3055
+			//			$reorder_action = 'espresso_' . $ajax_sorting_callback . '_nonce';
3056
+			//			$sortable_list_table_form_fields = wp_nonce_field( $reorder_action, 'ajax_table_sort_nonce', FALSE, FALSE );
3057
+			$sortable_list_table_form_fields .= '<input type="hidden" id="ajax_table_sort_page" name="ajax_table_sort_page" value="'
3058
+												. $this->page_slug
3059
+												. '" />';
3060
+			$sortable_list_table_form_fields .= '<input type="hidden" id="ajax_table_sort_action" name="ajax_table_sort_action" value="'
3061
+												. $ajax_sorting_callback
3062
+												. '" />';
3063
+		} else {
3064
+			$sortable_list_table_form_fields = '';
3065
+		}
3066
+		$this->_template_args['sortable_list_table_form_fields'] = $sortable_list_table_form_fields;
3067
+		$hidden_form_fields                                      = isset($this->_template_args['list_table_hidden_fields'])
3068
+			? $this->_template_args['list_table_hidden_fields']
3069
+			: '';
3070
+		$nonce_ref                                               = $this->_req_action . '_nonce';
3071
+		$hidden_form_fields                                      .= '<input type="hidden" name="'
3072
+																	. $nonce_ref
3073
+																	. '" value="'
3074
+																	. wp_create_nonce($nonce_ref)
3075
+																	. '">';
3076
+		$this->_template_args['list_table_hidden_fields']        = $hidden_form_fields;
3077
+		//display message about search results?
3078
+		$this->_template_args['before_list_table'] .= ! empty($this->_req_data['s'])
3079
+			? '<p class="ee-search-results">' . sprintf(
3080
+				esc_html__('Displaying search results for the search string: %1$s', 'event_espresso'),
3081
+				trim($this->_req_data['s'], '%')
3082
+			) . '</p>'
3083
+			: '';
3084
+		// filter before_list_table template arg
3085
+		$this->_template_args['before_list_table'] = apply_filters(
3086
+			'FHEE__EE_Admin_Page___display_admin_list_table_page__before_list_table__template_arg',
3087
+			$this->_template_args['before_list_table'],
3088
+			$this->page_slug,
3089
+			$this->_req_data,
3090
+			$this->_req_action
3091
+		);
3092
+		// convert to array and filter again
3093
+		// arrays are easier to inject new items in a specific location,
3094
+		// but would not be backwards compatible, so we have to add a new filter
3095
+		$this->_template_args['before_list_table'] = implode(
3096
+			" \n",
3097
+			(array)apply_filters(
3098
+				'FHEE__EE_Admin_Page___display_admin_list_table_page__before_list_table__template_args_array',
3099
+				(array)$this->_template_args['before_list_table'],
3100
+				$this->page_slug,
3101
+				$this->_req_data,
3102
+				$this->_req_action
3103
+			)
3104
+		);
3105
+		// filter after_list_table template arg
3106
+		$this->_template_args['after_list_table'] = apply_filters(
3107
+			'FHEE__EE_Admin_Page___display_admin_list_table_page__after_list_table__template_arg',
3108
+			$this->_template_args['after_list_table'],
3109
+			$this->page_slug,
3110
+			$this->_req_data,
3111
+			$this->_req_action
3112
+		);
3113
+		// convert to array and filter again
3114
+		// arrays are easier to inject new items in a specific location,
3115
+		// but would not be backwards compatible, so we have to add a new filter
3116
+		$this->_template_args['after_list_table']   = implode(
3117
+			" \n",
3118
+			(array)apply_filters(
3119
+				'FHEE__EE_Admin_Page___display_admin_list_table_page__after_list_table__template_args_array',
3120
+				(array)$this->_template_args['after_list_table'],
3121
+				$this->page_slug,
3122
+				$this->_req_data,
3123
+				$this->_req_action
3124
+			)
3125
+		);
3126
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
3127
+			$template_path,
3128
+			$this->_template_args,
3129
+			true
3130
+		);
3131
+		// the final template wrapper
3132
+		if ($sidebar) {
3133
+			$this->display_admin_page_with_sidebar();
3134
+		} else {
3135
+			$this->display_admin_page_with_no_sidebar();
3136
+		}
3137
+	}
3138
+
3139
+
3140
+
3141
+	/**
3142
+	 * This just prepares a legend using the given items and the admin_details_legend.template.php file and returns the
3143
+	 * html string for the legend.
3144
+	 * $items are expected in an array in the following format:
3145
+	 * $legend_items = array(
3146
+	 *        'item_id' => array(
3147
+	 *            'icon' => 'http://url_to_icon_being_described.png',
3148
+	 *            'desc' => esc_html__('localized description of item');
3149
+	 *        )
3150
+	 * );
3151
+	 *
3152
+	 * @param  array $items see above for format of array
3153
+	 * @return string html string of legend
3154
+	 * @throws DomainException
3155
+	 */
3156
+	protected function _display_legend($items)
3157
+	{
3158
+		$this->_template_args['items'] = apply_filters(
3159
+			'FHEE__EE_Admin_Page___display_legend__items',
3160
+			(array)$items,
3161
+			$this
3162
+		);
3163
+		return EEH_Template::display_template(
3164
+			EE_ADMIN_TEMPLATE . 'admin_details_legend.template.php',
3165
+			$this->_template_args,
3166
+			true
3167
+		);
3168
+	}
3169
+
3170
+
3171
+	/**
3172
+	 * This is used whenever we're DOING_AJAX to return a formatted json array that our calling javascript can expect
3173
+	 * The returned json object is created from an array in the following format:
3174
+	 * array(
3175
+	 *  'error' => FALSE, //(default FALSE), contains any errors and/or exceptions (exceptions return json early),
3176
+	 *  'success' => FALSE, //(default FALSE) - contains any special success message.
3177
+	 *  'notices' => '', // - contains any EE_Error formatted notices
3178
+	 *  'content' => 'string can be html', //this is a string of formatted content (can be html)
3179
+	 *  'data' => array() //this can be any key/value pairs that a method returns for later json parsing by the js.
3180
+	 *  We're also going to include the template args with every package (so js can pick out any specific template args
3181
+	 *  that might be included in here)
3182
+	 * )
3183
+	 * The json object is populated by whatever is set in the $_template_args property.
3184
+	 *
3185
+	 * @param bool  $sticky_notices    Used to indicate whether you want to ensure notices are added to a transient
3186
+	 *                                 instead of displayed.
3187
+	 * @param array $notices_arguments Use this to pass any additional args on to the _process_notices.
3188
+	 * @return void
3189
+	 * @throws EE_Error
3190
+	 */
3191
+	protected function _return_json($sticky_notices = false, $notices_arguments = array())
3192
+	{
3193
+		//make sure any EE_Error notices have been handled.
3194
+		$this->_process_notices($notices_arguments, true, $sticky_notices);
3195
+		$data = isset($this->_template_args['data']) ? $this->_template_args['data'] : array();
3196
+		unset($this->_template_args['data']);
3197
+		$json = array(
3198
+			'error'     => isset($this->_template_args['error']) ? $this->_template_args['error'] : false,
3199
+			'success'   => isset($this->_template_args['success']) ? $this->_template_args['success'] : false,
3200
+			'errors'    => isset($this->_template_args['errors']) ? $this->_template_args['errors'] : false,
3201
+			'attention' => isset($this->_template_args['attention']) ? $this->_template_args['attention'] : false,
3202
+			'notices'   => EE_Error::get_notices(),
3203
+			'content'   => isset($this->_template_args['admin_page_content'])
3204
+				? $this->_template_args['admin_page_content'] : '',
3205
+			'data'      => array_merge($data, array('template_args' => $this->_template_args)),
3206
+			'isEEajax'  => true
3207
+			//special flag so any ajax.Success methods in js can identify this return package as a EEajax package.
3208
+		);
3209
+		// make sure there are no php errors or headers_sent.  Then we can set correct json header.
3210
+		if (null === error_get_last() || ! headers_sent()) {
3211
+			header('Content-Type: application/json; charset=UTF-8');
3212
+		}
3213
+		echo wp_json_encode($json);
3214
+		exit();
3215
+	}
3216
+
3217
+
3218
+
3219
+	/**
3220
+	 * Simply a wrapper for the protected method so we can call this outside the class (ONLY when doing ajax)
3221
+	 *
3222
+	 * @return void
3223
+	 * @throws EE_Error
3224
+	 */
3225
+	public function return_json()
3226
+	{
3227
+		if (defined('DOING_AJAX') && DOING_AJAX) {
3228
+			$this->_return_json();
3229
+		} else {
3230
+			throw new EE_Error(
3231
+				sprintf(
3232
+					esc_html__('The public %s method can only be called when DOING_AJAX = TRUE', 'event_espresso'),
3233
+					__FUNCTION__
3234
+				)
3235
+			);
3236
+		}
3237
+	}
3238
+
3239
+
3240
+
3241
+	/**
3242
+	 * This provides a way for child hook classes to send along themselves by reference so methods/properties within
3243
+	 * them can be accessed by EE_Admin_child pages. This is assigned to the $_hook_obj property.
3244
+	 *
3245
+	 * @param EE_Admin_Hooks $hook_obj This will be the object for the EE_Admin_Hooks child
3246
+	 */
3247
+	public function set_hook_object(EE_Admin_Hooks $hook_obj)
3248
+	{
3249
+		$this->_hook_obj = $hook_obj;
3250
+	}
3251
+
3252
+
3253
+
3254
+	/**
3255
+	 *        generates  HTML wrapper with Tabbed nav for an admin page
3256
+	 *
3257
+	 * @param  boolean $about whether to use the special about page wrapper or default.
3258
+	 * @return void
3259
+	 * @throws DomainException
3260
+	 * @throws EE_Error
3261
+	 */
3262
+	public function admin_page_wrapper($about = false)
3263
+	{
3264
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3265
+		$this->_nav_tabs                                   = $this->_get_main_nav_tabs();
3266
+		$this->_template_args['nav_tabs']                  = $this->_nav_tabs;
3267
+		$this->_template_args['admin_page_title']          = $this->_admin_page_title;
3268
+		$this->_template_args['before_admin_page_content'] = apply_filters(
3269
+			"FHEE_before_admin_page_content{$this->_current_page}{$this->_current_view}",
3270
+			isset($this->_template_args['before_admin_page_content'])
3271
+				? $this->_template_args['before_admin_page_content']
3272
+				: ''
3273
+		);
3274
+		$this->_template_args['after_admin_page_content']  = apply_filters(
3275
+			"FHEE_after_admin_page_content{$this->_current_page}{$this->_current_view}",
3276
+			isset($this->_template_args['after_admin_page_content'])
3277
+				? $this->_template_args['after_admin_page_content']
3278
+				: ''
3279
+		);
3280
+		$this->_template_args['after_admin_page_content']  .= $this->_set_help_popup_content();
3281
+		// load settings page wrapper template
3282
+		$template_path = ! defined('DOING_AJAX')
3283
+			? EE_ADMIN_TEMPLATE . 'admin_wrapper.template.php'
3284
+			: EE_ADMIN_TEMPLATE
3285
+			  . 'admin_wrapper_ajax.template.php';
3286
+		//about page?
3287
+		$template_path = $about
3288
+			? EE_ADMIN_TEMPLATE . 'about_admin_wrapper.template.php'
3289
+			: $template_path;
3290
+		if (defined('DOING_AJAX')) {
3291
+			$this->_template_args['admin_page_content'] = EEH_Template::display_template(
3292
+				$template_path,
3293
+				$this->_template_args,
3294
+				true
3295
+			);
3296
+			$this->_return_json();
3297
+		} else {
3298
+			EEH_Template::display_template($template_path, $this->_template_args);
3299
+		}
3300
+	}
3301
+
3302
+
3303
+
3304
+	/**
3305
+	 * This returns the admin_nav tabs html using the configuration in the _nav_tabs property
3306
+	 *
3307
+	 * @return string html
3308
+	 * @throws EE_Error
3309
+	 */
3310
+	protected function _get_main_nav_tabs()
3311
+	{
3312
+		// let's generate the html using the EEH_Tabbed_Content helper.
3313
+		// We do this here so that it's possible for child classes to add in nav tabs dynamically at the last minute
3314
+		// (rather than setting in the page_routes array)
3315
+		return EEH_Tabbed_Content::display_admin_nav_tabs($this->_nav_tabs);
3316
+	}
3317
+
3318
+
3319
+
3320
+	/**
3321
+	 *        sort nav tabs
3322
+	 *
3323
+	 * @param $a
3324
+	 * @param $b
3325
+	 * @return int
3326
+	 */
3327
+	private function _sort_nav_tabs($a, $b)
3328
+	{
3329
+		if ($a['order'] === $b['order']) {
3330
+			return 0;
3331
+		}
3332
+		return ($a['order'] < $b['order']) ? -1 : 1;
3333
+	}
3334
+
3335
+
3336
+
3337
+	/**
3338
+	 *    generates HTML for the forms used on admin pages
3339
+	 *
3340
+	 * @param    array $input_vars - array of input field details
3341
+	 * @param string   $generator  (options are 'string' or 'array', basically use this to indicate which generator to
3342
+	 *                             use)
3343
+	 * @param bool     $id
3344
+	 * @return string
3345
+	 * @uses   EEH_Form_Fields::get_form_fields (/helper/EEH_Form_Fields.helper.php)
3346
+	 * @uses   EEH_Form_Fields::get_form_fields_array (/helper/EEH_Form_Fields.helper.php)
3347
+	 */
3348
+	protected function _generate_admin_form_fields($input_vars = array(), $generator = 'string', $id = false)
3349
+	{
3350
+		$content = $generator === 'string'
3351
+			? EEH_Form_Fields::get_form_fields($input_vars, $id)
3352
+			: EEH_Form_Fields::get_form_fields_array($input_vars);
3353
+		return $content;
3354
+	}
3355
+
3356
+
3357
+
3358
+	/**
3359
+	 * generates the "Save" and "Save & Close" buttons for edit forms
3360
+	 *
3361
+	 * @param bool             $both     if true then both buttons will be generated.  If false then just the "Save &
3362
+	 *                                   Close" button.
3363
+	 * @param array            $text     if included, generator will use the given text for the buttons ( array([0] =>
3364
+	 *                                   'Save', [1] => 'save & close')
3365
+	 * @param array            $actions  if included allows us to set the actions that each button will carry out (i.e.
3366
+	 *                                   via the "name" value in the button).  We can also use this to just dump
3367
+	 *                                   default actions by submitting some other value.
3368
+	 * @param bool|string|null $referrer if false then we just do the default action on save and close.  Other wise it
3369
+	 *                                   will use the $referrer string. IF null, then we don't do ANYTHING on save and
3370
+	 *                                   close (normal form handling).
3371
+	 */
3372
+	protected function _set_save_buttons($both = true, $text = array(), $actions = array(), $referrer = null)
3373
+	{
3374
+		//make sure $text and $actions are in an array
3375
+		$text          = (array)$text;
3376
+		$actions       = (array)$actions;
3377
+		$referrer_url  = empty($referrer)
3378
+			? '<input type="hidden" id="save_and_close_referrer" name="save_and_close_referrer" value="'
3379
+			  . $_SERVER['REQUEST_URI']
3380
+			  . '" />'
3381
+			: '<input type="hidden" id="save_and_close_referrer" name="save_and_close_referrer" value="'
3382
+			  . $referrer
3383
+			  . '" />';
3384
+		$button_text   = ! empty($text)
3385
+			? $text
3386
+			: array(
3387
+				esc_html__('Save', 'event_espresso'),
3388
+				esc_html__('Save and Close', 'event_espresso'),
3389
+			);
3390
+		$default_names = array('save', 'save_and_close');
3391
+		//add in a hidden index for the current page (so save and close redirects properly)
3392
+		$this->_template_args['save_buttons'] = $referrer_url;
3393
+		foreach ($button_text as $key => $button) {
3394
+			$ref                                  = $default_names[$key];
3395
+			$this->_template_args['save_buttons'] .= '<input type="submit" class="button-primary '
3396
+													 . $ref
3397
+													 . '" value="'
3398
+													 . $button
3399
+													 . '" name="'
3400
+													 . (! empty($actions) ? $actions[$key] : $ref)
3401
+													 . '" id="'
3402
+													 . $this->_current_view . '_' . $ref
3403
+													 . '" />';
3404
+			if (! $both) {
3405
+				break;
3406
+			}
3407
+		}
3408
+	}
3409
+
3410
+
3411
+
3412
+	/**
3413
+	 * Wrapper for the protected function.  Allows plugins/addons to call this to set the form tags.
3414
+	 *
3415
+	 * @see   $this->_set_add_edit_form_tags() for details on params
3416
+	 * @since 4.6.0
3417
+	 * @param string $route
3418
+	 * @param array  $additional_hidden_fields
3419
+	 */
3420
+	public function set_add_edit_form_tags($route = '', $additional_hidden_fields = array())
3421
+	{
3422
+		$this->_set_add_edit_form_tags($route, $additional_hidden_fields);
3423
+	}
3424
+
3425
+
3426
+
3427
+	/**
3428
+	 * set form open and close tags on add/edit pages.
3429
+	 *
3430
+	 * @param string $route                    the route you want the form to direct to
3431
+	 * @param array  $additional_hidden_fields any additional hidden fields required in the form header
3432
+	 * @return void
3433
+	 */
3434
+	protected function _set_add_edit_form_tags($route = '', $additional_hidden_fields = array())
3435
+	{
3436
+		if (empty($route)) {
3437
+			$user_msg = esc_html__(
3438
+				'An error occurred. No action was set for this page\'s form.',
3439
+				'event_espresso'
3440
+			);
3441
+			$dev_msg  = $user_msg . "\n" . sprintf(
3442
+					esc_html__('The $route argument is required for the %s->%s method.', 'event_espresso'),
3443
+					__FUNCTION__,
3444
+					__CLASS__
3445
+				);
3446
+			EE_Error::add_error($user_msg . '||' . $dev_msg, __FILE__, __FUNCTION__, __LINE__);
3447
+		}
3448
+		// open form
3449
+		$this->_template_args['before_admin_page_content'] = '<form name="form" method="post" action="'
3450
+															 . $this->_admin_base_url
3451
+															 . '" id="'
3452
+															 . $route
3453
+															 . '_event_form" >';
3454
+		// add nonce
3455
+		$nonce = wp_nonce_field($route . '_nonce', $route . '_nonce', false, false);
3456
+		//		$nonce = wp_nonce_field( $route . '_nonce', '_wpnonce', FALSE, FALSE );
3457
+		$this->_template_args['before_admin_page_content'] .= "\n\t" . $nonce;
3458
+		// add REQUIRED form action
3459
+		$hidden_fields = array(
3460
+			'action' => array('type' => 'hidden', 'value' => $route),
3461
+		);
3462
+		// merge arrays
3463
+		$hidden_fields = is_array($additional_hidden_fields)
3464
+			? array_merge($hidden_fields, $additional_hidden_fields)
3465
+			: $hidden_fields;
3466
+		// generate form fields
3467
+		$form_fields = $this->_generate_admin_form_fields($hidden_fields, 'array');
3468
+		// add fields to form
3469
+		foreach ((array)$form_fields as $field_name => $form_field) {
3470
+			$this->_template_args['before_admin_page_content'] .= "\n\t" . $form_field['field'];
3471
+		}
3472
+		// close form
3473
+		$this->_template_args['after_admin_page_content'] = '</form>';
3474
+	}
3475
+
3476
+
3477
+
3478
+	/**
3479
+	 * Public Wrapper for _redirect_after_action() method since its
3480
+	 * discovered it would be useful for external code to have access.
3481
+	 *
3482
+	 * @see   EE_Admin_Page::_redirect_after_action() for params.
3483
+	 * @since 4.5.0
3484
+	 * @param bool   $success
3485
+	 * @param string $what
3486
+	 * @param string $action_desc
3487
+	 * @param array  $query_args
3488
+	 * @param bool   $override_overwrite
3489
+	 * @throws EE_Error
3490
+	 */
3491
+	public function redirect_after_action(
3492
+		$success = false,
3493
+		$what = 'item',
3494
+		$action_desc = 'processed',
3495
+		$query_args = array(),
3496
+		$override_overwrite = false
3497
+	) {
3498
+		$this->_redirect_after_action(
3499
+			$success,
3500
+			$what,
3501
+			$action_desc,
3502
+			$query_args,
3503
+			$override_overwrite
3504
+		);
3505
+	}
3506
+
3507
+
3508
+
3509
+	/**
3510
+	 *    _redirect_after_action
3511
+	 *
3512
+	 * @param int    $success            - whether success was for two or more records, or just one, or none
3513
+	 * @param string $what               - what the action was performed on
3514
+	 * @param string $action_desc        - what was done ie: updated, deleted, etc
3515
+	 * @param array  $query_args         - an array of query_args to be added to the URL to redirect to after the admin
3516
+	 *                                   action is completed
3517
+	 * @param BOOL   $override_overwrite by default all EE_Error::success messages are overwritten, this allows you to
3518
+	 *                                   override this so that they show.
3519
+	 * @return void
3520
+	 * @throws EE_Error
3521
+	 */
3522
+	protected function _redirect_after_action(
3523
+		$success = 0,
3524
+		$what = 'item',
3525
+		$action_desc = 'processed',
3526
+		$query_args = array(),
3527
+		$override_overwrite = false
3528
+	) {
3529
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3530
+		//class name for actions/filters.
3531
+		$classname = get_class($this);
3532
+		// set redirect url.
3533
+		// Note if there is a "page" index in the $query_args then we go with vanilla admin.php route,
3534
+		// otherwise we go with whatever is set as the _admin_base_url
3535
+		$redirect_url = isset($query_args['page']) ? admin_url('admin.php') : $this->_admin_base_url;
3536
+		$notices      = EE_Error::get_notices(false);
3537
+		// overwrite default success messages //BUT ONLY if overwrite not overridden
3538
+		if (! $override_overwrite || ! empty($notices['errors'])) {
3539
+			EE_Error::overwrite_success();
3540
+		}
3541
+		if (! empty($what) && ! empty($action_desc)  && empty($notices['errors'])) {
3542
+			// how many records affected ? more than one record ? or just one ?
3543
+			if ($success > 1) {
3544
+				// set plural msg
3545
+				EE_Error::add_success(
3546
+					sprintf(
3547
+						esc_html__('The "%s" have been successfully %s.', 'event_espresso'),
3548
+						$what,
3549
+						$action_desc
3550
+					),
3551
+					__FILE__,
3552
+					__FUNCTION__,
3553
+					__LINE__
3554
+				);
3555
+			} elseif ($success === 1) {
3556
+				// set singular msg
3557
+				EE_Error::add_success(
3558
+					sprintf(
3559
+						esc_html__('The "%s" has been successfully %s.', 'event_espresso'),
3560
+						$what,
3561
+						$action_desc
3562
+					),
3563
+					__FILE__,
3564
+					__FUNCTION__,
3565
+					__LINE__
3566
+				);
3567
+			}
3568
+		}
3569
+		// check that $query_args isn't something crazy
3570
+		if (! is_array($query_args)) {
3571
+			$query_args = array();
3572
+		}
3573
+		/**
3574
+		 * Allow injecting actions before the query_args are modified for possible different
3575
+		 * redirections on save and close actions
3576
+		 *
3577
+		 * @since 4.2.0
3578
+		 * @param array $query_args       The original query_args array coming into the
3579
+		 *                                method.
3580
+		 */
3581
+		do_action(
3582
+			"AHEE__{$classname}___redirect_after_action__before_redirect_modification_{$this->_req_action}",
3583
+			$query_args
3584
+		);
3585
+		//calculate where we're going (if we have a "save and close" button pushed)
3586
+		if (isset($this->_req_data['save_and_close'], $this->_req_data['save_and_close_referrer'])) {
3587
+			// even though we have the save_and_close referrer, we need to parse the url for the action in order to generate a nonce
3588
+			$parsed_url = parse_url($this->_req_data['save_and_close_referrer']);
3589
+			// regenerate query args array from referrer URL
3590
+			parse_str($parsed_url['query'], $query_args);
3591
+			// correct page and action will be in the query args now
3592
+			$redirect_url = admin_url('admin.php');
3593
+		}
3594
+		//merge any default query_args set in _default_route_query_args property
3595
+		if (! empty($this->_default_route_query_args) && ! $this->_is_UI_request) {
3596
+			$args_to_merge = array();
3597
+			foreach ($this->_default_route_query_args as $query_param => $query_value) {
3598
+				//is there a wp_referer array in our _default_route_query_args property?
3599
+				if ($query_param === 'wp_referer') {
3600
+					$query_value = (array)$query_value;
3601
+					foreach ($query_value as $reference => $value) {
3602
+						if (strpos($reference, 'nonce') !== false) {
3603
+							continue;
3604
+						}
3605
+						//finally we will override any arguments in the referer with
3606
+						//what might be set on the _default_route_query_args array.
3607
+						if (isset($this->_default_route_query_args[$reference])) {
3608
+							$args_to_merge[$reference] = urlencode($this->_default_route_query_args[$reference]);
3609
+						} else {
3610
+							$args_to_merge[$reference] = urlencode($value);
3611
+						}
3612
+					}
3613
+					continue;
3614
+				}
3615
+				$args_to_merge[$query_param] = $query_value;
3616
+			}
3617
+			//now let's merge these arguments but override with what was specifically sent in to the
3618
+			//redirect.
3619
+			$query_args = array_merge($args_to_merge, $query_args);
3620
+		}
3621
+		$this->_process_notices($query_args);
3622
+		// generate redirect url
3623
+		// if redirecting to anything other than the main page, add a nonce
3624
+		if (isset($query_args['action'])) {
3625
+			// manually generate wp_nonce and merge that with the query vars
3626
+			// becuz the wp_nonce_url function wrecks havoc on some vars
3627
+			$query_args['_wpnonce'] = wp_create_nonce($query_args['action'] . '_nonce');
3628
+		}
3629
+		// we're adding some hooks and filters in here for processing any things just before redirects
3630
+		// (example: an admin page has done an insert or update and we want to run something after that).
3631
+		do_action('AHEE_redirect_' . $classname . $this->_req_action, $query_args);
3632
+		$redirect_url = apply_filters(
3633
+			'FHEE_redirect_' . $classname . $this->_req_action,
3634
+			self::add_query_args_and_nonce($query_args, $redirect_url),
3635
+			$query_args
3636
+		);
3637
+		// check if we're doing ajax.  If we are then lets just return the results and js can handle how it wants.
3638
+		if (defined('DOING_AJAX')) {
3639
+			$default_data                    = array(
3640
+				'close'        => true,
3641
+				'redirect_url' => $redirect_url,
3642
+				'where'        => 'main',
3643
+				'what'         => 'append',
3644
+			);
3645
+			$this->_template_args['success'] = $success;
3646
+			$this->_template_args['data']    = ! empty($this->_template_args['data']) ? array_merge(
3647
+				$default_data,
3648
+				$this->_template_args['data']
3649
+			) : $default_data;
3650
+			$this->_return_json();
3651
+		}
3652
+		wp_safe_redirect($redirect_url);
3653
+		exit();
3654
+	}
3655
+
3656
+
3657
+
3658
+	/**
3659
+	 * process any notices before redirecting (or returning ajax request)
3660
+	 * This method sets the $this->_template_args['notices'] attribute;
3661
+	 *
3662
+	 * @param  array $query_args        any query args that need to be used for notice transient ('action')
3663
+	 * @param bool   $skip_route_verify This is typically used when we are processing notices REALLY early and
3664
+	 *                                  page_routes haven't been defined yet.
3665
+	 * @param bool   $sticky_notices    This is used to flag that regardless of whether this is doing_ajax or not, we
3666
+	 *                                  still save a transient for the notice.
3667
+	 * @return void
3668
+	 * @throws EE_Error
3669
+	 */
3670
+	protected function _process_notices($query_args = array(), $skip_route_verify = false, $sticky_notices = true)
3671
+	{
3672
+		//first let's set individual error properties if doing_ajax and the properties aren't already set.
3673
+		if (defined('DOING_AJAX') && DOING_AJAX) {
3674
+			$notices = EE_Error::get_notices(false);
3675
+			if (empty($this->_template_args['success'])) {
3676
+				$this->_template_args['success'] = isset($notices['success']) ? $notices['success'] : false;
3677
+			}
3678
+			if (empty($this->_template_args['errors'])) {
3679
+				$this->_template_args['errors'] = isset($notices['errors']) ? $notices['errors'] : false;
3680
+			}
3681
+			if (empty($this->_template_args['attention'])) {
3682
+				$this->_template_args['attention'] = isset($notices['attention']) ? $notices['attention'] : false;
3683
+			}
3684
+		}
3685
+		$this->_template_args['notices'] = EE_Error::get_notices();
3686
+		//IF this isn't ajax we need to create a transient for the notices using the route (however, overridden if $sticky_notices == true)
3687
+		if (! defined('DOING_AJAX') || $sticky_notices) {
3688
+			$route = isset($query_args['action']) ? $query_args['action'] : 'default';
3689
+			$this->_add_transient(
3690
+				$route,
3691
+				$this->_template_args['notices'],
3692
+				true,
3693
+				$skip_route_verify
3694
+			);
3695
+		}
3696
+	}
3697
+
3698
+
3699
+
3700
+	/**
3701
+	 * get_action_link_or_button
3702
+	 * returns the button html for adding, editing, or deleting an item (depending on given type)
3703
+	 *
3704
+	 * @param string $action        use this to indicate which action the url is generated with.
3705
+	 * @param string $type          accepted strings must be defined in the $_labels['button'] array(as the key)
3706
+	 *                              property.
3707
+	 * @param array  $extra_request if the button requires extra params you can include them in $key=>$value pairs.
3708
+	 * @param string $class         Use this to give the class for the button. Defaults to 'button-primary'
3709
+	 * @param string $base_url      If this is not provided
3710
+	 *                              the _admin_base_url will be used as the default for the button base_url.
3711
+	 *                              Otherwise this value will be used.
3712
+	 * @param bool   $exclude_nonce If true then no nonce will be in the generated button link.
3713
+	 * @return string
3714
+	 * @throws InvalidArgumentException
3715
+	 * @throws InvalidInterfaceException
3716
+	 * @throws InvalidDataTypeException
3717
+	 * @throws EE_Error
3718
+	 */
3719
+	public function get_action_link_or_button(
3720
+		$action,
3721
+		$type = 'add',
3722
+		$extra_request = array(),
3723
+		$class = 'button-primary',
3724
+		$base_url = '',
3725
+		$exclude_nonce = false
3726
+	) {
3727
+		//first let's validate the action (if $base_url is FALSE otherwise validation will happen further along)
3728
+		if (empty($base_url) && ! isset($this->_page_routes[$action])) {
3729
+			throw new EE_Error(
3730
+				sprintf(
3731
+					esc_html__(
3732
+						'There is no page route for given action for the button.  This action was given: %s',
3733
+						'event_espresso'
3734
+					),
3735
+					$action
3736
+				)
3737
+			);
3738
+		}
3739
+		if (! isset($this->_labels['buttons'][$type])) {
3740
+			throw new EE_Error(
3741
+				sprintf(
3742
+					__(
3743
+						'There is no label for the given button type (%s). Labels are set in the <code>_page_config</code> property.',
3744
+						'event_espresso'
3745
+					),
3746
+					$type
3747
+				)
3748
+			);
3749
+		}
3750
+		//finally check user access for this button.
3751
+		$has_access = $this->check_user_access($action, true);
3752
+		if (! $has_access) {
3753
+			return '';
3754
+		}
3755
+		$_base_url  = ! $base_url ? $this->_admin_base_url : $base_url;
3756
+		$query_args = array(
3757
+			'action' => $action,
3758
+		);
3759
+		//merge extra_request args but make sure our original action takes precedence and doesn't get overwritten.
3760
+		if (! empty($extra_request)) {
3761
+			$query_args = array_merge($extra_request, $query_args);
3762
+		}
3763
+		$url = self::add_query_args_and_nonce($query_args, $_base_url, false, $exclude_nonce);
3764
+		return EEH_Template::get_button_or_link($url, $this->_labels['buttons'][$type], $class);
3765
+	}
3766
+
3767
+
3768
+
3769
+	/**
3770
+	 * _per_page_screen_option
3771
+	 * Utility function for adding in a per_page_option in the screen_options_dropdown.
3772
+	 *
3773
+	 * @return void
3774
+	 * @throws InvalidArgumentException
3775
+	 * @throws InvalidInterfaceException
3776
+	 * @throws InvalidDataTypeException
3777
+	 */
3778
+	protected function _per_page_screen_option()
3779
+	{
3780
+		$option = 'per_page';
3781
+		$args   = array(
3782
+			'label'   => esc_html__(
3783
+					apply_filters(
3784
+						'FHEE__EE_Admin_Page___per_page_screen_options___label',
3785
+						$this->_admin_page_title,
3786
+						$this
3787
+					)
3788
+			),
3789
+			'default' => (int) apply_filters(
3790
+					'FHEE__EE_Admin_Page___per_page_screen_options__default',
3791
+					10
3792
+			),
3793
+			'option'  => $this->_current_page . '_' . $this->_current_view . '_per_page',
3794
+		);
3795
+		//ONLY add the screen option if the user has access to it.
3796
+		if ($this->check_user_access($this->_current_view, true)) {
3797
+			add_screen_option($option, $args);
3798
+		}
3799
+	}
3800
+
3801
+
3802
+
3803
+	/**
3804
+	 * set_per_page_screen_option
3805
+	 * All this does is make sure that WordPress saves any per_page screen options (if set) for the current page.
3806
+	 * we have to do this rather than running inside the 'set-screen-options' hook because it runs earlier than
3807
+	 * admin_menu.
3808
+	 *
3809
+	 * @return void
3810
+	 */
3811
+	private function _set_per_page_screen_options()
3812
+	{
3813
+		if (isset($_POST['wp_screen_options']) && is_array($_POST['wp_screen_options'])) {
3814
+			check_admin_referer('screen-options-nonce', 'screenoptionnonce');
3815
+			if (! $user = wp_get_current_user()) {
3816
+				return;
3817
+			}
3818
+			$option = $_POST['wp_screen_options']['option'];
3819
+			$value  = $_POST['wp_screen_options']['value'];
3820
+			if ($option != sanitize_key($option)) {
3821
+				return;
3822
+			}
3823
+			$map_option = $option;
3824
+			$option     = str_replace('-', '_', $option);
3825
+			switch ($map_option) {
3826
+				case $this->_current_page . '_' . $this->_current_view . '_per_page':
3827
+					$value = (int)$value;
3828
+					$max_value = apply_filters(
3829
+						'FHEE__EE_Admin_Page___set_per_page_screen_options__max_value',
3830
+						999,
3831
+						$this->_current_page,
3832
+						$this->_current_view
3833
+					);
3834
+					if ($value < 1) {
3835
+						return;
3836
+					}
3837
+					$value = min($value, $max_value);
3838
+					break;
3839
+				default:
3840
+					$value = apply_filters(
3841
+						'FHEE__EE_Admin_Page___set_per_page_screen_options__value',
3842
+						false,
3843
+						$option,
3844
+						$value
3845
+					);
3846
+					if (false === $value) {
3847
+						return;
3848
+					}
3849
+					break;
3850
+			}
3851
+			update_user_meta($user->ID, $option, $value);
3852
+			wp_safe_redirect(remove_query_arg(array('pagenum', 'apage', 'paged'), wp_get_referer()));
3853
+			exit;
3854
+		}
3855
+	}
3856
+
3857
+
3858
+
3859
+	/**
3860
+	 * This just allows for setting the $_template_args property if it needs to be set outside the object
3861
+	 *
3862
+	 * @param array $data array that will be assigned to template args.
3863
+	 */
3864
+	public function set_template_args($data)
3865
+	{
3866
+		$this->_template_args = array_merge($this->_template_args, (array)$data);
3867
+	}
3868
+
3869
+
3870
+
3871
+	/**
3872
+	 * This makes available the WP transient system for temporarily moving data between routes
3873
+	 *
3874
+	 * @param string $route             the route that should receive the transient
3875
+	 * @param array  $data              the data that gets sent
3876
+	 * @param bool   $notices           If this is for notices then we use this to indicate so, otherwise its just a
3877
+	 *                                  normal route transient.
3878
+	 * @param bool   $skip_route_verify Used to indicate we want to skip route verification.  This is usually ONLY used
3879
+	 *                                  when we are adding a transient before page_routes have been defined.
3880
+	 * @return void
3881
+	 * @throws EE_Error
3882
+	 */
3883
+	protected function _add_transient($route, $data, $notices = false, $skip_route_verify = false)
3884
+	{
3885
+		$user_id = get_current_user_id();
3886
+		if (! $skip_route_verify) {
3887
+			$this->_verify_route($route);
3888
+		}
3889
+		//now let's set the string for what kind of transient we're setting
3890
+		$transient = $notices
3891
+			? 'ee_rte_n_tx_' . $route . '_' . $user_id
3892
+			: 'rte_tx_' . $route . '_' . $user_id;
3893
+		$data      = $notices ? array('notices' => $data) : $data;
3894
+		//is there already a transient for this route?  If there is then let's ADD to that transient
3895
+		$existing = is_multisite() && is_network_admin()
3896
+			? get_site_transient($transient)
3897
+			: get_transient($transient);
3898
+		if ($existing) {
3899
+			$data = array_merge((array)$data, (array)$existing);
3900
+		}
3901
+		if (is_multisite() && is_network_admin()) {
3902
+			set_site_transient($transient, $data, 8);
3903
+		} else {
3904
+			set_transient($transient, $data, 8);
3905
+		}
3906
+	}
3907
+
3908
+
3909
+
3910
+	/**
3911
+	 * this retrieves the temporary transient that has been set for moving data between routes.
3912
+	 *
3913
+	 * @param bool   $notices true we get notices transient. False we just return normal route transient
3914
+	 * @param string $route
3915
+	 * @return mixed data
3916
+	 */
3917
+	protected function _get_transient($notices = false, $route = '')
3918
+	{
3919
+		$user_id   = get_current_user_id();
3920
+		$route     = ! $route ? $this->_req_action : $route;
3921
+		$transient = $notices
3922
+			? 'ee_rte_n_tx_' . $route . '_' . $user_id
3923
+			: 'rte_tx_' . $route . '_' . $user_id;
3924
+		$data      = is_multisite() && is_network_admin()
3925
+			? get_site_transient($transient)
3926
+			: get_transient($transient);
3927
+		//delete transient after retrieval (just in case it hasn't expired);
3928
+		if (is_multisite() && is_network_admin()) {
3929
+			delete_site_transient($transient);
3930
+		} else {
3931
+			delete_transient($transient);
3932
+		}
3933
+		return $notices && isset($data['notices']) ? $data['notices'] : $data;
3934
+	}
3935
+
3936
+
3937
+
3938
+	/**
3939
+	 * The purpose of this method is just to run garbage collection on any EE transients that might have expired but
3940
+	 * would not be called later. This will be assigned to run on a specific EE Admin page. (place the method in the
3941
+	 * default route callback on the EE_Admin page you want it run.)
3942
+	 *
3943
+	 * @return void
3944
+	 */
3945
+	protected function _transient_garbage_collection()
3946
+	{
3947
+		global $wpdb;
3948
+		//retrieve all existing transients
3949
+		$query = "SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE '%rte_tx_%' OR option_name LIKE '%rte_n_tx_%'";
3950
+		if ($results = $wpdb->get_results($query)) {
3951
+			foreach ($results as $result) {
3952
+				$transient = str_replace('_transient_', '', $result->option_name);
3953
+				get_transient($transient);
3954
+				if (is_multisite() && is_network_admin()) {
3955
+					get_site_transient($transient);
3956
+				}
3957
+			}
3958
+		}
3959
+	}
3960
+
3961
+
3962
+
3963
+	/**
3964
+	 * get_view
3965
+	 *
3966
+	 * @return string content of _view property
3967
+	 */
3968
+	public function get_view()
3969
+	{
3970
+		return $this->_view;
3971
+	}
3972
+
3973
+
3974
+
3975
+	/**
3976
+	 * getter for the protected $_views property
3977
+	 *
3978
+	 * @return array
3979
+	 */
3980
+	public function get_views()
3981
+	{
3982
+		return $this->_views;
3983
+	}
3984
+
3985
+
3986
+
3987
+	/**
3988
+	 * get_current_page
3989
+	 *
3990
+	 * @return string _current_page property value
3991
+	 */
3992
+	public function get_current_page()
3993
+	{
3994
+		return $this->_current_page;
3995
+	}
3996
+
3997
+
3998
+
3999
+	/**
4000
+	 * get_current_view
4001
+	 *
4002
+	 * @return string _current_view property value
4003
+	 */
4004
+	public function get_current_view()
4005
+	{
4006
+		return $this->_current_view;
4007
+	}
4008
+
4009
+
4010
+
4011
+	/**
4012
+	 * get_current_screen
4013
+	 *
4014
+	 * @return object The current WP_Screen object
4015
+	 */
4016
+	public function get_current_screen()
4017
+	{
4018
+		return $this->_current_screen;
4019
+	}
4020
+
4021
+
4022
+
4023
+	/**
4024
+	 * get_current_page_view_url
4025
+	 *
4026
+	 * @return string This returns the url for the current_page_view.
4027
+	 */
4028
+	public function get_current_page_view_url()
4029
+	{
4030
+		return $this->_current_page_view_url;
4031
+	}
4032
+
4033
+
4034
+
4035
+	/**
4036
+	 * just returns the _req_data property
4037
+	 *
4038
+	 * @return array
4039
+	 */
4040
+	public function get_request_data()
4041
+	{
4042
+		return $this->_req_data;
4043
+	}
4044
+
4045
+
4046
+
4047
+	/**
4048
+	 * returns the _req_data protected property
4049
+	 *
4050
+	 * @return string
4051
+	 */
4052
+	public function get_req_action()
4053
+	{
4054
+		return $this->_req_action;
4055
+	}
4056
+
4057
+
4058
+
4059
+	/**
4060
+	 * @return bool  value of $_is_caf property
4061
+	 */
4062
+	public function is_caf()
4063
+	{
4064
+		return $this->_is_caf;
4065
+	}
4066
+
4067
+
4068
+
4069
+	/**
4070
+	 * @return mixed
4071
+	 */
4072
+	public function default_espresso_metaboxes()
4073
+	{
4074
+		return $this->_default_espresso_metaboxes;
4075
+	}
4076
+
4077
+
4078
+
4079
+	/**
4080
+	 * @return mixed
4081
+	 */
4082
+	public function admin_base_url()
4083
+	{
4084
+		return $this->_admin_base_url;
4085
+	}
4086 4086
 
4087 4087
 
4088 4088
 
4089
-    /**
4090
-     * @return mixed
4091
-     */
4092
-    public function wp_page_slug()
4093
-    {
4094
-        return $this->_wp_page_slug;
4095
-    }
4089
+	/**
4090
+	 * @return mixed
4091
+	 */
4092
+	public function wp_page_slug()
4093
+	{
4094
+		return $this->_wp_page_slug;
4095
+	}
4096 4096
 
4097 4097
 
4098
-
4099
-    /**
4100
-     * updates  espresso configuration settings
4101
-     *
4102
-     * @param string                   $tab
4103
-     * @param EE_Config_Base|EE_Config $config
4104
-     * @param string                   $file file where error occurred
4105
-     * @param string                   $func function  where error occurred
4106
-     * @param string                   $line line no where error occurred
4107
-     * @return boolean
4108
-     */
4109
-    protected function _update_espresso_configuration($tab, $config, $file = '', $func = '', $line = '')
4110
-    {
4111
-        //remove any options that are NOT going to be saved with the config settings.
4112
-        if (isset($config->core->ee_ueip_optin)) {
4113
-            $config->core->ee_ueip_has_notified = true;
4114
-            // TODO: remove the following two lines and make sure values are migrated from 3.1
4115
-            update_option('ee_ueip_optin', $config->core->ee_ueip_optin);
4116
-            update_option('ee_ueip_has_notified', true);
4117
-        }
4118
-        // and save it (note we're also doing the network save here)
4119
-        $net_saved    = is_main_site() ? EE_Network_Config::instance()->update_config(false, false) : true;
4120
-        $config_saved = EE_Config::instance()->update_espresso_config(false, false);
4121
-        if ($config_saved && $net_saved) {
4122
-            EE_Error::add_success(sprintf(__('"%s" have been successfully updated.', 'event_espresso'), $tab));
4123
-            return true;
4124
-        }
4125
-        EE_Error::add_error(sprintf(__('The "%s" were not updated.', 'event_espresso'), $tab), $file, $func, $line);
4126
-        return false;
4127
-    }
4128
-
4129
-
4130
-
4131
-    /**
4132
-     * Returns an array to be used for EE_FOrm_Fields.helper.php's select_input as the $values argument.
4133
-     *
4134
-     * @return array
4135
-     */
4136
-    public function get_yes_no_values()
4137
-    {
4138
-        return $this->_yes_no_values;
4139
-    }
4140
-
4141
-
4142
-
4143
-    protected function _get_dir()
4144
-    {
4145
-        $reflector = new ReflectionClass(get_class($this));
4146
-        return dirname($reflector->getFileName());
4147
-    }
4148
-
4149
-
4150
-
4151
-    /**
4152
-     * A helper for getting a "next link".
4153
-     *
4154
-     * @param string $url   The url to link to
4155
-     * @param string $class The class to use.
4156
-     * @return string
4157
-     */
4158
-    protected function _next_link($url, $class = 'dashicons dashicons-arrow-right')
4159
-    {
4160
-        return '<a class="' . $class . '" href="' . $url . '"></a>';
4161
-    }
4162
-
4163
-
4164
-
4165
-    /**
4166
-     * A helper for getting a "previous link".
4167
-     *
4168
-     * @param string $url   The url to link to
4169
-     * @param string $class The class to use.
4170
-     * @return string
4171
-     */
4172
-    protected function _previous_link($url, $class = 'dashicons dashicons-arrow-left')
4173
-    {
4174
-        return '<a class="' . $class . '" href="' . $url . '"></a>';
4175
-    }
4176
-
4177
-
4178
-
4179
-
4180
-
4181
-
4182
-
4183
-    //below are some messages related methods that should be available across the EE_Admin system.  Note, these methods are NOT page specific
4184
-
4185
-
4186
-    /**
4187
-     * This processes an request to resend a registration and assumes we have a _REG_ID for doing so. So if the caller
4188
-     * 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
4189
-     * _req_data array.
4190
-     *
4191
-     * @return bool success/fail
4192
-     * @throws EE_Error
4193
-     * @throws InvalidArgumentException
4194
-     * @throws ReflectionException
4195
-     * @throws InvalidDataTypeException
4196
-     * @throws InvalidInterfaceException
4197
-     */
4198
-    protected function _process_resend_registration()
4199
-    {
4200
-        $this->_template_args['success'] = EED_Messages::process_resend($this->_req_data);
4201
-        do_action(
4202
-            'AHEE__EE_Admin_Page___process_resend_registration',
4203
-            $this->_template_args['success'],
4204
-            $this->_req_data
4205
-        );
4206
-        return $this->_template_args['success'];
4207
-    }
4208
-
4209
-
4210
-
4211
-    /**
4212
-     * This automatically processes any payment message notifications when manual payment has been applied.
4213
-     *
4214
-     * @param \EE_Payment $payment
4215
-     * @return bool success/fail
4216
-     */
4217
-    protected function _process_payment_notification(EE_Payment $payment)
4218
-    {
4219
-        add_filter('FHEE__EE_Payment_Processor__process_registration_payments__display_notifications', '__return_true');
4220
-        do_action('AHEE__EE_Admin_Page___process_admin_payment_notification', $payment);
4221
-        $this->_template_args['success'] = apply_filters(
4222
-            'FHEE__EE_Admin_Page___process_admin_payment_notification__success',
4223
-            false,
4224
-            $payment
4225
-        );
4226
-        return $this->_template_args['success'];
4227
-    }
4098
+
4099
+	/**
4100
+	 * updates  espresso configuration settings
4101
+	 *
4102
+	 * @param string                   $tab
4103
+	 * @param EE_Config_Base|EE_Config $config
4104
+	 * @param string                   $file file where error occurred
4105
+	 * @param string                   $func function  where error occurred
4106
+	 * @param string                   $line line no where error occurred
4107
+	 * @return boolean
4108
+	 */
4109
+	protected function _update_espresso_configuration($tab, $config, $file = '', $func = '', $line = '')
4110
+	{
4111
+		//remove any options that are NOT going to be saved with the config settings.
4112
+		if (isset($config->core->ee_ueip_optin)) {
4113
+			$config->core->ee_ueip_has_notified = true;
4114
+			// TODO: remove the following two lines and make sure values are migrated from 3.1
4115
+			update_option('ee_ueip_optin', $config->core->ee_ueip_optin);
4116
+			update_option('ee_ueip_has_notified', true);
4117
+		}
4118
+		// and save it (note we're also doing the network save here)
4119
+		$net_saved    = is_main_site() ? EE_Network_Config::instance()->update_config(false, false) : true;
4120
+		$config_saved = EE_Config::instance()->update_espresso_config(false, false);
4121
+		if ($config_saved && $net_saved) {
4122
+			EE_Error::add_success(sprintf(__('"%s" have been successfully updated.', 'event_espresso'), $tab));
4123
+			return true;
4124
+		}
4125
+		EE_Error::add_error(sprintf(__('The "%s" were not updated.', 'event_espresso'), $tab), $file, $func, $line);
4126
+		return false;
4127
+	}
4128
+
4129
+
4130
+
4131
+	/**
4132
+	 * Returns an array to be used for EE_FOrm_Fields.helper.php's select_input as the $values argument.
4133
+	 *
4134
+	 * @return array
4135
+	 */
4136
+	public function get_yes_no_values()
4137
+	{
4138
+		return $this->_yes_no_values;
4139
+	}
4140
+
4141
+
4142
+
4143
+	protected function _get_dir()
4144
+	{
4145
+		$reflector = new ReflectionClass(get_class($this));
4146
+		return dirname($reflector->getFileName());
4147
+	}
4148
+
4149
+
4150
+
4151
+	/**
4152
+	 * A helper for getting a "next link".
4153
+	 *
4154
+	 * @param string $url   The url to link to
4155
+	 * @param string $class The class to use.
4156
+	 * @return string
4157
+	 */
4158
+	protected function _next_link($url, $class = 'dashicons dashicons-arrow-right')
4159
+	{
4160
+		return '<a class="' . $class . '" href="' . $url . '"></a>';
4161
+	}
4162
+
4163
+
4164
+
4165
+	/**
4166
+	 * A helper for getting a "previous link".
4167
+	 *
4168
+	 * @param string $url   The url to link to
4169
+	 * @param string $class The class to use.
4170
+	 * @return string
4171
+	 */
4172
+	protected function _previous_link($url, $class = 'dashicons dashicons-arrow-left')
4173
+	{
4174
+		return '<a class="' . $class . '" href="' . $url . '"></a>';
4175
+	}
4176
+
4177
+
4178
+
4179
+
4180
+
4181
+
4182
+
4183
+	//below are some messages related methods that should be available across the EE_Admin system.  Note, these methods are NOT page specific
4184
+
4185
+
4186
+	/**
4187
+	 * This processes an request to resend a registration and assumes we have a _REG_ID for doing so. So if the caller
4188
+	 * 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
4189
+	 * _req_data array.
4190
+	 *
4191
+	 * @return bool success/fail
4192
+	 * @throws EE_Error
4193
+	 * @throws InvalidArgumentException
4194
+	 * @throws ReflectionException
4195
+	 * @throws InvalidDataTypeException
4196
+	 * @throws InvalidInterfaceException
4197
+	 */
4198
+	protected function _process_resend_registration()
4199
+	{
4200
+		$this->_template_args['success'] = EED_Messages::process_resend($this->_req_data);
4201
+		do_action(
4202
+			'AHEE__EE_Admin_Page___process_resend_registration',
4203
+			$this->_template_args['success'],
4204
+			$this->_req_data
4205
+		);
4206
+		return $this->_template_args['success'];
4207
+	}
4208
+
4209
+
4210
+
4211
+	/**
4212
+	 * This automatically processes any payment message notifications when manual payment has been applied.
4213
+	 *
4214
+	 * @param \EE_Payment $payment
4215
+	 * @return bool success/fail
4216
+	 */
4217
+	protected function _process_payment_notification(EE_Payment $payment)
4218
+	{
4219
+		add_filter('FHEE__EE_Payment_Processor__process_registration_payments__display_notifications', '__return_true');
4220
+		do_action('AHEE__EE_Admin_Page___process_admin_payment_notification', $payment);
4221
+		$this->_template_args['success'] = apply_filters(
4222
+			'FHEE__EE_Admin_Page___process_admin_payment_notification__success',
4223
+			false,
4224
+			$payment
4225
+		);
4226
+		return $this->_template_args['success'];
4227
+	}
4228 4228
 
4229 4229
 
4230 4230
 }
Please login to merge, or discard this patch.
core/db_models/EEM_Transaction.model.php 1 patch
Indentation   +405 added lines, -405 removed lines patch added patch discarded remove patch
@@ -5,7 +5,7 @@  discard block
 block discarded – undo
5 5
 use EventEspresso\core\services\loaders\LoaderFactory;
6 6
 
7 7
 if ( ! defined('EVENT_ESPRESSO_VERSION')) {
8
-    exit('No direct script access allowed');
8
+	exit('No direct script access allowed');
9 9
 }
10 10
 require_once(EE_MODELS . 'EEM_Base.model.php');
11 11
 
@@ -21,193 +21,193 @@  discard block
 block discarded – undo
21 21
 class EEM_Transaction extends EEM_Base
22 22
 {
23 23
 
24
-    // private instance of the Transaction object
25
-    protected static $_instance;
26
-
27
-    /**
28
-     * Status ID(STS_ID on esp_status table) to indicate the transaction is complete,
29
-     * but payment is pending. This is the state for transactions where payment is promised
30
-     * from an offline gateway.
31
-     */
32
-    //	const open_status_code = 'TPN';
33
-
34
-    /**
35
-     * Status ID(STS_ID on esp_status table) to indicate the transaction failed,
36
-     * either due to a technical reason (server or computer crash during registration),
37
-     *  or some other reason that prevent the collection of any useful contact information from any of the registrants
38
-     */
39
-    const failed_status_code = 'TFL';
40
-
41
-    /**
42
-     * Status ID(STS_ID on esp_status table) to indicate the transaction was abandoned,
43
-     * either due to a technical reason (server or computer crash during registration),
44
-     * or due to an abandoned cart after registrant chose not to complete the registration process
45
-     * HOWEVER...
46
-     * an abandoned TXN differs from a failed TXN in that it was able to capture contact information for at least one
47
-     * registrant
48
-     */
49
-    const abandoned_status_code = 'TAB';
50
-
51
-    /**
52
-     * Status ID(STS_ID on esp_status table) to indicate an incomplete transaction,
53
-     * meaning that monies are still owing: TXN_paid < TXN_total
54
-     */
55
-    const incomplete_status_code = 'TIN';
56
-
57
-    /**
58
-     * Status ID (STS_ID on esp_status table) to indicate a complete transaction.
59
-     * meaning that NO monies are owing: TXN_paid == TXN_total
60
-     */
61
-    const complete_status_code = 'TCM';
62
-
63
-    /**
64
-     *  Status ID(STS_ID on esp_status table) to indicate the transaction is overpaid.
65
-     *  This is the same as complete, but site admins actually owe clients the moneys!  TXN_paid > TXN_total
66
-     */
67
-    const overpaid_status_code = 'TOP';
68
-
69
-
70
-    /**
71
-     *    private constructor to prevent direct creation
72
-     *
73
-     * @Constructor
74
-     * @access protected
75
-     *
76
-     * @param string $timezone string representing the timezone we want to set for returned Date Time Strings (and any
77
-     *                         incoming timezone data that gets saved). Note this just sends the timezone info to the
78
-     *                         date time model field objects.  Default is NULL (and will be assumed using the set
79
-     *                         timezone in the 'timezone_string' wp option)
80
-     *
81
-     * @return EEM_Transaction
82
-     * @throws \EE_Error
83
-     */
84
-    protected function __construct($timezone)
85
-    {
86
-        $this->singular_item = __('Transaction', 'event_espresso');
87
-        $this->plural_item   = __('Transactions', 'event_espresso');
88
-
89
-        $this->_tables                 = array(
90
-            'TransactionTable' => new EE_Primary_Table('esp_transaction', 'TXN_ID')
91
-        );
92
-        $this->_fields                 = array(
93
-            'TransactionTable' => array(
94
-                'TXN_ID'           => new EE_Primary_Key_Int_Field('TXN_ID', __('Transaction ID', 'event_espresso')),
95
-                'TXN_timestamp'    => new EE_Datetime_Field('TXN_timestamp',
96
-                    __('date when transaction was created', 'event_espresso'), false, EE_Datetime_Field::now,
97
-                    $timezone),
98
-                'TXN_total'        => new EE_Money_Field('TXN_total',
99
-                    __('Total value of Transaction', 'event_espresso'), false, 0),
100
-                'TXN_paid'         => new EE_Money_Field('TXN_paid',
101
-                    __('Amount paid towards transaction to date', 'event_espresso'), false, 0),
102
-                'STS_ID'           => new EE_Foreign_Key_String_Field('STS_ID', __('Status ID', 'event_espresso'),
103
-                    false, EEM_Transaction::failed_status_code, 'Status'),
104
-                'TXN_session_data' => new EE_Serialized_Text_Field('TXN_session_data',
105
-                    __('Serialized session data', 'event_espresso'), true, ''),
106
-                'TXN_hash_salt'    => new EE_Plain_Text_Field('TXN_hash_salt',
107
-                    __('Transaction Hash Salt', 'event_espresso'), true, ''),
108
-                'PMD_ID'           => new EE_Foreign_Key_Int_Field('PMD_ID',
109
-                    __("Last Used Payment Method", 'event_espresso'), true, null, 'Payment_Method'),
110
-                'TXN_reg_steps'    => new EE_Serialized_Text_Field('TXN_reg_steps',
111
-                    __('Registration Steps', 'event_espresso'), false, array()),
112
-            )
113
-        );
114
-        $this->_model_relations        = array(
115
-            'Registration'   => new EE_Has_Many_Relation(),
116
-            'Payment'        => new EE_Has_Many_Relation(),
117
-            'Status'         => new EE_Belongs_To_Relation(),
118
-            'Line_Item'      => new EE_Has_Many_Relation(false),
119
-            //you can delete a transaction without needing to delete its line items
120
-            'Payment_Method' => new EE_Belongs_To_Relation(),
121
-            'Message'        => new EE_Has_Many_Relation()
122
-        );
123
-        $this->_model_chain_to_wp_user = 'Registration.Event';
124
-        parent::__construct($timezone);
125
-
126
-    }
127
-
128
-
129
-    /**
130
-     *    txn_status_array
131
-     * get list of transaction statuses
132
-     *
133
-     * @access public
134
-     * @return array
135
-     */
136
-    public static function txn_status_array()
137
-    {
138
-        return apply_filters(
139
-            'FHEE__EEM_Transaction__txn_status_array',
140
-            array(
141
-                EEM_Transaction::overpaid_status_code,
142
-                EEM_Transaction::complete_status_code,
143
-                EEM_Transaction::incomplete_status_code,
144
-                EEM_Transaction::abandoned_status_code,
145
-                EEM_Transaction::failed_status_code,
146
-            )
147
-        );
148
-    }
149
-
150
-    /**
151
-     *        get the revenue per day  for the Transaction Admin page Reports Tab
152
-     *
153
-     * @access        public
154
-     *
155
-     * @param string $period
156
-     *
157
-     * @return \stdClass[]
158
-     */
159
-    public function get_revenue_per_day_report($period = '-1 month')
160
-    {
161
-        $sql_date = $this->convert_datetime_for_query('TXN_timestamp', date('Y-m-d H:i:s', strtotime($period)),
162
-            'Y-m-d H:i:s', 'UTC');
163
-
164
-        $query_interval = EEH_DTT_Helper::get_sql_query_interval_for_offset($this->get_timezone(), 'TXN_timestamp');
165
-
166
-        return $this->_get_all_wpdb_results(
167
-            array(
168
-                array(
169
-                    'TXN_timestamp' => array('>=', $sql_date)
170
-                ),
171
-                'group_by' => 'txnDate',
172
-                'order_by' => array('TXN_timestamp' => 'ASC')
173
-            ),
174
-            OBJECT,
175
-            array(
176
-                'txnDate' => array('DATE(' . $query_interval . ')', '%s'),
177
-                'revenue' => array('SUM(TransactionTable.TXN_paid)', '%d')
178
-            )
179
-        );
180
-    }
181
-
182
-
183
-    /**
184
-     *        get the revenue per event  for the Transaction Admin page Reports Tab
185
-     *
186
-     * @access        public
187
-     *
188
-     * @param string $period
189
-     *
190
-     * @throws \EE_Error
191
-     * @return mixed
192
-     */
193
-    public function get_revenue_per_event_report($period = '-1 month')
194
-    {
195
-        global $wpdb;
196
-        $transaction_table          = $wpdb->prefix . 'esp_transaction';
197
-        $registration_table         = $wpdb->prefix . 'esp_registration';
198
-        $registration_payment_table = $wpdb->prefix . 'esp_registration_payment';
199
-        $event_table                = $wpdb->posts;
200
-        $payment_table              = $wpdb->prefix . 'esp_payment';
201
-        $sql_date                   = date('Y-m-d H:i:s', strtotime($period));
202
-        $approved_payment_status    = EEM_Payment::status_id_approved;
203
-        $extra_event_on_join        = '';
204
-        //exclude events not authored by user if permissions in effect
205
-        if ( ! EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_event_report')) {
206
-            $extra_event_on_join = ' AND Event.post_author = ' . get_current_user_id();
207
-        }
208
-
209
-        return $wpdb->get_results(
210
-            "SELECT
24
+	// private instance of the Transaction object
25
+	protected static $_instance;
26
+
27
+	/**
28
+	 * Status ID(STS_ID on esp_status table) to indicate the transaction is complete,
29
+	 * but payment is pending. This is the state for transactions where payment is promised
30
+	 * from an offline gateway.
31
+	 */
32
+	//	const open_status_code = 'TPN';
33
+
34
+	/**
35
+	 * Status ID(STS_ID on esp_status table) to indicate the transaction failed,
36
+	 * either due to a technical reason (server or computer crash during registration),
37
+	 *  or some other reason that prevent the collection of any useful contact information from any of the registrants
38
+	 */
39
+	const failed_status_code = 'TFL';
40
+
41
+	/**
42
+	 * Status ID(STS_ID on esp_status table) to indicate the transaction was abandoned,
43
+	 * either due to a technical reason (server or computer crash during registration),
44
+	 * or due to an abandoned cart after registrant chose not to complete the registration process
45
+	 * HOWEVER...
46
+	 * an abandoned TXN differs from a failed TXN in that it was able to capture contact information for at least one
47
+	 * registrant
48
+	 */
49
+	const abandoned_status_code = 'TAB';
50
+
51
+	/**
52
+	 * Status ID(STS_ID on esp_status table) to indicate an incomplete transaction,
53
+	 * meaning that monies are still owing: TXN_paid < TXN_total
54
+	 */
55
+	const incomplete_status_code = 'TIN';
56
+
57
+	/**
58
+	 * Status ID (STS_ID on esp_status table) to indicate a complete transaction.
59
+	 * meaning that NO monies are owing: TXN_paid == TXN_total
60
+	 */
61
+	const complete_status_code = 'TCM';
62
+
63
+	/**
64
+	 *  Status ID(STS_ID on esp_status table) to indicate the transaction is overpaid.
65
+	 *  This is the same as complete, but site admins actually owe clients the moneys!  TXN_paid > TXN_total
66
+	 */
67
+	const overpaid_status_code = 'TOP';
68
+
69
+
70
+	/**
71
+	 *    private constructor to prevent direct creation
72
+	 *
73
+	 * @Constructor
74
+	 * @access protected
75
+	 *
76
+	 * @param string $timezone string representing the timezone we want to set for returned Date Time Strings (and any
77
+	 *                         incoming timezone data that gets saved). Note this just sends the timezone info to the
78
+	 *                         date time model field objects.  Default is NULL (and will be assumed using the set
79
+	 *                         timezone in the 'timezone_string' wp option)
80
+	 *
81
+	 * @return EEM_Transaction
82
+	 * @throws \EE_Error
83
+	 */
84
+	protected function __construct($timezone)
85
+	{
86
+		$this->singular_item = __('Transaction', 'event_espresso');
87
+		$this->plural_item   = __('Transactions', 'event_espresso');
88
+
89
+		$this->_tables                 = array(
90
+			'TransactionTable' => new EE_Primary_Table('esp_transaction', 'TXN_ID')
91
+		);
92
+		$this->_fields                 = array(
93
+			'TransactionTable' => array(
94
+				'TXN_ID'           => new EE_Primary_Key_Int_Field('TXN_ID', __('Transaction ID', 'event_espresso')),
95
+				'TXN_timestamp'    => new EE_Datetime_Field('TXN_timestamp',
96
+					__('date when transaction was created', 'event_espresso'), false, EE_Datetime_Field::now,
97
+					$timezone),
98
+				'TXN_total'        => new EE_Money_Field('TXN_total',
99
+					__('Total value of Transaction', 'event_espresso'), false, 0),
100
+				'TXN_paid'         => new EE_Money_Field('TXN_paid',
101
+					__('Amount paid towards transaction to date', 'event_espresso'), false, 0),
102
+				'STS_ID'           => new EE_Foreign_Key_String_Field('STS_ID', __('Status ID', 'event_espresso'),
103
+					false, EEM_Transaction::failed_status_code, 'Status'),
104
+				'TXN_session_data' => new EE_Serialized_Text_Field('TXN_session_data',
105
+					__('Serialized session data', 'event_espresso'), true, ''),
106
+				'TXN_hash_salt'    => new EE_Plain_Text_Field('TXN_hash_salt',
107
+					__('Transaction Hash Salt', 'event_espresso'), true, ''),
108
+				'PMD_ID'           => new EE_Foreign_Key_Int_Field('PMD_ID',
109
+					__("Last Used Payment Method", 'event_espresso'), true, null, 'Payment_Method'),
110
+				'TXN_reg_steps'    => new EE_Serialized_Text_Field('TXN_reg_steps',
111
+					__('Registration Steps', 'event_espresso'), false, array()),
112
+			)
113
+		);
114
+		$this->_model_relations        = array(
115
+			'Registration'   => new EE_Has_Many_Relation(),
116
+			'Payment'        => new EE_Has_Many_Relation(),
117
+			'Status'         => new EE_Belongs_To_Relation(),
118
+			'Line_Item'      => new EE_Has_Many_Relation(false),
119
+			//you can delete a transaction without needing to delete its line items
120
+			'Payment_Method' => new EE_Belongs_To_Relation(),
121
+			'Message'        => new EE_Has_Many_Relation()
122
+		);
123
+		$this->_model_chain_to_wp_user = 'Registration.Event';
124
+		parent::__construct($timezone);
125
+
126
+	}
127
+
128
+
129
+	/**
130
+	 *    txn_status_array
131
+	 * get list of transaction statuses
132
+	 *
133
+	 * @access public
134
+	 * @return array
135
+	 */
136
+	public static function txn_status_array()
137
+	{
138
+		return apply_filters(
139
+			'FHEE__EEM_Transaction__txn_status_array',
140
+			array(
141
+				EEM_Transaction::overpaid_status_code,
142
+				EEM_Transaction::complete_status_code,
143
+				EEM_Transaction::incomplete_status_code,
144
+				EEM_Transaction::abandoned_status_code,
145
+				EEM_Transaction::failed_status_code,
146
+			)
147
+		);
148
+	}
149
+
150
+	/**
151
+	 *        get the revenue per day  for the Transaction Admin page Reports Tab
152
+	 *
153
+	 * @access        public
154
+	 *
155
+	 * @param string $period
156
+	 *
157
+	 * @return \stdClass[]
158
+	 */
159
+	public function get_revenue_per_day_report($period = '-1 month')
160
+	{
161
+		$sql_date = $this->convert_datetime_for_query('TXN_timestamp', date('Y-m-d H:i:s', strtotime($period)),
162
+			'Y-m-d H:i:s', 'UTC');
163
+
164
+		$query_interval = EEH_DTT_Helper::get_sql_query_interval_for_offset($this->get_timezone(), 'TXN_timestamp');
165
+
166
+		return $this->_get_all_wpdb_results(
167
+			array(
168
+				array(
169
+					'TXN_timestamp' => array('>=', $sql_date)
170
+				),
171
+				'group_by' => 'txnDate',
172
+				'order_by' => array('TXN_timestamp' => 'ASC')
173
+			),
174
+			OBJECT,
175
+			array(
176
+				'txnDate' => array('DATE(' . $query_interval . ')', '%s'),
177
+				'revenue' => array('SUM(TransactionTable.TXN_paid)', '%d')
178
+			)
179
+		);
180
+	}
181
+
182
+
183
+	/**
184
+	 *        get the revenue per event  for the Transaction Admin page Reports Tab
185
+	 *
186
+	 * @access        public
187
+	 *
188
+	 * @param string $period
189
+	 *
190
+	 * @throws \EE_Error
191
+	 * @return mixed
192
+	 */
193
+	public function get_revenue_per_event_report($period = '-1 month')
194
+	{
195
+		global $wpdb;
196
+		$transaction_table          = $wpdb->prefix . 'esp_transaction';
197
+		$registration_table         = $wpdb->prefix . 'esp_registration';
198
+		$registration_payment_table = $wpdb->prefix . 'esp_registration_payment';
199
+		$event_table                = $wpdb->posts;
200
+		$payment_table              = $wpdb->prefix . 'esp_payment';
201
+		$sql_date                   = date('Y-m-d H:i:s', strtotime($period));
202
+		$approved_payment_status    = EEM_Payment::status_id_approved;
203
+		$extra_event_on_join        = '';
204
+		//exclude events not authored by user if permissions in effect
205
+		if ( ! EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_event_report')) {
206
+			$extra_event_on_join = ' AND Event.post_author = ' . get_current_user_id();
207
+		}
208
+
209
+		return $wpdb->get_results(
210
+			"SELECT
211 211
 			Transaction_Event.event_name AS event_name,
212 212
 			SUM(Transaction_Event.paid) AS revenue
213 213
 			FROM
@@ -235,227 +235,227 @@  discard block
 block discarded – undo
235 235
 					$extra_event_on_join
236 236
 				) AS Transaction_Event
237 237
 			GROUP BY event_name",
238
-            OBJECT
239
-        );
240
-    }
241
-
242
-
243
-    /**
244
-     * Gets the current transaction given the reg_url_link, or assumes the reg_url_link is in the
245
-     * $_REQUEST global variable. Either way, tries to find the current transaction (through
246
-     * the registration pointed to by reg_url_link), if not returns null
247
-     *
248
-     * @param string $reg_url_link
249
-     *
250
-     * @return EE_Transaction
251
-     */
252
-    public function get_transaction_from_reg_url_link($reg_url_link = '')
253
-    {
254
-        return $this->get_one(array(
255
-            array(
256
-                'Registration.REG_url_link' => ! empty($reg_url_link) ? $reg_url_link : EE_Registry::instance()->REQ->get('e_reg_url_link',
257
-                    '')
258
-            )
259
-        ));
260
-    }
261
-
262
-
263
-    /**
264
-     * Updates the provided EE_Transaction with all the applicable payments
265
-     * (or fetch the EE_Transaction from its ID)
266
-     *
267
-     * @deprecated
268
-     *
269
-     * @param EE_Transaction|int $transaction_obj_or_id
270
-     * @param boolean            $save_txn whether or not to save the transaction during this function call
271
-     *
272
-     * @return boolean
273
-     * @throws \EE_Error
274
-     */
275
-    public function update_based_on_payments($transaction_obj_or_id, $save_txn = true)
276
-    {
277
-        EE_Error::doing_it_wrong(
278
-            __CLASS__ . '::' . __FUNCTION__,
279
-            sprintf(__('This method is deprecated. Please use "%s" instead', 'event_espresso'),
280
-                'EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()'),
281
-            '4.6.0'
282
-        );
283
-        /** @type EE_Transaction_Processor $transaction_processor */
284
-        $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
285
-
286
-        return $transaction_processor->update_transaction_and_registrations_after_checkout_or_payment(
287
-            $this->ensure_is_obj($transaction_obj_or_id)
288
-        );
289
-    }
290
-
291
-    /**
292
-     * Deletes "junk" transactions that were probably added by bots. There might be TONS
293
-     * of these, so we are very careful to NOT select (which the models do even when deleting),
294
-     * and so we only use wpdb directly and only do minimal joins.
295
-     * Transactions are considered "junk" if they're failed for longer than a week.
296
-     * Also, there is an extra check for payments related to the transaction, because if a transaction has a payment on
297
-     * it, it's probably not junk (regardless of what status it has).
298
-     * The downside to this approach is that is addons are listening for object deletions
299
-     * on EEM_Base::delete() they won't be notified of this.  However, there is an action that plugins can hook into
300
-     * to catch these types of deletions.
301
-     *
302
-     * @global WPDB $wpdb
303
-     * @return mixed
304
-     */
305
-    public function delete_junk_transactions()
306
-    {
307
-        /** @type WPDB $wpdb */
308
-        global $wpdb;
309
-        $deleted             = false;
310
-        $time_to_leave_alone = apply_filters(
311
-            'FHEE__EEM_Transaction__delete_junk_transactions__time_to_leave_alone'
312
-            , WEEK_IN_SECONDS
313
-        );
314
-
315
-
316
-        /**
317
-         * This allows code to filter the query arguments used for retrieving the transaction IDs to delete.
318
-         * Useful for plugins that want to exclude transactions matching certain query parameters.
319
-         * The query parameters should be in the format accepted by the EEM_Base model queries.
320
-         */
321
-        $ids_query = apply_filters(
322
-            'FHEE__EEM_Transaction__delete_junk_transactions__initial_query_args',
323
-            array(
324
-                0 => array(
325
-                    'STS_ID'        => EEM_Transaction::failed_status_code,
326
-                    'Payment.PAY_ID' => array( 'IS NULL' ),
327
-                    'TXN_timestamp' => array('<', time() - $time_to_leave_alone)
328
-                )
329
-            ),
330
-            $time_to_leave_alone
331
-        );
332
-
333
-
334
-        /**
335
-         * This filter is for when code needs to filter the list of transaction ids that represent transactions
336
-         * about to be deleted based on some other criteria that isn't easily done via the query args filter.
337
-         */
338
-        $txn_ids = apply_filters(
339
-            'FHEE__EEM_Transaction__delete_junk_transactions__transaction_ids_to_delete',
340
-            EEM_Transaction::instance()->get_col($ids_query, 'TXN_ID'),
341
-            $time_to_leave_alone
342
-        );
343
-        //now that we have the ids to delete
344
-        if (! empty($txn_ids) && is_array($txn_ids)) {
345
-            // first, make sure these TXN's are removed the "ee_locked_transactions" array
346
-            EEM_Transaction::unset_locked_transactions($txn_ids);
347
-            // let's get deletin'...
348
-            // Why no wpdb->prepare?  Because the data is trusted.
349
-            // We got the ids from the original query to get them FROM
350
-            // the db (which is sanitized) so no need to prepare them again.
351
-            $query   = '
238
+			OBJECT
239
+		);
240
+	}
241
+
242
+
243
+	/**
244
+	 * Gets the current transaction given the reg_url_link, or assumes the reg_url_link is in the
245
+	 * $_REQUEST global variable. Either way, tries to find the current transaction (through
246
+	 * the registration pointed to by reg_url_link), if not returns null
247
+	 *
248
+	 * @param string $reg_url_link
249
+	 *
250
+	 * @return EE_Transaction
251
+	 */
252
+	public function get_transaction_from_reg_url_link($reg_url_link = '')
253
+	{
254
+		return $this->get_one(array(
255
+			array(
256
+				'Registration.REG_url_link' => ! empty($reg_url_link) ? $reg_url_link : EE_Registry::instance()->REQ->get('e_reg_url_link',
257
+					'')
258
+			)
259
+		));
260
+	}
261
+
262
+
263
+	/**
264
+	 * Updates the provided EE_Transaction with all the applicable payments
265
+	 * (or fetch the EE_Transaction from its ID)
266
+	 *
267
+	 * @deprecated
268
+	 *
269
+	 * @param EE_Transaction|int $transaction_obj_or_id
270
+	 * @param boolean            $save_txn whether or not to save the transaction during this function call
271
+	 *
272
+	 * @return boolean
273
+	 * @throws \EE_Error
274
+	 */
275
+	public function update_based_on_payments($transaction_obj_or_id, $save_txn = true)
276
+	{
277
+		EE_Error::doing_it_wrong(
278
+			__CLASS__ . '::' . __FUNCTION__,
279
+			sprintf(__('This method is deprecated. Please use "%s" instead', 'event_espresso'),
280
+				'EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()'),
281
+			'4.6.0'
282
+		);
283
+		/** @type EE_Transaction_Processor $transaction_processor */
284
+		$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
285
+
286
+		return $transaction_processor->update_transaction_and_registrations_after_checkout_or_payment(
287
+			$this->ensure_is_obj($transaction_obj_or_id)
288
+		);
289
+	}
290
+
291
+	/**
292
+	 * Deletes "junk" transactions that were probably added by bots. There might be TONS
293
+	 * of these, so we are very careful to NOT select (which the models do even when deleting),
294
+	 * and so we only use wpdb directly and only do minimal joins.
295
+	 * Transactions are considered "junk" if they're failed for longer than a week.
296
+	 * Also, there is an extra check for payments related to the transaction, because if a transaction has a payment on
297
+	 * it, it's probably not junk (regardless of what status it has).
298
+	 * The downside to this approach is that is addons are listening for object deletions
299
+	 * on EEM_Base::delete() they won't be notified of this.  However, there is an action that plugins can hook into
300
+	 * to catch these types of deletions.
301
+	 *
302
+	 * @global WPDB $wpdb
303
+	 * @return mixed
304
+	 */
305
+	public function delete_junk_transactions()
306
+	{
307
+		/** @type WPDB $wpdb */
308
+		global $wpdb;
309
+		$deleted             = false;
310
+		$time_to_leave_alone = apply_filters(
311
+			'FHEE__EEM_Transaction__delete_junk_transactions__time_to_leave_alone'
312
+			, WEEK_IN_SECONDS
313
+		);
314
+
315
+
316
+		/**
317
+		 * This allows code to filter the query arguments used for retrieving the transaction IDs to delete.
318
+		 * Useful for plugins that want to exclude transactions matching certain query parameters.
319
+		 * The query parameters should be in the format accepted by the EEM_Base model queries.
320
+		 */
321
+		$ids_query = apply_filters(
322
+			'FHEE__EEM_Transaction__delete_junk_transactions__initial_query_args',
323
+			array(
324
+				0 => array(
325
+					'STS_ID'        => EEM_Transaction::failed_status_code,
326
+					'Payment.PAY_ID' => array( 'IS NULL' ),
327
+					'TXN_timestamp' => array('<', time() - $time_to_leave_alone)
328
+				)
329
+			),
330
+			$time_to_leave_alone
331
+		);
332
+
333
+
334
+		/**
335
+		 * This filter is for when code needs to filter the list of transaction ids that represent transactions
336
+		 * about to be deleted based on some other criteria that isn't easily done via the query args filter.
337
+		 */
338
+		$txn_ids = apply_filters(
339
+			'FHEE__EEM_Transaction__delete_junk_transactions__transaction_ids_to_delete',
340
+			EEM_Transaction::instance()->get_col($ids_query, 'TXN_ID'),
341
+			$time_to_leave_alone
342
+		);
343
+		//now that we have the ids to delete
344
+		if (! empty($txn_ids) && is_array($txn_ids)) {
345
+			// first, make sure these TXN's are removed the "ee_locked_transactions" array
346
+			EEM_Transaction::unset_locked_transactions($txn_ids);
347
+			// let's get deletin'...
348
+			// Why no wpdb->prepare?  Because the data is trusted.
349
+			// We got the ids from the original query to get them FROM
350
+			// the db (which is sanitized) so no need to prepare them again.
351
+			$query   = '
352 352
 				DELETE
353 353
 				FROM ' . $this->table() . '
354 354
 				WHERE
355 355
 					TXN_ID IN ( ' . implode(",", $txn_ids) . ')';
356
-            $deleted = $wpdb->query($query);
357
-        }
358
-        if ($deleted) {
359
-            /**
360
-             * Allows code to do something after the transactions have been deleted.
361
-             */
362
-            do_action('AHEE__EEM_Transaction__delete_junk_transactions__successful_deletion', $txn_ids);
363
-        }
364
-
365
-        return $deleted;
366
-    }
367
-
368
-
369
-    /**
370
-     * @param array $transaction_IDs
371
-     *
372
-     * @return bool
373
-     */
374
-    public static function unset_locked_transactions(array $transaction_IDs)
375
-    {
376
-        $locked_transactions = get_option('ee_locked_transactions', array());
377
-        $update              = false;
378
-        foreach ($transaction_IDs as $TXN_ID) {
379
-            if (isset($locked_transactions[$TXN_ID])) {
380
-                unset($locked_transactions[$TXN_ID]);
381
-                $update = true;
382
-            }
383
-        }
384
-        if ($update) {
385
-            update_option('ee_locked_transactions', $locked_transactions);
386
-        }
387
-
388
-        return $update;
389
-    }
390
-
391
-
392
-
393
-    /**
394
-     * returns an array of EE_Transaction objects whose timestamp is greater than
395
-     * the current time minus the session lifespan, which defaults to 60 minutes
396
-     *
397
-     * @return EE_Base_Class[]|EE_Transaction[]
398
-     * @throws EE_Error
399
-     * @throws InvalidArgumentException
400
-     * @throws InvalidDataTypeException
401
-     * @throws InvalidInterfaceException
402
-     */
403
-    public function get_transactions_in_progress()
404
-    {
405
-        return $this->_get_transactions_in_progress();
406
-    }
407
-
408
-
409
-
410
-    /**
411
-     * returns an array of EE_Transaction objects whose timestamp is less than
412
-     * the current time minus the session lifespan, which defaults to 60 minutes
413
-     *
414
-     * @return EE_Base_Class[]|EE_Transaction[]
415
-     * @throws EE_Error
416
-     * @throws InvalidArgumentException
417
-     * @throws InvalidDataTypeException
418
-     * @throws InvalidInterfaceException
419
-     */
420
-    public function get_transactions_not_in_progress()
421
-    {
422
-        return $this->_get_transactions_in_progress('<=');
423
-    }
424
-
425
-
426
-
427
-    /**
428
-     * @param string $comparison
429
-     * @return EE_Base_Class[]|EE_Transaction[]
430
-     * @throws EE_Error
431
-     * @throws InvalidArgumentException
432
-     * @throws InvalidDataTypeException
433
-     * @throws InvalidInterfaceException
434
-     */
435
-    private function _get_transactions_in_progress($comparison = '>=')
436
-    {
437
-        $comparison = $comparison === '>=' || $comparison === '<='
438
-            ? $comparison
439
-            : '>=';
440
-        /** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */
441
-        $session_lifespan = LoaderFactory::getLoader()->getShared(
442
-            'EventEspresso\core\domain\values\session\SessionLifespan'
443
-        );
444
-        return $this->get_all(
445
-            array(
446
-                array(
447
-                    'TXN_timestamp' => array(
448
-                        $comparison,
449
-                        $session_lifespan->expiration()
450
-                    ),
451
-                    'STS_ID' => array(
452
-                        '!=',
453
-                        EEM_Transaction::complete_status_code
454
-                    ),
455
-                )
456
-            )
457
-        );
458
-    }
356
+			$deleted = $wpdb->query($query);
357
+		}
358
+		if ($deleted) {
359
+			/**
360
+			 * Allows code to do something after the transactions have been deleted.
361
+			 */
362
+			do_action('AHEE__EEM_Transaction__delete_junk_transactions__successful_deletion', $txn_ids);
363
+		}
364
+
365
+		return $deleted;
366
+	}
367
+
368
+
369
+	/**
370
+	 * @param array $transaction_IDs
371
+	 *
372
+	 * @return bool
373
+	 */
374
+	public static function unset_locked_transactions(array $transaction_IDs)
375
+	{
376
+		$locked_transactions = get_option('ee_locked_transactions', array());
377
+		$update              = false;
378
+		foreach ($transaction_IDs as $TXN_ID) {
379
+			if (isset($locked_transactions[$TXN_ID])) {
380
+				unset($locked_transactions[$TXN_ID]);
381
+				$update = true;
382
+			}
383
+		}
384
+		if ($update) {
385
+			update_option('ee_locked_transactions', $locked_transactions);
386
+		}
387
+
388
+		return $update;
389
+	}
390
+
391
+
392
+
393
+	/**
394
+	 * returns an array of EE_Transaction objects whose timestamp is greater than
395
+	 * the current time minus the session lifespan, which defaults to 60 minutes
396
+	 *
397
+	 * @return EE_Base_Class[]|EE_Transaction[]
398
+	 * @throws EE_Error
399
+	 * @throws InvalidArgumentException
400
+	 * @throws InvalidDataTypeException
401
+	 * @throws InvalidInterfaceException
402
+	 */
403
+	public function get_transactions_in_progress()
404
+	{
405
+		return $this->_get_transactions_in_progress();
406
+	}
407
+
408
+
409
+
410
+	/**
411
+	 * returns an array of EE_Transaction objects whose timestamp is less than
412
+	 * the current time minus the session lifespan, which defaults to 60 minutes
413
+	 *
414
+	 * @return EE_Base_Class[]|EE_Transaction[]
415
+	 * @throws EE_Error
416
+	 * @throws InvalidArgumentException
417
+	 * @throws InvalidDataTypeException
418
+	 * @throws InvalidInterfaceException
419
+	 */
420
+	public function get_transactions_not_in_progress()
421
+	{
422
+		return $this->_get_transactions_in_progress('<=');
423
+	}
424
+
425
+
426
+
427
+	/**
428
+	 * @param string $comparison
429
+	 * @return EE_Base_Class[]|EE_Transaction[]
430
+	 * @throws EE_Error
431
+	 * @throws InvalidArgumentException
432
+	 * @throws InvalidDataTypeException
433
+	 * @throws InvalidInterfaceException
434
+	 */
435
+	private function _get_transactions_in_progress($comparison = '>=')
436
+	{
437
+		$comparison = $comparison === '>=' || $comparison === '<='
438
+			? $comparison
439
+			: '>=';
440
+		/** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */
441
+		$session_lifespan = LoaderFactory::getLoader()->getShared(
442
+			'EventEspresso\core\domain\values\session\SessionLifespan'
443
+		);
444
+		return $this->get_all(
445
+			array(
446
+				array(
447
+					'TXN_timestamp' => array(
448
+						$comparison,
449
+						$session_lifespan->expiration()
450
+					),
451
+					'STS_ID' => array(
452
+						'!=',
453
+						EEM_Transaction::complete_status_code
454
+					),
455
+				)
456
+			)
457
+		);
458
+	}
459 459
 
460 460
 
461 461
 }
Please login to merge, or discard this patch.
core/db_models/EEM_Line_Item.model.php 3 patches
Indentation   +382 added lines, -382 removed lines patch added patch discarded remove patch
@@ -47,391 +47,391 @@
 block discarded – undo
47 47
 class EEM_Line_Item extends EEM_Base
48 48
 {
49 49
 
50
-    /**
51
-     * Tax sub-total is just the total of all the taxes, which should be children
52
-     * of this line item. There should only ever be one tax sub-total, and it should
53
-     * be a direct child of
54
-     */
55
-    const type_tax_sub_total = 'tax-sub-total';
56
-
57
-    /**
58
-     * Tax line items indicate a tax applied to all the taxable line items.
59
-     * Should not have any children line items.
60
-     */
61
-    const type_tax = 'tax';
62
-
63
-    /**
64
-     * Indicating individual items purchased, or discounts or surcharges.
65
-     * The sum of all the regular line items  plus the tax items should equal
66
-     * the grand total.
67
-     * Possible children fo sub-line-items and cancellations.
68
-     */
69
-    const type_line_item = 'line-item';
70
-
71
-    /**
72
-     * line item indicating all the factors that make a single line item.
73
-     * Sub-line items should have NO children line items.
74
-     */
75
-    const type_sub_line_item = 'sub-item';
76
-
77
-    /**
78
-     * line item indicating a sub-total (eg total for an event, or before taxes).
79
-     * Direct children can be line items and other sub-totals
80
-     *
81
-     */
82
-    const type_sub_total = 'sub-total';
83
-
84
-    /**
85
-     * line item for teh grand total of an order. Its direct children
86
-     * should be tax subtotals and subtotals, and possibly a regular line item
87
-     * indicating a transaction-wide discount/surcharge
88
-     */
89
-    const type_total = 'total';
90
-
91
-    /**
92
-     * When a line item is cancelled, a sub-line-item of type 'cancellation'
93
-     * should be created, indicating the quantity that were cancelled
94
-     * (because a line item could have a quantity of 1, and its cancellation item
95
-     * could be for 3, indicating that originally 4 were purchased, but 3 have been
96
-     * cancelled, and only one remains).
97
-     * When items are refunded, a cancellation line item should be made, which points
98
-     * to teh payment model object which actually refunded the payment.
99
-     * Cancellations should NOT have any children line items; the should NOT affect
100
-     * any calculations, and are only meant as a record that cancellations have occurred.
101
-     */
102
-    const type_cancellation = 'cancellation';
103
-
104
-    // private instance of the EEM_Line_Item object
105
-    protected static $_instance = NULL;
106
-
107
-
108
-    /**
109
-     *        private constructor to prevent direct creation
110
-     * @Constructor
111
-     * @access protected
112
-     * @param string $timezone string representing the timezone we want to set for returned Date Time Strings (and any incoming timezone data that gets saved).  Note this just sends the timezone info to the date time model field objects.  Default is NULL (and will be assumed using the set timezone in the 'timezone_string' wp option)
113
-     * @return \EEM_Line_Item
114
-     */
115
-    protected function __construct($timezone)
116
-    {
117
-        $this->singular_item = __('Line Item', 'event_espresso');
118
-        $this->plural_item = __('Line Items', 'event_espresso');
119
-
120
-        $this->_tables = array(
121
-            'Line_Item' => new EE_Primary_Table('esp_line_item', 'LIN_ID')
122
-        );
123
-        $line_items_can_be_for = apply_filters('FHEE__EEM_Line_Item__line_items_can_be_for', array('Ticket', 'Price', 'Event'));
124
-        $this->_fields = array(
125
-            'Line_Item' => array(
126
-                'LIN_ID' => new EE_Primary_Key_Int_Field('LIN_ID', __("ID", "event_espresso")),
127
-                'LIN_code' => new EE_Slug_Field('LIN_code', __("Code for index into Cart", "event_espresso"), TRUE),
128
-                'TXN_ID' => new EE_Foreign_Key_Int_Field('TXN_ID', __("Transaction ID", "event_espresso"), TRUE, NULL, 'Transaction'),
129
-                'LIN_name' => new EE_Full_HTML_Field('LIN_name', __("Line Item Name", "event_espresso"), FALSE, ''),
130
-                'LIN_desc' => new EE_Full_HTML_Field('LIN_desc', __("Line Item Description", "event_espresso"), TRUE),
131
-                'LIN_unit_price' => new EE_Money_Field('LIN_unit_price', __("Unit Price", "event_espresso"), FALSE, 0),
132
-                'LIN_percent' => new EE_Float_Field('LIN_percent', __("Percent", "event_espresso"), FALSE, 0),
133
-                'LIN_is_taxable' => new EE_Boolean_Field('LIN_is_taxable', __("Taxable", "event_espresso"), FALSE, FALSE),
134
-                'LIN_order' => new EE_Integer_Field('LIN_order', __("Order of Application towards total of parent", "event_espresso"), FALSE, 1),
135
-                'LIN_total' => new EE_Money_Field('LIN_total', __("Total (unit price x quantity)", "event_espresso"), FALSE, 0),
136
-                'LIN_quantity' => new EE_Integer_Field('LIN_quantity', __("Quantity", "event_espresso"), TRUE, 1),
137
-                'LIN_parent' => new EE_Integer_Field('LIN_parent', __("Parent ID (this item goes towards that Line Item's total)", "event_espresso"), TRUE, NULL),
138
-                'LIN_type' => new EE_Enum_Text_Field('LIN_type', __("Type", "event_espresso"), FALSE, 'line-item', array(
139
-                        self::type_line_item => __("Line Item", "event_espresso"),
140
-                        self::type_sub_line_item => __("Sub-Item", "event_espresso"),
141
-                        self::type_sub_total => __("Subtotal", "event_espresso"),
142
-                        self::type_tax_sub_total => __("Tax Subtotal", "event_espresso"),
143
-                        self::type_tax => __("Tax", "event_espresso"),
144
-                        self::type_total => __("Total", "event_espresso"),
145
-                        self::type_cancellation => __('Cancellation', 'event_espresso')
146
-                    )
147
-                ),
148
-                'OBJ_ID' => new EE_Foreign_Key_Int_Field('OBJ_ID', __('ID of Item purchased.', 'event_espresso'), TRUE, NULL, $line_items_can_be_for),
149
-                'OBJ_type' => new EE_Any_Foreign_Model_Name_Field('OBJ_type', __("Model Name this Line Item is for", "event_espresso"), TRUE, NULL, $line_items_can_be_for),
150
-                'LIN_timestamp' => new EE_Datetime_Field('LIN_timestamp', __('When the line item was created', 'event_espresso'), false, EE_Datetime_Field::now, $timezone),
151
-            )
152
-        );
153
-        $this->_model_relations = array(
154
-            'Transaction' => new EE_Belongs_To_Relation(),
155
-            'Ticket' => new EE_Belongs_To_Any_Relation(),
156
-            'Price' => new EE_Belongs_To_Any_Relation(),
157
-            'Event' => new EE_Belongs_To_Any_Relation()
158
-        );
159
-        $this->_model_chain_to_wp_user = 'Transaction.Registration.Event';
160
-        $this->_caps_slug = 'transactions';
161
-        parent::__construct($timezone);
162
-    }
163
-
164
-
165
-    /**
166
-     * Gets all the line items for this transaction of the given type
167
-     * @param string $line_item_type like one of EEM_Line_Item::type_*
168
-     * @param EE_Transaction|int $transaction
169
-     * @return EE_Line_Item[]
170
-     */
171
-    public function get_all_of_type_for_transaction($line_item_type, $transaction)
172
-    {
173
-        $transaction = EEM_Transaction::instance()->ensure_is_ID($transaction);
174
-        return $this->get_all(array(array(
175
-            'LIN_type' => $line_item_type,
176
-            'TXN_ID' => $transaction
177
-        )));
178
-    }
179
-
180
-
181
-    /**
182
-     * Gets all line items unrelated to tickets that are normal line items
183
-     * (eg shipping, promotions, and miscellaneous other stuff should probably fit in this category)
184
-     * @param EE_Transaction|int $transaction
185
-     * @return EE_Line_Item[]
186
-     */
187
-    public function get_all_non_ticket_line_items_for_transaction($transaction)
188
-    {
189
-        $transaction = EEM_Transaction::instance()->ensure_is_ID($transaction);
190
-        return $this->get_all(array(array(
191
-            'LIN_type' => self::type_line_item,
192
-            'TXN_ID' => $transaction,
193
-            'OR' => array(
194
-                'OBJ_type*notticket' => array('!=', 'Ticket'),
195
-                'OBJ_type*null' => array('IS_NULL'))
196
-        )));
197
-    }
198
-
199
-    /**
200
-     * Deletes line items with no transaction who have passed the transaction cutoff time.
201
-     * This needs to be very efficient
202
-     * because if there are spam bots afoot there will be LOTS of line items
203
-     * @return int count of how many deleted
204
-     */
205
-    public function delete_line_items_with_no_transaction()
206
-    {
207
-        /** @type WPDB $wpdb */
208
-        global $wpdb;
209
-        $time_to_leave_alone = apply_filters(
210
-            'FHEE__EEM_Line_Item__delete_line_items_with_no_transaction__time_to_leave_alone', WEEK_IN_SECONDS
211
-        );
212
-        $query = $wpdb->prepare(
213
-            'DELETE li
50
+	/**
51
+	 * Tax sub-total is just the total of all the taxes, which should be children
52
+	 * of this line item. There should only ever be one tax sub-total, and it should
53
+	 * be a direct child of
54
+	 */
55
+	const type_tax_sub_total = 'tax-sub-total';
56
+
57
+	/**
58
+	 * Tax line items indicate a tax applied to all the taxable line items.
59
+	 * Should not have any children line items.
60
+	 */
61
+	const type_tax = 'tax';
62
+
63
+	/**
64
+	 * Indicating individual items purchased, or discounts or surcharges.
65
+	 * The sum of all the regular line items  plus the tax items should equal
66
+	 * the grand total.
67
+	 * Possible children fo sub-line-items and cancellations.
68
+	 */
69
+	const type_line_item = 'line-item';
70
+
71
+	/**
72
+	 * line item indicating all the factors that make a single line item.
73
+	 * Sub-line items should have NO children line items.
74
+	 */
75
+	const type_sub_line_item = 'sub-item';
76
+
77
+	/**
78
+	 * line item indicating a sub-total (eg total for an event, or before taxes).
79
+	 * Direct children can be line items and other sub-totals
80
+	 *
81
+	 */
82
+	const type_sub_total = 'sub-total';
83
+
84
+	/**
85
+	 * line item for teh grand total of an order. Its direct children
86
+	 * should be tax subtotals and subtotals, and possibly a regular line item
87
+	 * indicating a transaction-wide discount/surcharge
88
+	 */
89
+	const type_total = 'total';
90
+
91
+	/**
92
+	 * When a line item is cancelled, a sub-line-item of type 'cancellation'
93
+	 * should be created, indicating the quantity that were cancelled
94
+	 * (because a line item could have a quantity of 1, and its cancellation item
95
+	 * could be for 3, indicating that originally 4 were purchased, but 3 have been
96
+	 * cancelled, and only one remains).
97
+	 * When items are refunded, a cancellation line item should be made, which points
98
+	 * to teh payment model object which actually refunded the payment.
99
+	 * Cancellations should NOT have any children line items; the should NOT affect
100
+	 * any calculations, and are only meant as a record that cancellations have occurred.
101
+	 */
102
+	const type_cancellation = 'cancellation';
103
+
104
+	// private instance of the EEM_Line_Item object
105
+	protected static $_instance = NULL;
106
+
107
+
108
+	/**
109
+	 *        private constructor to prevent direct creation
110
+	 * @Constructor
111
+	 * @access protected
112
+	 * @param string $timezone string representing the timezone we want to set for returned Date Time Strings (and any incoming timezone data that gets saved).  Note this just sends the timezone info to the date time model field objects.  Default is NULL (and will be assumed using the set timezone in the 'timezone_string' wp option)
113
+	 * @return \EEM_Line_Item
114
+	 */
115
+	protected function __construct($timezone)
116
+	{
117
+		$this->singular_item = __('Line Item', 'event_espresso');
118
+		$this->plural_item = __('Line Items', 'event_espresso');
119
+
120
+		$this->_tables = array(
121
+			'Line_Item' => new EE_Primary_Table('esp_line_item', 'LIN_ID')
122
+		);
123
+		$line_items_can_be_for = apply_filters('FHEE__EEM_Line_Item__line_items_can_be_for', array('Ticket', 'Price', 'Event'));
124
+		$this->_fields = array(
125
+			'Line_Item' => array(
126
+				'LIN_ID' => new EE_Primary_Key_Int_Field('LIN_ID', __("ID", "event_espresso")),
127
+				'LIN_code' => new EE_Slug_Field('LIN_code', __("Code for index into Cart", "event_espresso"), TRUE),
128
+				'TXN_ID' => new EE_Foreign_Key_Int_Field('TXN_ID', __("Transaction ID", "event_espresso"), TRUE, NULL, 'Transaction'),
129
+				'LIN_name' => new EE_Full_HTML_Field('LIN_name', __("Line Item Name", "event_espresso"), FALSE, ''),
130
+				'LIN_desc' => new EE_Full_HTML_Field('LIN_desc', __("Line Item Description", "event_espresso"), TRUE),
131
+				'LIN_unit_price' => new EE_Money_Field('LIN_unit_price', __("Unit Price", "event_espresso"), FALSE, 0),
132
+				'LIN_percent' => new EE_Float_Field('LIN_percent', __("Percent", "event_espresso"), FALSE, 0),
133
+				'LIN_is_taxable' => new EE_Boolean_Field('LIN_is_taxable', __("Taxable", "event_espresso"), FALSE, FALSE),
134
+				'LIN_order' => new EE_Integer_Field('LIN_order', __("Order of Application towards total of parent", "event_espresso"), FALSE, 1),
135
+				'LIN_total' => new EE_Money_Field('LIN_total', __("Total (unit price x quantity)", "event_espresso"), FALSE, 0),
136
+				'LIN_quantity' => new EE_Integer_Field('LIN_quantity', __("Quantity", "event_espresso"), TRUE, 1),
137
+				'LIN_parent' => new EE_Integer_Field('LIN_parent', __("Parent ID (this item goes towards that Line Item's total)", "event_espresso"), TRUE, NULL),
138
+				'LIN_type' => new EE_Enum_Text_Field('LIN_type', __("Type", "event_espresso"), FALSE, 'line-item', array(
139
+						self::type_line_item => __("Line Item", "event_espresso"),
140
+						self::type_sub_line_item => __("Sub-Item", "event_espresso"),
141
+						self::type_sub_total => __("Subtotal", "event_espresso"),
142
+						self::type_tax_sub_total => __("Tax Subtotal", "event_espresso"),
143
+						self::type_tax => __("Tax", "event_espresso"),
144
+						self::type_total => __("Total", "event_espresso"),
145
+						self::type_cancellation => __('Cancellation', 'event_espresso')
146
+					)
147
+				),
148
+				'OBJ_ID' => new EE_Foreign_Key_Int_Field('OBJ_ID', __('ID of Item purchased.', 'event_espresso'), TRUE, NULL, $line_items_can_be_for),
149
+				'OBJ_type' => new EE_Any_Foreign_Model_Name_Field('OBJ_type', __("Model Name this Line Item is for", "event_espresso"), TRUE, NULL, $line_items_can_be_for),
150
+				'LIN_timestamp' => new EE_Datetime_Field('LIN_timestamp', __('When the line item was created', 'event_espresso'), false, EE_Datetime_Field::now, $timezone),
151
+			)
152
+		);
153
+		$this->_model_relations = array(
154
+			'Transaction' => new EE_Belongs_To_Relation(),
155
+			'Ticket' => new EE_Belongs_To_Any_Relation(),
156
+			'Price' => new EE_Belongs_To_Any_Relation(),
157
+			'Event' => new EE_Belongs_To_Any_Relation()
158
+		);
159
+		$this->_model_chain_to_wp_user = 'Transaction.Registration.Event';
160
+		$this->_caps_slug = 'transactions';
161
+		parent::__construct($timezone);
162
+	}
163
+
164
+
165
+	/**
166
+	 * Gets all the line items for this transaction of the given type
167
+	 * @param string $line_item_type like one of EEM_Line_Item::type_*
168
+	 * @param EE_Transaction|int $transaction
169
+	 * @return EE_Line_Item[]
170
+	 */
171
+	public function get_all_of_type_for_transaction($line_item_type, $transaction)
172
+	{
173
+		$transaction = EEM_Transaction::instance()->ensure_is_ID($transaction);
174
+		return $this->get_all(array(array(
175
+			'LIN_type' => $line_item_type,
176
+			'TXN_ID' => $transaction
177
+		)));
178
+	}
179
+
180
+
181
+	/**
182
+	 * Gets all line items unrelated to tickets that are normal line items
183
+	 * (eg shipping, promotions, and miscellaneous other stuff should probably fit in this category)
184
+	 * @param EE_Transaction|int $transaction
185
+	 * @return EE_Line_Item[]
186
+	 */
187
+	public function get_all_non_ticket_line_items_for_transaction($transaction)
188
+	{
189
+		$transaction = EEM_Transaction::instance()->ensure_is_ID($transaction);
190
+		return $this->get_all(array(array(
191
+			'LIN_type' => self::type_line_item,
192
+			'TXN_ID' => $transaction,
193
+			'OR' => array(
194
+				'OBJ_type*notticket' => array('!=', 'Ticket'),
195
+				'OBJ_type*null' => array('IS_NULL'))
196
+		)));
197
+	}
198
+
199
+	/**
200
+	 * Deletes line items with no transaction who have passed the transaction cutoff time.
201
+	 * This needs to be very efficient
202
+	 * because if there are spam bots afoot there will be LOTS of line items
203
+	 * @return int count of how many deleted
204
+	 */
205
+	public function delete_line_items_with_no_transaction()
206
+	{
207
+		/** @type WPDB $wpdb */
208
+		global $wpdb;
209
+		$time_to_leave_alone = apply_filters(
210
+			'FHEE__EEM_Line_Item__delete_line_items_with_no_transaction__time_to_leave_alone', WEEK_IN_SECONDS
211
+		);
212
+		$query = $wpdb->prepare(
213
+			'DELETE li
214 214
 				FROM ' . $this->table() . ' li
215 215
 				LEFT JOIN ' . EEM_Transaction::instance()->table() . ' t ON li.TXN_ID = t.TXN_ID
216 216
 				WHERE t.TXN_ID IS NULL AND li.LIN_timestamp < %s',
217
-            // use GMT time because that's what TXN_timestamps are in
218
-            date('Y-m-d H:i:s', time() - $time_to_leave_alone)
219
-        );
220
-        return $wpdb->query($query);
221
-    }
222
-
223
-
224
-    /**
225
-     * get_line_item_for_transaction_object
226
-     * Gets a transaction's line item record for a specific object such as a EE_Event or EE_Ticket
227
-     *
228
-     * @param int $TXN_ID
229
-     * @param \EE_Base_Class $object
230
-     * @return EE_Line_Item[]
231
-     */
232
-    public function get_line_item_for_transaction_object($TXN_ID, EE_Base_Class $object)
233
-    {
234
-        return $this->get_all(array(array(
235
-            'TXN_ID' => $TXN_ID,
236
-            'OBJ_type' => str_replace('EE_', '', get_class($object)),
237
-            'OBJ_ID' => $object->ID()
238
-        )));
239
-    }
240
-
241
-
242
-    /**
243
-     * get_object_line_items_for_transaction
244
-     * Gets all of the the object line items for a transaction, based on an object type plus an array of object IDs
245
-     *
246
-     * @param int $TXN_ID
247
-     * @param string $OBJ_type
248
-     * @param array $OBJ_IDs
249
-     * @return EE_Line_Item[]
250
-     */
251
-    public function get_object_line_items_for_transaction($TXN_ID, $OBJ_type = 'Event', $OBJ_IDs = array())
252
-    {
253
-        $query_params = array(
254
-            'OBJ_type' => $OBJ_type,
255
-            // if incoming $OBJ_IDs is an array, then make sure it is formatted correctly for the query
256
-            'OBJ_ID' => is_array($OBJ_IDs) && !isset($OBJ_IDs['IN']) ? array('IN', $OBJ_IDs) : $OBJ_IDs
257
-        );
258
-        if ($TXN_ID) {
259
-            $query_params['TXN_ID'] = $TXN_ID;
260
-        }
261
-        return $this->get_all(array($query_params));
262
-    }
263
-
264
-
265
-    /**
266
-     * get_all_ticket_line_items_for_transaction
267
-     *
268
-     * @param EE_Transaction $transaction
269
-     * @return EE_Line_Item[]
270
-     */
271
-    public function get_all_ticket_line_items_for_transaction(EE_Transaction $transaction)
272
-    {
273
-        return $this->get_all(array(
274
-            array(
275
-                'TXN_ID' => $transaction->ID(),
276
-                'OBJ_type' => 'Ticket',
277
-            )
278
-        ));
279
-    }
280
-
281
-
282
-    /**
283
-     * get_ticket_line_item_for_transaction
284
-     *
285
-     * @param int $TXN_ID
286
-     * @param int $TKT_ID
287
-     * @return \EE_Line_Item
288
-     */
289
-    public function get_ticket_line_item_for_transaction($TXN_ID, $TKT_ID)
290
-    {
291
-        return $this->get_one(array(
292
-            array(
293
-                'TXN_ID' => EEM_Transaction::instance()->ensure_is_ID($TXN_ID),
294
-                'OBJ_ID' => $TKT_ID,
295
-                'OBJ_type' => 'Ticket',
296
-            )
297
-        ));
298
-    }
299
-
300
-
301
-    /**
302
-     * get_existing_promotion_line_item
303
-     * searches the cart for existing line items for the specified promotion
304
-     *
305
-     * @since   1.0.0
306
-     *
307
-     * @param EE_Line_Item $parent_line_item
308
-     * @param EE_Promotion $promotion
309
-     * @return EE_Line_Item
310
-     */
311
-    public function get_existing_promotion_line_item(EE_Line_Item $parent_line_item, EE_Promotion $promotion)
312
-    {
313
-        return $this->get_one(array(
314
-            array(
315
-                'TXN_ID' => $parent_line_item->TXN_ID(),
316
-                'LIN_parent' => $parent_line_item->ID(),
317
-                'OBJ_type' => 'Promotion',
318
-                'OBJ_ID' => $promotion->ID()
319
-            )
320
-        ));
321
-    }
322
-
323
-
324
-    /**
325
-     * get_all_promotion_line_items
326
-     * searches the cart for any and all existing promotion line items
327
-     *
328
-     * @since   1.0.0
329
-     *
330
-     * @param EE_Line_Item $parent_line_item
331
-     * @return EE_Line_Item[]
332
-     */
333
-    public function get_all_promotion_line_items(EE_Line_Item $parent_line_item)
334
-    {
335
-        return $this->get_all(array(
336
-            array(
337
-                'TXN_ID' => $parent_line_item->TXN_ID(),
338
-                'LIN_parent' => $parent_line_item->ID(),
339
-                'OBJ_type' => 'Promotion'
340
-            )
341
-        ));
342
-    }
343
-
344
-    /**
345
-     * Gets the registration's corresponding line item.
346
-     * Note: basically does NOT support having multiple line items for a single ticket,
347
-     * which would happen if some of the registrations had a price modifier while others didn't.
348
-     * In order to support that, we'd probably need a LIN_ID on registrations or something.
349
-     * @param EE_Registration $registration
350
-     * @return EE_Line_ITem
351
-     */
352
-    public function get_line_item_for_registration(EE_Registration $registration)
353
-    {
354
-        return $this->get_one($this->line_item_for_registration_query_params($registration));
355
-    }
356
-
357
-    /**
358
-     * Gets the query params used to retrieve a specific line item for the given registration
359
-     * @param EE_Registration $registration
360
-     * @param array $original_query_params any extra query params you'd like to be merged with
361
-     * @return array like EEM_Base::get_all()'s $query_params
362
-     */
363
-    public function line_item_for_registration_query_params(EE_Registration $registration, $original_query_params = array())
364
-    {
365
-        return array_replace_recursive($original_query_params, array(
366
-            array(
367
-                'OBJ_ID' => $registration->ticket_ID(),
368
-                'OBJ_type' => 'Ticket',
369
-                'TXN_ID' => $registration->transaction_ID()
370
-            )
371
-        ));
372
-    }
373
-
374
-
375
-    /**
376
-     * @return EE_Base_Class[]|EE_Line_Item[]
377
-     * @throws EE_Error
378
-     */
379
-    public function get_total_line_items_with_no_transaction()
380
-    {
381
-        return $this->get_total_line_items_for_carts();
382
-    }
383
-
384
-
385
-    /**
386
-     * @return EE_Base_Class[]|EE_Line_Item[]
387
-     * @throws EE_Error
388
-     */
389
-    public function get_total_line_items_for_active_carts()
390
-    {
391
-        return $this->get_total_line_items_for_carts(false);
392
-    }
393
-
394
-
395
-    /**
396
-     * @return EE_Base_Class[]|EE_Line_Item[]
397
-     * @throws EE_Error
398
-     */
399
-    public function get_total_line_items_for_expired_carts()
400
-    {
401
-        return $this->get_total_line_items_for_carts(true);
402
-    }
403
-
404
-
405
-    /**
406
-     * Returns an array of grand total line items where the TXN_ID is 0.
407
-     * If $expired is set to true, then only line items for expired sessions will be returned.
408
-     * If $expired is set to false, then only line items for active sessions will be returned.
409
-     *
410
-     * @param bool|null $expired
411
-     * @return EE_Base_Class[]|EE_Line_Item[]
412
-     * @throws InvalidInterfaceException
413
-     * @throws InvalidDataTypeException
414
-     * @throws EE_Error
415
-     * @throws InvalidArgumentException
416
-     */
417
-    private function get_total_line_items_for_carts($expired = null)
418
-    {
419
-        $where_params = array(
420
-            'TXN_ID' => 0,
421
-            'LIN_type' => 'total',
422
-        );
423
-        if ($expired !== null) {
424
-            /** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */
425
-            $session_lifespan = LoaderFactory::getLoader()->getShared(
426
-                'EventEspresso\core\domain\values\session\SessionLifespan'
427
-            );
428
-            $where_params['LIN_timestamp'] = array(
429
-                $expired ? '<=' : '>',
430
-                $session_lifespan->expiration(),
431
-            );
432
-        }
433
-        return $this->get_all(array($where_params));
434
-    }
217
+			// use GMT time because that's what TXN_timestamps are in
218
+			date('Y-m-d H:i:s', time() - $time_to_leave_alone)
219
+		);
220
+		return $wpdb->query($query);
221
+	}
222
+
223
+
224
+	/**
225
+	 * get_line_item_for_transaction_object
226
+	 * Gets a transaction's line item record for a specific object such as a EE_Event or EE_Ticket
227
+	 *
228
+	 * @param int $TXN_ID
229
+	 * @param \EE_Base_Class $object
230
+	 * @return EE_Line_Item[]
231
+	 */
232
+	public function get_line_item_for_transaction_object($TXN_ID, EE_Base_Class $object)
233
+	{
234
+		return $this->get_all(array(array(
235
+			'TXN_ID' => $TXN_ID,
236
+			'OBJ_type' => str_replace('EE_', '', get_class($object)),
237
+			'OBJ_ID' => $object->ID()
238
+		)));
239
+	}
240
+
241
+
242
+	/**
243
+	 * get_object_line_items_for_transaction
244
+	 * Gets all of the the object line items for a transaction, based on an object type plus an array of object IDs
245
+	 *
246
+	 * @param int $TXN_ID
247
+	 * @param string $OBJ_type
248
+	 * @param array $OBJ_IDs
249
+	 * @return EE_Line_Item[]
250
+	 */
251
+	public function get_object_line_items_for_transaction($TXN_ID, $OBJ_type = 'Event', $OBJ_IDs = array())
252
+	{
253
+		$query_params = array(
254
+			'OBJ_type' => $OBJ_type,
255
+			// if incoming $OBJ_IDs is an array, then make sure it is formatted correctly for the query
256
+			'OBJ_ID' => is_array($OBJ_IDs) && !isset($OBJ_IDs['IN']) ? array('IN', $OBJ_IDs) : $OBJ_IDs
257
+		);
258
+		if ($TXN_ID) {
259
+			$query_params['TXN_ID'] = $TXN_ID;
260
+		}
261
+		return $this->get_all(array($query_params));
262
+	}
263
+
264
+
265
+	/**
266
+	 * get_all_ticket_line_items_for_transaction
267
+	 *
268
+	 * @param EE_Transaction $transaction
269
+	 * @return EE_Line_Item[]
270
+	 */
271
+	public function get_all_ticket_line_items_for_transaction(EE_Transaction $transaction)
272
+	{
273
+		return $this->get_all(array(
274
+			array(
275
+				'TXN_ID' => $transaction->ID(),
276
+				'OBJ_type' => 'Ticket',
277
+			)
278
+		));
279
+	}
280
+
281
+
282
+	/**
283
+	 * get_ticket_line_item_for_transaction
284
+	 *
285
+	 * @param int $TXN_ID
286
+	 * @param int $TKT_ID
287
+	 * @return \EE_Line_Item
288
+	 */
289
+	public function get_ticket_line_item_for_transaction($TXN_ID, $TKT_ID)
290
+	{
291
+		return $this->get_one(array(
292
+			array(
293
+				'TXN_ID' => EEM_Transaction::instance()->ensure_is_ID($TXN_ID),
294
+				'OBJ_ID' => $TKT_ID,
295
+				'OBJ_type' => 'Ticket',
296
+			)
297
+		));
298
+	}
299
+
300
+
301
+	/**
302
+	 * get_existing_promotion_line_item
303
+	 * searches the cart for existing line items for the specified promotion
304
+	 *
305
+	 * @since   1.0.0
306
+	 *
307
+	 * @param EE_Line_Item $parent_line_item
308
+	 * @param EE_Promotion $promotion
309
+	 * @return EE_Line_Item
310
+	 */
311
+	public function get_existing_promotion_line_item(EE_Line_Item $parent_line_item, EE_Promotion $promotion)
312
+	{
313
+		return $this->get_one(array(
314
+			array(
315
+				'TXN_ID' => $parent_line_item->TXN_ID(),
316
+				'LIN_parent' => $parent_line_item->ID(),
317
+				'OBJ_type' => 'Promotion',
318
+				'OBJ_ID' => $promotion->ID()
319
+			)
320
+		));
321
+	}
322
+
323
+
324
+	/**
325
+	 * get_all_promotion_line_items
326
+	 * searches the cart for any and all existing promotion line items
327
+	 *
328
+	 * @since   1.0.0
329
+	 *
330
+	 * @param EE_Line_Item $parent_line_item
331
+	 * @return EE_Line_Item[]
332
+	 */
333
+	public function get_all_promotion_line_items(EE_Line_Item $parent_line_item)
334
+	{
335
+		return $this->get_all(array(
336
+			array(
337
+				'TXN_ID' => $parent_line_item->TXN_ID(),
338
+				'LIN_parent' => $parent_line_item->ID(),
339
+				'OBJ_type' => 'Promotion'
340
+			)
341
+		));
342
+	}
343
+
344
+	/**
345
+	 * Gets the registration's corresponding line item.
346
+	 * Note: basically does NOT support having multiple line items for a single ticket,
347
+	 * which would happen if some of the registrations had a price modifier while others didn't.
348
+	 * In order to support that, we'd probably need a LIN_ID on registrations or something.
349
+	 * @param EE_Registration $registration
350
+	 * @return EE_Line_ITem
351
+	 */
352
+	public function get_line_item_for_registration(EE_Registration $registration)
353
+	{
354
+		return $this->get_one($this->line_item_for_registration_query_params($registration));
355
+	}
356
+
357
+	/**
358
+	 * Gets the query params used to retrieve a specific line item for the given registration
359
+	 * @param EE_Registration $registration
360
+	 * @param array $original_query_params any extra query params you'd like to be merged with
361
+	 * @return array like EEM_Base::get_all()'s $query_params
362
+	 */
363
+	public function line_item_for_registration_query_params(EE_Registration $registration, $original_query_params = array())
364
+	{
365
+		return array_replace_recursive($original_query_params, array(
366
+			array(
367
+				'OBJ_ID' => $registration->ticket_ID(),
368
+				'OBJ_type' => 'Ticket',
369
+				'TXN_ID' => $registration->transaction_ID()
370
+			)
371
+		));
372
+	}
373
+
374
+
375
+	/**
376
+	 * @return EE_Base_Class[]|EE_Line_Item[]
377
+	 * @throws EE_Error
378
+	 */
379
+	public function get_total_line_items_with_no_transaction()
380
+	{
381
+		return $this->get_total_line_items_for_carts();
382
+	}
383
+
384
+
385
+	/**
386
+	 * @return EE_Base_Class[]|EE_Line_Item[]
387
+	 * @throws EE_Error
388
+	 */
389
+	public function get_total_line_items_for_active_carts()
390
+	{
391
+		return $this->get_total_line_items_for_carts(false);
392
+	}
393
+
394
+
395
+	/**
396
+	 * @return EE_Base_Class[]|EE_Line_Item[]
397
+	 * @throws EE_Error
398
+	 */
399
+	public function get_total_line_items_for_expired_carts()
400
+	{
401
+		return $this->get_total_line_items_for_carts(true);
402
+	}
403
+
404
+
405
+	/**
406
+	 * Returns an array of grand total line items where the TXN_ID is 0.
407
+	 * If $expired is set to true, then only line items for expired sessions will be returned.
408
+	 * If $expired is set to false, then only line items for active sessions will be returned.
409
+	 *
410
+	 * @param bool|null $expired
411
+	 * @return EE_Base_Class[]|EE_Line_Item[]
412
+	 * @throws InvalidInterfaceException
413
+	 * @throws InvalidDataTypeException
414
+	 * @throws EE_Error
415
+	 * @throws InvalidArgumentException
416
+	 */
417
+	private function get_total_line_items_for_carts($expired = null)
418
+	{
419
+		$where_params = array(
420
+			'TXN_ID' => 0,
421
+			'LIN_type' => 'total',
422
+		);
423
+		if ($expired !== null) {
424
+			/** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */
425
+			$session_lifespan = LoaderFactory::getLoader()->getShared(
426
+				'EventEspresso\core\domain\values\session\SessionLifespan'
427
+			);
428
+			$where_params['LIN_timestamp'] = array(
429
+				$expired ? '<=' : '>',
430
+				$session_lifespan->expiration(),
431
+			);
432
+		}
433
+		return $this->get_all(array($where_params));
434
+	}
435 435
 
436 436
 
437 437
 }
Please login to merge, or discard this patch.
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -4,7 +4,7 @@  discard block
 block discarded – undo
4 4
 use EventEspresso\core\exceptions\InvalidInterfaceException;
5 5
 use EventEspresso\core\services\loaders\LoaderFactory;
6 6
 
7
-if (!defined('EVENT_ESPRESSO_VERSION')) exit('No direct script access allowed');
7
+if ( ! defined('EVENT_ESPRESSO_VERSION')) exit('No direct script access allowed');
8 8
 
9 9
 /**
10 10
  * Event Espresso
@@ -211,8 +211,8 @@  discard block
 block discarded – undo
211 211
         );
212 212
         $query = $wpdb->prepare(
213 213
             'DELETE li
214
-				FROM ' . $this->table() . ' li
215
-				LEFT JOIN ' . EEM_Transaction::instance()->table() . ' t ON li.TXN_ID = t.TXN_ID
214
+				FROM ' . $this->table().' li
215
+				LEFT JOIN ' . EEM_Transaction::instance()->table().' t ON li.TXN_ID = t.TXN_ID
216 216
 				WHERE t.TXN_ID IS NULL AND li.LIN_timestamp < %s',
217 217
             // use GMT time because that's what TXN_timestamps are in
218 218
             date('Y-m-d H:i:s', time() - $time_to_leave_alone)
@@ -253,7 +253,7 @@  discard block
 block discarded – undo
253 253
         $query_params = array(
254 254
             'OBJ_type' => $OBJ_type,
255 255
             // if incoming $OBJ_IDs is an array, then make sure it is formatted correctly for the query
256
-            'OBJ_ID' => is_array($OBJ_IDs) && !isset($OBJ_IDs['IN']) ? array('IN', $OBJ_IDs) : $OBJ_IDs
256
+            'OBJ_ID' => is_array($OBJ_IDs) && ! isset($OBJ_IDs['IN']) ? array('IN', $OBJ_IDs) : $OBJ_IDs
257 257
         );
258 258
         if ($TXN_ID) {
259 259
             $query_params['TXN_ID'] = $TXN_ID;
Please login to merge, or discard this patch.
Braces   +3 added lines, -1 removed lines patch added patch discarded remove patch
@@ -4,7 +4,9 @@
 block discarded – undo
4 4
 use EventEspresso\core\exceptions\InvalidInterfaceException;
5 5
 use EventEspresso\core\services\loaders\LoaderFactory;
6 6
 
7
-if (!defined('EVENT_ESPRESSO_VERSION')) exit('No direct script access allowed');
7
+if (!defined('EVENT_ESPRESSO_VERSION')) {
8
+	exit('No direct script access allowed');
9
+}
8 10
 
9 11
 /**
10 12
  * Event Espresso
Please login to merge, or discard this patch.
core/EE_Dependency_Map.core.php 1 patch
Indentation   +836 added lines, -836 removed lines patch added patch discarded remove patch
@@ -8,7 +8,7 @@  discard block
 block discarded – undo
8 8
 use EventEspresso\core\services\request\ResponseInterface;
9 9
 
10 10
 if (! defined('EVENT_ESPRESSO_VERSION')) {
11
-    exit('No direct script access allowed');
11
+	exit('No direct script access allowed');
12 12
 }
13 13
 
14 14
 
@@ -25,841 +25,841 @@  discard block
 block discarded – undo
25 25
 class EE_Dependency_Map
26 26
 {
27 27
 
28
-    /**
29
-     * This means that the requested class dependency is not present in the dependency map
30
-     */
31
-    const not_registered = 0;
32
-
33
-    /**
34
-     * This instructs class loaders to ALWAYS return a newly instantiated object for the requested class.
35
-     */
36
-    const load_new_object = 1;
37
-
38
-    /**
39
-     * This instructs class loaders to return a previously instantiated and cached object for the requested class.
40
-     * IF a previously instantiated object does not exist, a new one will be created and added to the cache.
41
-     */
42
-    const load_from_cache = 2;
43
-
44
-    /**
45
-     * When registering a dependency,
46
-     * this indicates to keep any existing dependencies that already exist,
47
-     * and simply discard any new dependencies declared in the incoming data
48
-     */
49
-    const KEEP_EXISTING_DEPENDENCIES = 0;
50
-
51
-    /**
52
-     * When registering a dependency,
53
-     * this indicates to overwrite any existing dependencies that already exist using the incoming data
54
-     */
55
-    const OVERWRITE_DEPENDENCIES = 1;
56
-
57
-
58
-
59
-    /**
60
-     * @type EE_Dependency_Map $_instance
61
-     */
62
-    protected static $_instance;
63
-
64
-    /**
65
-     * @type RequestInterface $request
66
-     */
67
-    protected $request;
68
-
69
-    /**
70
-     * @type LegacyRequestInterface $legacy_request
71
-     */
72
-    protected $legacy_request;
73
-
74
-    /**
75
-     * @type ResponseInterface $response
76
-     */
77
-    protected $response;
78
-
79
-    /**
80
-     * @type LoaderInterface $loader
81
-     */
82
-    protected $loader;
83
-
84
-    /**
85
-     * @type array $_dependency_map
86
-     */
87
-    protected $_dependency_map = array();
88
-
89
-    /**
90
-     * @type array $_class_loaders
91
-     */
92
-    protected $_class_loaders = array();
93
-
94
-    /**
95
-     * @type array $_aliases
96
-     */
97
-    protected $_aliases = array();
98
-
99
-
100
-
101
-    /**
102
-     * EE_Dependency_Map constructor.
103
-     */
104
-    protected function __construct()
105
-    {
106
-        // add_action('EE_Load_Espresso_Core__handle_request__initialize_core_loading', array($this, 'initialize'));
107
-        do_action('EE_Dependency_Map____construct');
108
-    }
109
-
110
-
111
-
112
-    /**
113
-     * @throws InvalidDataTypeException
114
-     * @throws InvalidInterfaceException
115
-     * @throws InvalidArgumentException
116
-     */
117
-    public function initialize()
118
-    {
119
-        $this->_register_core_dependencies();
120
-        $this->_register_core_class_loaders();
121
-        $this->_register_core_aliases();
122
-    }
123
-
124
-
125
-
126
-    /**
127
-     * @singleton method used to instantiate class object
128
-     * @return EE_Dependency_Map
129
-     */
130
-    public static function instance() {
131
-        // check if class object is instantiated, and instantiated properly
132
-        if (! self::$_instance instanceof EE_Dependency_Map) {
133
-            self::$_instance = new EE_Dependency_Map(/*$request, $response, $legacy_request*/);
134
-        }
135
-        return self::$_instance;
136
-    }
137
-
138
-
139
-    /**
140
-     * @param RequestInterface $request
141
-     */
142
-    public function setRequest(RequestInterface $request)
143
-    {
144
-        $this->request = $request;
145
-    }
146
-
147
-
148
-    /**
149
-     * @param LegacyRequestInterface $legacy_request
150
-     */
151
-    public function setLegacyRequest(LegacyRequestInterface $legacy_request)
152
-    {
153
-        $this->legacy_request = $legacy_request;
154
-    }
155
-
156
-
157
-    /**
158
-     * @param ResponseInterface $response
159
-     */
160
-    public function setResponse(ResponseInterface $response)
161
-    {
162
-        $this->response = $response;
163
-    }
164
-
165
-
166
-
167
-    /**
168
-     * @param LoaderInterface $loader
169
-     */
170
-    public function setLoader(LoaderInterface $loader)
171
-    {
172
-        $this->loader = $loader;
173
-    }
174
-
175
-
176
-
177
-    /**
178
-     * @param string $class
179
-     * @param array  $dependencies
180
-     * @param int    $overwrite
181
-     * @return bool
182
-     */
183
-    public static function register_dependencies(
184
-        $class,
185
-        array $dependencies,
186
-        $overwrite = EE_Dependency_Map::KEEP_EXISTING_DEPENDENCIES
187
-    ) {
188
-        return self::$_instance->registerDependencies($class, $dependencies, $overwrite);
189
-    }
190
-
191
-
192
-
193
-    /**
194
-     * Assigns an array of class names and corresponding load sources (new or cached)
195
-     * to the class specified by the first parameter.
196
-     * IMPORTANT !!!
197
-     * The order of elements in the incoming $dependencies array MUST match
198
-     * the order of the constructor parameters for the class in question.
199
-     * This is especially important when overriding any existing dependencies that are registered.
200
-     * the third parameter controls whether any duplicate dependencies are overwritten or not.
201
-     *
202
-     * @param string $class
203
-     * @param array  $dependencies
204
-     * @param int    $overwrite
205
-     * @return bool
206
-     */
207
-    public function registerDependencies(
208
-        $class,
209
-        array $dependencies,
210
-        $overwrite = EE_Dependency_Map::KEEP_EXISTING_DEPENDENCIES
211
-    ) {
212
-        $class = trim($class, '\\');
213
-        $registered = false;
214
-        if (empty(self::$_instance->_dependency_map[ $class ])) {
215
-            self::$_instance->_dependency_map[ $class ] = array();
216
-        }
217
-        // we need to make sure that any aliases used when registering a dependency
218
-        // get resolved to the correct class name
219
-        foreach ($dependencies as $dependency => $load_source) {
220
-            $alias = self::$_instance->get_alias($dependency);
221
-            if (
222
-                $overwrite === EE_Dependency_Map::OVERWRITE_DEPENDENCIES
223
-                || ! isset(self::$_instance->_dependency_map[ $class ][ $alias ])
224
-            ) {
225
-                unset($dependencies[$dependency]);
226
-                $dependencies[$alias] = $load_source;
227
-                $registered = true;
228
-            }
229
-        }
230
-        // now add our two lists of dependencies together.
231
-        // using Union (+=) favours the arrays in precedence from left to right,
232
-        // so $dependencies is NOT overwritten because it is listed first
233
-        // ie: with A = B + C, entries in B take precedence over duplicate entries in C
234
-        // Union is way faster than array_merge() but should be used with caution...
235
-        // especially with numerically indexed arrays
236
-        $dependencies += self::$_instance->_dependency_map[ $class ];
237
-        // now we need to ensure that the resulting dependencies
238
-        // array only has the entries that are required for the class
239
-        // so first count how many dependencies were originally registered for the class
240
-        $dependency_count = count(self::$_instance->_dependency_map[ $class ]);
241
-        // if that count is non-zero (meaning dependencies were already registered)
242
-        self::$_instance->_dependency_map[ $class ] = $dependency_count
243
-            // then truncate the  final array to match that count
244
-            ? array_slice($dependencies, 0, $dependency_count)
245
-            // otherwise just take the incoming array because nothing previously existed
246
-            : $dependencies;
247
-        return $registered;
248
-    }
249
-
250
-
251
-
252
-    /**
253
-     * @param string $class_name
254
-     * @param string $loader
255
-     * @return bool
256
-     * @throws DomainException
257
-     */
258
-    public static function register_class_loader($class_name, $loader = 'load_core')
259
-    {
260
-        if (! $loader instanceof Closure && strpos($class_name, '\\') !== false) {
261
-            throw new DomainException(
262
-                esc_html__('Don\'t use class loaders for FQCNs.', 'event_espresso')
263
-            );
264
-        }
265
-        // check that loader is callable or method starts with "load_" and exists in EE_Registry
266
-        if (
267
-            ! is_callable($loader)
268
-            && (
269
-                strpos($loader, 'load_') !== 0
270
-                || ! method_exists('EE_Registry', $loader)
271
-            )
272
-        ) {
273
-            throw new DomainException(
274
-                sprintf(
275
-                    esc_html__(
276
-                        '"%1$s" is not a valid loader method on EE_Registry.',
277
-                        'event_espresso'
278
-                    ),
279
-                    $loader
280
-                )
281
-            );
282
-        }
283
-        $class_name = self::$_instance->get_alias($class_name);
284
-        if (! isset(self::$_instance->_class_loaders[$class_name])) {
285
-            self::$_instance->_class_loaders[$class_name] = $loader;
286
-            return true;
287
-        }
288
-        return false;
289
-    }
290
-
291
-
292
-
293
-    /**
294
-     * @return array
295
-     */
296
-    public function dependency_map()
297
-    {
298
-        return $this->_dependency_map;
299
-    }
300
-
301
-
302
-
303
-    /**
304
-     * returns TRUE if dependency map contains a listing for the provided class name
305
-     *
306
-     * @param string $class_name
307
-     * @return boolean
308
-     */
309
-    public function has($class_name = '')
310
-    {
311
-        // all legacy models have the same dependencies
312
-        if (strpos($class_name, 'EEM_') === 0) {
313
-            $class_name = 'LEGACY_MODELS';
314
-        }
315
-        return isset($this->_dependency_map[$class_name]) ? true : false;
316
-    }
317
-
318
-
319
-
320
-    /**
321
-     * returns TRUE if dependency map contains a listing for the provided class name AND dependency
322
-     *
323
-     * @param string $class_name
324
-     * @param string $dependency
325
-     * @return bool
326
-     */
327
-    public function has_dependency_for_class($class_name = '', $dependency = '')
328
-    {
329
-        // all legacy models have the same dependencies
330
-        if (strpos($class_name, 'EEM_') === 0) {
331
-            $class_name = 'LEGACY_MODELS';
332
-        }
333
-        $dependency = $this->get_alias($dependency);
334
-        return isset($this->_dependency_map[$class_name][$dependency])
335
-            ? true
336
-            : false;
337
-    }
338
-
339
-
340
-
341
-    /**
342
-     * returns loading strategy for whether a previously cached dependency should be loaded or a new instance returned
343
-     *
344
-     * @param string $class_name
345
-     * @param string $dependency
346
-     * @return int
347
-     */
348
-    public function loading_strategy_for_class_dependency($class_name = '', $dependency = '')
349
-    {
350
-        // all legacy models have the same dependencies
351
-        if (strpos($class_name, 'EEM_') === 0) {
352
-            $class_name = 'LEGACY_MODELS';
353
-        }
354
-        $dependency = $this->get_alias($dependency);
355
-        return $this->has_dependency_for_class($class_name, $dependency)
356
-            ? $this->_dependency_map[$class_name][$dependency]
357
-            : EE_Dependency_Map::not_registered;
358
-    }
359
-
360
-
361
-
362
-    /**
363
-     * @param string $class_name
364
-     * @return string | Closure
365
-     */
366
-    public function class_loader($class_name)
367
-    {
368
-        // all legacy models use load_model()
369
-        if(strpos($class_name, 'EEM_') === 0){
370
-            return 'load_model';
371
-        }
372
-        $class_name = $this->get_alias($class_name);
373
-        return isset($this->_class_loaders[$class_name]) ? $this->_class_loaders[$class_name] : '';
374
-    }
375
-
376
-
377
-
378
-    /**
379
-     * @return array
380
-     */
381
-    public function class_loaders()
382
-    {
383
-        return $this->_class_loaders;
384
-    }
385
-
386
-
387
-
388
-    /**
389
-     * adds an alias for a classname
390
-     *
391
-     * @param string $class_name the class name that should be used (concrete class to replace interface)
392
-     * @param string $alias      the class name that would be type hinted for (abstract parent or interface)
393
-     * @param string $for_class  the class that has the dependency (is type hinting for the interface)
394
-     */
395
-    public function add_alias($class_name, $alias, $for_class = '')
396
-    {
397
-        if ($for_class !== '') {
398
-            if (! isset($this->_aliases[$for_class])) {
399
-                $this->_aliases[$for_class] = array();
400
-            }
401
-            $this->_aliases[$for_class][$class_name] = $alias;
402
-        }
403
-        $this->_aliases[$class_name] = $alias;
404
-    }
405
-
406
-
407
-
408
-    /**
409
-     * returns TRUE if the provided class name has an alias
410
-     *
411
-     * @param string $class_name
412
-     * @param string $for_class
413
-     * @return bool
414
-     */
415
-    public function has_alias($class_name = '', $for_class = '')
416
-    {
417
-        return isset($this->_aliases[$for_class][$class_name])
418
-               || (
419
-                   isset($this->_aliases[$class_name])
420
-                   && ! is_array($this->_aliases[$class_name])
421
-               );
422
-    }
423
-
424
-
425
-
426
-    /**
427
-     * returns alias for class name if one exists, otherwise returns the original classname
428
-     * functions recursively, so that multiple aliases can be used to drill down to a classname
429
-     *  for example:
430
-     *      if the following two entries were added to the _aliases array:
431
-     *          array(
432
-     *              'interface_alias'           => 'some\namespace\interface'
433
-     *              'some\namespace\interface'  => 'some\namespace\classname'
434
-     *          )
435
-     *      then one could use EE_Registry::instance()->create( 'interface_alias' )
436
-     *      to load an instance of 'some\namespace\classname'
437
-     *
438
-     * @param string $class_name
439
-     * @param string $for_class
440
-     * @return string
441
-     */
442
-    public function get_alias($class_name = '', $for_class = '')
443
-    {
444
-        if (! $this->has_alias($class_name, $for_class)) {
445
-            return $class_name;
446
-        }
447
-        if ($for_class !== '' && isset($this->_aliases[ $for_class ][ $class_name ])) {
448
-            return $this->get_alias($this->_aliases[$for_class][$class_name], $for_class);
449
-        }
450
-        return $this->get_alias($this->_aliases[$class_name]);
451
-    }
452
-
453
-
454
-
455
-    /**
456
-     * Registers the core dependencies and whether a previously instantiated object should be loaded from the cache,
457
-     * if one exists, or whether a new object should be generated every time the requested class is loaded.
458
-     * This is done by using the following class constants:
459
-     *        EE_Dependency_Map::load_from_cache - loads previously instantiated object
460
-     *        EE_Dependency_Map::load_new_object - generates a new object every time
461
-     */
462
-    protected function _register_core_dependencies()
463
-    {
464
-        $this->_dependency_map = array(
465
-            'EE_Request_Handler'                                                                                          => array(
466
-                'EE_Request' => EE_Dependency_Map::load_from_cache,
467
-            ),
468
-            'EE_System'                                                                                                   => array(
469
-                'EE_Registry'                                 => EE_Dependency_Map::load_from_cache,
470
-                'EventEspresso\core\services\loaders\Loader'  => EE_Dependency_Map::load_from_cache,
471
-                'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
472
-                'EE_Maintenance_Mode'                         => EE_Dependency_Map::load_from_cache,
473
-            ),
474
-            'EE_Session'                                                                                                  => array(
475
-                'EventEspresso\core\services\cache\TransientCacheStorage'  => EE_Dependency_Map::load_from_cache,
476
-                'EventEspresso\core\domain\values\session\SessionLifespan' => EE_Dependency_Map::load_from_cache,
477
-                'EventEspresso\core\services\request\Request'              => EE_Dependency_Map::load_from_cache,
478
-                'EE_Encryption'                                            => EE_Dependency_Map::load_from_cache,
479
-            ),
480
-            'EE_Cart'                                                                                                     => array(
481
-                'EE_Session' => EE_Dependency_Map::load_from_cache,
482
-            ),
483
-            'EE_Front_Controller'                                                                                         => array(
484
-                'EE_Registry'              => EE_Dependency_Map::load_from_cache,
485
-                'EE_Request_Handler'       => EE_Dependency_Map::load_from_cache,
486
-                'EE_Module_Request_Router' => EE_Dependency_Map::load_from_cache,
487
-            ),
488
-            'EE_Messenger_Collection_Loader'                                                                              => array(
489
-                'EE_Messenger_Collection' => EE_Dependency_Map::load_new_object,
490
-            ),
491
-            'EE_Message_Type_Collection_Loader'                                                                           => array(
492
-                'EE_Message_Type_Collection' => EE_Dependency_Map::load_new_object,
493
-            ),
494
-            'EE_Message_Resource_Manager'                                                                                 => array(
495
-                'EE_Messenger_Collection_Loader'    => EE_Dependency_Map::load_new_object,
496
-                'EE_Message_Type_Collection_Loader' => EE_Dependency_Map::load_new_object,
497
-                'EEM_Message_Template_Group'        => EE_Dependency_Map::load_from_cache,
498
-            ),
499
-            'EE_Message_Factory'                                                                                          => array(
500
-                'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
501
-            ),
502
-            'EE_messages'                                                                                                 => array(
503
-                'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
504
-            ),
505
-            'EE_Messages_Generator'                                                                                       => array(
506
-                'EE_Messages_Queue'                    => EE_Dependency_Map::load_new_object,
507
-                'EE_Messages_Data_Handler_Collection'  => EE_Dependency_Map::load_new_object,
508
-                'EE_Message_Template_Group_Collection' => EE_Dependency_Map::load_new_object,
509
-                'EEH_Parse_Shortcodes'                 => EE_Dependency_Map::load_from_cache,
510
-            ),
511
-            'EE_Messages_Processor'                                                                                       => array(
512
-                'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
513
-            ),
514
-            'EE_Messages_Queue'                                                                                           => array(
515
-                'EE_Message_Repository' => EE_Dependency_Map::load_new_object,
516
-            ),
517
-            'EE_Messages_Template_Defaults'                                                                               => array(
518
-                'EEM_Message_Template_Group' => EE_Dependency_Map::load_from_cache,
519
-                'EEM_Message_Template'       => EE_Dependency_Map::load_from_cache,
520
-            ),
521
-            'EE_Message_To_Generate_From_Request'                                                                         => array(
522
-                'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
523
-                'EE_Request_Handler'          => EE_Dependency_Map::load_from_cache,
524
-            ),
525
-            'EventEspresso\core\services\commands\CommandBus'                                                             => array(
526
-                'EventEspresso\core\services\commands\CommandHandlerManager' => EE_Dependency_Map::load_from_cache,
527
-            ),
528
-            'EventEspresso\services\commands\CommandHandler'                                                              => array(
529
-                'EE_Registry'         => EE_Dependency_Map::load_from_cache,
530
-                'CommandBusInterface' => EE_Dependency_Map::load_from_cache,
531
-            ),
532
-            'EventEspresso\core\services\commands\CommandHandlerManager'                                                  => array(
533
-                'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
534
-            ),
535
-            'EventEspresso\core\services\commands\CompositeCommandHandler'                                                => array(
536
-                'EventEspresso\core\services\commands\CommandBus'     => EE_Dependency_Map::load_from_cache,
537
-                'EventEspresso\core\services\commands\CommandFactory' => EE_Dependency_Map::load_from_cache,
538
-            ),
539
-            'EventEspresso\core\services\commands\CommandFactory'                                                         => array(
540
-                'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
541
-            ),
542
-            'EventEspresso\core\services\commands\middleware\CapChecker'                                                  => array(
543
-                'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker' => EE_Dependency_Map::load_from_cache,
544
-            ),
545
-            'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker'                                         => array(
546
-                'EE_Capabilities' => EE_Dependency_Map::load_from_cache,
547
-            ),
548
-            'EventEspresso\core\domain\services\capabilities\RegistrationsCapChecker'                                     => array(
549
-                'EE_Capabilities' => EE_Dependency_Map::load_from_cache,
550
-            ),
551
-            'EventEspresso\core\services\commands\registration\CreateRegistrationCommandHandler'                          => array(
552
-                'EventEspresso\core\domain\services\registration\CreateRegistrationService' => EE_Dependency_Map::load_from_cache,
553
-            ),
554
-            'EventEspresso\core\services\commands\registration\CopyRegistrationDetailsCommandHandler'                     => array(
555
-                'EventEspresso\core\domain\services\registration\CopyRegistrationService' => EE_Dependency_Map::load_from_cache,
556
-            ),
557
-            'EventEspresso\core\services\commands\registration\CopyRegistrationPaymentsCommandHandler'                    => array(
558
-                'EventEspresso\core\domain\services\registration\CopyRegistrationService' => EE_Dependency_Map::load_from_cache,
559
-            ),
560
-            'EventEspresso\core\services\commands\registration\CancelRegistrationAndTicketLineItemCommandHandler'         => array(
561
-                'EventEspresso\core\domain\services\registration\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache,
562
-            ),
563
-            'EventEspresso\core\services\commands\registration\UpdateRegistrationAndTransactionAfterChangeCommandHandler' => array(
564
-                'EventEspresso\core\domain\services\registration\UpdateRegistrationService' => EE_Dependency_Map::load_from_cache,
565
-            ),
566
-            'EventEspresso\core\services\commands\ticket\CreateTicketLineItemCommandHandler'                              => array(
567
-                'EventEspresso\core\domain\services\ticket\CreateTicketLineItemService' => EE_Dependency_Map::load_from_cache,
568
-            ),
569
-            'EventEspresso\core\services\commands\ticket\CancelTicketLineItemCommandHandler'                              => array(
570
-                'EventEspresso\core\domain\services\ticket\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache,
571
-            ),
572
-            'EventEspresso\core\domain\services\registration\CancelRegistrationService'                                   => array(
573
-                'EventEspresso\core\domain\services\ticket\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache,
574
-            ),
575
-            'EventEspresso\core\services\commands\attendee\CreateAttendeeCommandHandler'                                  => array(
576
-                'EEM_Attendee' => EE_Dependency_Map::load_from_cache,
577
-            ),
578
-            'EventEspresso\core\services\database\TableManager'                                                           => array(
579
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
580
-            ),
581
-            'EE_Data_Migration_Class_Base'                                                                                => array(
582
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
583
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
584
-            ),
585
-            'EE_DMS_Core_4_1_0'                                                                                           => array(
586
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
587
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
588
-            ),
589
-            'EE_DMS_Core_4_2_0'                                                                                           => array(
590
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
591
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
592
-            ),
593
-            'EE_DMS_Core_4_3_0'                                                                                           => array(
594
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
595
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
596
-            ),
597
-            'EE_DMS_Core_4_4_0'                                                                                           => array(
598
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
599
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
600
-            ),
601
-            'EE_DMS_Core_4_5_0'                                                                                           => array(
602
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
603
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
604
-            ),
605
-            'EE_DMS_Core_4_6_0'                                                                                           => array(
606
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
607
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
608
-            ),
609
-            'EE_DMS_Core_4_7_0'                                                                                           => array(
610
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
611
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
612
-            ),
613
-            'EE_DMS_Core_4_8_0'                                                                                           => array(
614
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
615
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
616
-            ),
617
-            'EE_DMS_Core_4_9_0'                                                                                           => array(
618
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
619
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
620
-            ),
621
-            'EventEspresso\core\services\assets\Registry'                                                                 => array(
622
-                'EE_Template_Config' => EE_Dependency_Map::load_from_cache,
623
-                'EE_Currency_Config' => EE_Dependency_Map::load_from_cache,
624
-                'EventEspresso\core\domain\Domain' => EE_Dependency_Map::load_from_cache
625
-            ),
626
-            'EventEspresso\core\domain\entities\shortcodes\EspressoCancelled'                                             => array(
627
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
628
-            ),
629
-            'EventEspresso\core\domain\entities\shortcodes\EspressoCheckout'                                              => array(
630
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
631
-            ),
632
-            'EventEspresso\core\domain\entities\shortcodes\EspressoEventAttendees'                                        => array(
633
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
634
-            ),
635
-            'EventEspresso\core\domain\entities\shortcodes\EspressoEvents'                                                => array(
636
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
637
-            ),
638
-            'EventEspresso\core\domain\entities\shortcodes\EspressoThankYou'                                              => array(
639
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
640
-            ),
641
-            'EventEspresso\core\domain\entities\shortcodes\EspressoTicketSelector'                                        => array(
642
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
643
-            ),
644
-            'EventEspresso\core\domain\entities\shortcodes\EspressoTxnPage'                                               => array(
645
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
646
-            ),
647
-            'EventEspresso\core\services\cache\BasicCacheManager'                        => array(
648
-                'EventEspresso\core\services\cache\TransientCacheStorage' => EE_Dependency_Map::load_from_cache,
649
-            ),
650
-            'EventEspresso\core\services\cache\PostRelatedCacheManager'                  => array(
651
-                'EventEspresso\core\services\cache\TransientCacheStorage' => EE_Dependency_Map::load_from_cache,
652
-            ),
653
-            'EventEspresso\core\domain\services\validation\email\EmailValidationService' => array(
654
-                'EE_Registration_Config'                                  => EE_Dependency_Map::load_from_cache,
655
-                'EventEspresso\core\services\loaders\Loader'              => EE_Dependency_Map::load_from_cache,
656
-            ),
657
-            'EventEspresso\core\domain\values\EmailAddress'                              => array(
658
-                null,
659
-                'EventEspresso\core\domain\services\validation\email\EmailValidationService' => EE_Dependency_Map::load_from_cache,
660
-            ),
661
-            'EventEspresso\core\services\orm\ModelFieldFactory' => array(
662
-                'EventEspresso\core\services\loaders\Loader'              => EE_Dependency_Map::load_from_cache,
663
-            ),
664
-            'LEGACY_MODELS'                                                   => array(
665
-                null,
666
-                'EventEspresso\core\services\database\ModelFieldFactory' => EE_Dependency_Map::load_from_cache,
667
-            ),
668
-            'EE_Module_Request_Router' => array(
669
-                'EE_Request' => EE_Dependency_Map::load_from_cache,
670
-            ),
671
-            'EE_Registration_Processor' => array(
672
-                'EE_Request' => EE_Dependency_Map::load_from_cache,
673
-            ),
674
-            'EventEspresso\core\services\notifications\PersistentAdminNoticeManager' => array(
675
-                null,
676
-                'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker' => EE_Dependency_Map::load_from_cache,
677
-                'EE_Request' => EE_Dependency_Map::load_from_cache,
678
-            ),
679
-            'EE_Admin_Transactions_List_Table' => array(
680
-                null,
681
-                'EventEspresso\core\domain\values\session\SessionLifespan' => EE_Dependency_Map::load_from_cache,
682
-            ),
683
-        );
684
-    }
685
-
686
-
687
-
688
-    /**
689
-     * Registers how core classes are loaded.
690
-     * This can either be done by simply providing the name of one of the EE_Registry loader methods such as:
691
-     *        'EE_Request_Handler' => 'load_core'
692
-     *        'EE_Messages_Queue'  => 'load_lib'
693
-     *        'EEH_Debug_Tools'    => 'load_helper'
694
-     * or, if greater control is required, by providing a custom closure. For example:
695
-     *        'Some_Class' => function () {
696
-     *            return new Some_Class();
697
-     *        },
698
-     * This is required for instantiating dependencies
699
-     * where an interface has been type hinted in a class constructor. For example:
700
-     *        'Required_Interface' => function () {
701
-     *            return new A_Class_That_Implements_Required_Interface();
702
-     *        },
703
-     *
704
-     * @throws InvalidInterfaceException
705
-     * @throws InvalidDataTypeException
706
-     * @throws InvalidArgumentException
707
-     */
708
-    protected function _register_core_class_loaders()
709
-    {
710
-        //for PHP5.3 compat, we need to register any properties called here in a variable because `$this` cannot
711
-        //be used in a closure.
712
-        $request = &$this->request;
713
-        $response = &$this->response;
714
-        $legacy_request = &$this->legacy_request;
715
-        // $loader = &$this->loader;
716
-        $this->_class_loaders = array(
717
-            //load_core
718
-            'EE_Capabilities'          => 'load_core',
719
-            'EE_Encryption'            => 'load_core',
720
-            'EE_Front_Controller'      => 'load_core',
721
-            'EE_Module_Request_Router' => 'load_core',
722
-            'EE_Registry'              => 'load_core',
723
-            'EE_Request'               => function () use (&$legacy_request) {
724
-                return $legacy_request;
725
-            },
726
-            'EventEspresso\core\services\request\Request' => function () use (&$request) {
727
-                return $request;
728
-            },
729
-            'EventEspresso\core\services\request\Response' => function () use (&$response) {
730
-                return $response;
731
-            },
732
-            'EE_Request_Handler'       => 'load_core',
733
-            'EE_Session'               => 'load_core',
734
-            'EE_Cron_Tasks'            => 'load_core',
735
-            'EE_System'                => 'load_core',
736
-            'EE_Maintenance_Mode'      => 'load_core',
737
-            'EE_Register_CPTs'         => 'load_core',
738
-            'EE_Admin'                 => 'load_core',
739
-            //load_lib
740
-            'EE_Message_Resource_Manager'          => 'load_lib',
741
-            'EE_Message_Type_Collection'           => 'load_lib',
742
-            'EE_Message_Type_Collection_Loader'    => 'load_lib',
743
-            'EE_Messenger_Collection'              => 'load_lib',
744
-            'EE_Messenger_Collection_Loader'       => 'load_lib',
745
-            'EE_Messages_Processor'                => 'load_lib',
746
-            'EE_Message_Repository'                => 'load_lib',
747
-            'EE_Messages_Queue'                    => 'load_lib',
748
-            'EE_Messages_Data_Handler_Collection'  => 'load_lib',
749
-            'EE_Message_Template_Group_Collection' => 'load_lib',
750
-            'EE_Payment_Method_Manager'            => 'load_lib',
751
-            'EE_Messages_Generator'                => function () {
752
-                return EE_Registry::instance()->load_lib(
753
-                    'Messages_Generator',
754
-                    array(),
755
-                    false,
756
-                    false
757
-                );
758
-            },
759
-            'EE_Messages_Template_Defaults'        => function ($arguments = array()) {
760
-                return EE_Registry::instance()->load_lib(
761
-                    'Messages_Template_Defaults',
762
-                    $arguments,
763
-                    false,
764
-                    false
765
-                );
766
-            },
767
-            //load_model
768
-            // 'EEM_Attendee'                         => 'load_model',
769
-            // 'EEM_Message_Template_Group'           => 'load_model',
770
-            // 'EEM_Message_Template'                 => 'load_model',
771
-            //load_helper
772
-            'EEH_Parse_Shortcodes'                 => function () {
773
-                if (EE_Registry::instance()->load_helper('Parse_Shortcodes')) {
774
-                    return new EEH_Parse_Shortcodes();
775
-                }
776
-                return null;
777
-            },
778
-            'EE_Template_Config'                   => function () {
779
-                return EE_Config::instance()->template_settings;
780
-            },
781
-            'EE_Currency_Config'                   => function () {
782
-                return EE_Config::instance()->currency;
783
-            },
784
-            'EE_Registration_Config'                   => function () {
785
-                return EE_Config::instance()->registration;
786
-            },
787
-            'EventEspresso\core\services\loaders\Loader' => function () {
788
-                return LoaderFactory::getLoader();
789
-            },
790
-        );
791
-    }
792
-
793
-
794
-
795
-    /**
796
-     * can be used for supplying alternate names for classes,
797
-     * or for connecting interface names to instantiable classes
798
-     */
799
-    protected function _register_core_aliases()
800
-    {
801
-        $this->_aliases = array(
802
-            'CommandBusInterface'                                                          => 'EventEspresso\core\services\commands\CommandBusInterface',
803
-            'EventEspresso\core\services\commands\CommandBusInterface'                     => 'EventEspresso\core\services\commands\CommandBus',
804
-            'CommandHandlerManagerInterface'                                               => 'EventEspresso\core\services\commands\CommandHandlerManagerInterface',
805
-            'EventEspresso\core\services\commands\CommandHandlerManagerInterface'          => 'EventEspresso\core\services\commands\CommandHandlerManager',
806
-            'CapChecker'                                                                   => 'EventEspresso\core\services\commands\middleware\CapChecker',
807
-            'AddActionHook'                                                                => 'EventEspresso\core\services\commands\middleware\AddActionHook',
808
-            'CapabilitiesChecker'                                                          => 'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker',
809
-            'CapabilitiesCheckerInterface'                                                 => 'EventEspresso\core\domain\services\capabilities\CapabilitiesCheckerInterface',
810
-            'EventEspresso\core\domain\services\capabilities\CapabilitiesCheckerInterface' => 'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker',
811
-            'CreateRegistrationService'                                                    => 'EventEspresso\core\domain\services\registration\CreateRegistrationService',
812
-            'CreateRegCodeCommandHandler'                                                  => 'EventEspresso\core\services\commands\registration\CreateRegCodeCommand',
813
-            'CreateRegUrlLinkCommandHandler'                                               => 'EventEspresso\core\services\commands\registration\CreateRegUrlLinkCommand',
814
-            'CreateRegistrationCommandHandler'                                             => 'EventEspresso\core\services\commands\registration\CreateRegistrationCommand',
815
-            'CopyRegistrationDetailsCommandHandler'                                        => 'EventEspresso\core\services\commands\registration\CopyRegistrationDetailsCommand',
816
-            'CopyRegistrationPaymentsCommandHandler'                                       => 'EventEspresso\core\services\commands\registration\CopyRegistrationPaymentsCommand',
817
-            'CancelRegistrationAndTicketLineItemCommandHandler'                            => 'EventEspresso\core\services\commands\registration\CancelRegistrationAndTicketLineItemCommandHandler',
818
-            'UpdateRegistrationAndTransactionAfterChangeCommandHandler'                    => 'EventEspresso\core\services\commands\registration\UpdateRegistrationAndTransactionAfterChangeCommandHandler',
819
-            'CreateTicketLineItemCommandHandler'                                           => 'EventEspresso\core\services\commands\ticket\CreateTicketLineItemCommand',
820
-            'CreateTransactionCommandHandler'                                     => 'EventEspresso\core\services\commands\transaction\CreateTransactionCommandHandler',
821
-            'CreateAttendeeCommandHandler'                                        => 'EventEspresso\core\services\commands\attendee\CreateAttendeeCommandHandler',
822
-            'TableManager'                                                                 => 'EventEspresso\core\services\database\TableManager',
823
-            'TableAnalysis'                                                                => 'EventEspresso\core\services\database\TableAnalysis',
824
-            'EspressoShortcode'                                                            => 'EventEspresso\core\services\shortcodes\EspressoShortcode',
825
-            'ShortcodeInterface'                                                           => 'EventEspresso\core\services\shortcodes\ShortcodeInterface',
826
-            'EventEspresso\core\services\shortcodes\ShortcodeInterface'                    => 'EventEspresso\core\services\shortcodes\EspressoShortcode',
827
-            'EventEspresso\core\services\cache\CacheStorageInterface'                      => 'EventEspresso\core\services\cache\TransientCacheStorage',
828
-            'LoaderInterface'                                                              => 'EventEspresso\core\services\loaders\LoaderInterface',
829
-            'EventEspresso\core\services\loaders\LoaderInterface'                          => 'EventEspresso\core\services\loaders\Loader',
830
-            'CommandFactoryInterface'                                                     => 'EventEspresso\core\services\commands\CommandFactoryInterface',
831
-            'EventEspresso\core\services\commands\CommandFactoryInterface'                => 'EventEspresso\core\services\commands\CommandFactory',
832
-            'EventEspresso\core\domain\services\session\SessionIdentifierInterface'       => 'EE_Session',
833
-            'EmailValidatorInterface'                                                     => 'EventEspresso\core\domain\services\validation\email\EmailValidatorInterface',
834
-            'EventEspresso\core\domain\services\validation\email\EmailValidatorInterface' => 'EventEspresso\core\domain\services\validation\email\EmailValidationService',
835
-            'NoticeConverterInterface'                                            => 'EventEspresso\core\services\notices\NoticeConverterInterface',
836
-            'EventEspresso\core\services\notices\NoticeConverterInterface'        => 'EventEspresso\core\services\notices\ConvertNoticesToEeErrors',
837
-            'NoticesContainerInterface'                                           => 'EventEspresso\core\services\notices\NoticesContainerInterface',
838
-            'EventEspresso\core\services\notices\NoticesContainerInterface'       => 'EventEspresso\core\services\notices\NoticesContainer',
839
-            'EventEspresso\core\services\request\RequestInterface'                => 'EventEspresso\core\services\request\Request',
840
-            'EventEspresso\core\services\request\ResponseInterface'               => 'EventEspresso\core\services\request\Response',
841
-            'EventEspresso\core\domain\DomainInterface'                           => 'EventEspresso\core\domain\Domain',
842
-        );
843
-        if (! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) {
844
-            $this->_aliases['EventEspresso\core\services\notices\NoticeConverterInterface'] = 'EventEspresso\core\services\notices\ConvertNoticesToAdminNotices';
845
-        }
846
-    }
847
-
848
-
849
-
850
-    /**
851
-     * This is used to reset the internal map and class_loaders to their original default state at the beginning of the
852
-     * request Primarily used by unit tests.
853
-     *
854
-     * @throws InvalidDataTypeException
855
-     * @throws InvalidInterfaceException
856
-     * @throws InvalidArgumentException
857
-     */
858
-    public function reset()
859
-    {
860
-        $this->_register_core_class_loaders();
861
-        $this->_register_core_dependencies();
862
-    }
28
+	/**
29
+	 * This means that the requested class dependency is not present in the dependency map
30
+	 */
31
+	const not_registered = 0;
32
+
33
+	/**
34
+	 * This instructs class loaders to ALWAYS return a newly instantiated object for the requested class.
35
+	 */
36
+	const load_new_object = 1;
37
+
38
+	/**
39
+	 * This instructs class loaders to return a previously instantiated and cached object for the requested class.
40
+	 * IF a previously instantiated object does not exist, a new one will be created and added to the cache.
41
+	 */
42
+	const load_from_cache = 2;
43
+
44
+	/**
45
+	 * When registering a dependency,
46
+	 * this indicates to keep any existing dependencies that already exist,
47
+	 * and simply discard any new dependencies declared in the incoming data
48
+	 */
49
+	const KEEP_EXISTING_DEPENDENCIES = 0;
50
+
51
+	/**
52
+	 * When registering a dependency,
53
+	 * this indicates to overwrite any existing dependencies that already exist using the incoming data
54
+	 */
55
+	const OVERWRITE_DEPENDENCIES = 1;
56
+
57
+
58
+
59
+	/**
60
+	 * @type EE_Dependency_Map $_instance
61
+	 */
62
+	protected static $_instance;
63
+
64
+	/**
65
+	 * @type RequestInterface $request
66
+	 */
67
+	protected $request;
68
+
69
+	/**
70
+	 * @type LegacyRequestInterface $legacy_request
71
+	 */
72
+	protected $legacy_request;
73
+
74
+	/**
75
+	 * @type ResponseInterface $response
76
+	 */
77
+	protected $response;
78
+
79
+	/**
80
+	 * @type LoaderInterface $loader
81
+	 */
82
+	protected $loader;
83
+
84
+	/**
85
+	 * @type array $_dependency_map
86
+	 */
87
+	protected $_dependency_map = array();
88
+
89
+	/**
90
+	 * @type array $_class_loaders
91
+	 */
92
+	protected $_class_loaders = array();
93
+
94
+	/**
95
+	 * @type array $_aliases
96
+	 */
97
+	protected $_aliases = array();
98
+
99
+
100
+
101
+	/**
102
+	 * EE_Dependency_Map constructor.
103
+	 */
104
+	protected function __construct()
105
+	{
106
+		// add_action('EE_Load_Espresso_Core__handle_request__initialize_core_loading', array($this, 'initialize'));
107
+		do_action('EE_Dependency_Map____construct');
108
+	}
109
+
110
+
111
+
112
+	/**
113
+	 * @throws InvalidDataTypeException
114
+	 * @throws InvalidInterfaceException
115
+	 * @throws InvalidArgumentException
116
+	 */
117
+	public function initialize()
118
+	{
119
+		$this->_register_core_dependencies();
120
+		$this->_register_core_class_loaders();
121
+		$this->_register_core_aliases();
122
+	}
123
+
124
+
125
+
126
+	/**
127
+	 * @singleton method used to instantiate class object
128
+	 * @return EE_Dependency_Map
129
+	 */
130
+	public static function instance() {
131
+		// check if class object is instantiated, and instantiated properly
132
+		if (! self::$_instance instanceof EE_Dependency_Map) {
133
+			self::$_instance = new EE_Dependency_Map(/*$request, $response, $legacy_request*/);
134
+		}
135
+		return self::$_instance;
136
+	}
137
+
138
+
139
+	/**
140
+	 * @param RequestInterface $request
141
+	 */
142
+	public function setRequest(RequestInterface $request)
143
+	{
144
+		$this->request = $request;
145
+	}
146
+
147
+
148
+	/**
149
+	 * @param LegacyRequestInterface $legacy_request
150
+	 */
151
+	public function setLegacyRequest(LegacyRequestInterface $legacy_request)
152
+	{
153
+		$this->legacy_request = $legacy_request;
154
+	}
155
+
156
+
157
+	/**
158
+	 * @param ResponseInterface $response
159
+	 */
160
+	public function setResponse(ResponseInterface $response)
161
+	{
162
+		$this->response = $response;
163
+	}
164
+
165
+
166
+
167
+	/**
168
+	 * @param LoaderInterface $loader
169
+	 */
170
+	public function setLoader(LoaderInterface $loader)
171
+	{
172
+		$this->loader = $loader;
173
+	}
174
+
175
+
176
+
177
+	/**
178
+	 * @param string $class
179
+	 * @param array  $dependencies
180
+	 * @param int    $overwrite
181
+	 * @return bool
182
+	 */
183
+	public static function register_dependencies(
184
+		$class,
185
+		array $dependencies,
186
+		$overwrite = EE_Dependency_Map::KEEP_EXISTING_DEPENDENCIES
187
+	) {
188
+		return self::$_instance->registerDependencies($class, $dependencies, $overwrite);
189
+	}
190
+
191
+
192
+
193
+	/**
194
+	 * Assigns an array of class names and corresponding load sources (new or cached)
195
+	 * to the class specified by the first parameter.
196
+	 * IMPORTANT !!!
197
+	 * The order of elements in the incoming $dependencies array MUST match
198
+	 * the order of the constructor parameters for the class in question.
199
+	 * This is especially important when overriding any existing dependencies that are registered.
200
+	 * the third parameter controls whether any duplicate dependencies are overwritten or not.
201
+	 *
202
+	 * @param string $class
203
+	 * @param array  $dependencies
204
+	 * @param int    $overwrite
205
+	 * @return bool
206
+	 */
207
+	public function registerDependencies(
208
+		$class,
209
+		array $dependencies,
210
+		$overwrite = EE_Dependency_Map::KEEP_EXISTING_DEPENDENCIES
211
+	) {
212
+		$class = trim($class, '\\');
213
+		$registered = false;
214
+		if (empty(self::$_instance->_dependency_map[ $class ])) {
215
+			self::$_instance->_dependency_map[ $class ] = array();
216
+		}
217
+		// we need to make sure that any aliases used when registering a dependency
218
+		// get resolved to the correct class name
219
+		foreach ($dependencies as $dependency => $load_source) {
220
+			$alias = self::$_instance->get_alias($dependency);
221
+			if (
222
+				$overwrite === EE_Dependency_Map::OVERWRITE_DEPENDENCIES
223
+				|| ! isset(self::$_instance->_dependency_map[ $class ][ $alias ])
224
+			) {
225
+				unset($dependencies[$dependency]);
226
+				$dependencies[$alias] = $load_source;
227
+				$registered = true;
228
+			}
229
+		}
230
+		// now add our two lists of dependencies together.
231
+		// using Union (+=) favours the arrays in precedence from left to right,
232
+		// so $dependencies is NOT overwritten because it is listed first
233
+		// ie: with A = B + C, entries in B take precedence over duplicate entries in C
234
+		// Union is way faster than array_merge() but should be used with caution...
235
+		// especially with numerically indexed arrays
236
+		$dependencies += self::$_instance->_dependency_map[ $class ];
237
+		// now we need to ensure that the resulting dependencies
238
+		// array only has the entries that are required for the class
239
+		// so first count how many dependencies were originally registered for the class
240
+		$dependency_count = count(self::$_instance->_dependency_map[ $class ]);
241
+		// if that count is non-zero (meaning dependencies were already registered)
242
+		self::$_instance->_dependency_map[ $class ] = $dependency_count
243
+			// then truncate the  final array to match that count
244
+			? array_slice($dependencies, 0, $dependency_count)
245
+			// otherwise just take the incoming array because nothing previously existed
246
+			: $dependencies;
247
+		return $registered;
248
+	}
249
+
250
+
251
+
252
+	/**
253
+	 * @param string $class_name
254
+	 * @param string $loader
255
+	 * @return bool
256
+	 * @throws DomainException
257
+	 */
258
+	public static function register_class_loader($class_name, $loader = 'load_core')
259
+	{
260
+		if (! $loader instanceof Closure && strpos($class_name, '\\') !== false) {
261
+			throw new DomainException(
262
+				esc_html__('Don\'t use class loaders for FQCNs.', 'event_espresso')
263
+			);
264
+		}
265
+		// check that loader is callable or method starts with "load_" and exists in EE_Registry
266
+		if (
267
+			! is_callable($loader)
268
+			&& (
269
+				strpos($loader, 'load_') !== 0
270
+				|| ! method_exists('EE_Registry', $loader)
271
+			)
272
+		) {
273
+			throw new DomainException(
274
+				sprintf(
275
+					esc_html__(
276
+						'"%1$s" is not a valid loader method on EE_Registry.',
277
+						'event_espresso'
278
+					),
279
+					$loader
280
+				)
281
+			);
282
+		}
283
+		$class_name = self::$_instance->get_alias($class_name);
284
+		if (! isset(self::$_instance->_class_loaders[$class_name])) {
285
+			self::$_instance->_class_loaders[$class_name] = $loader;
286
+			return true;
287
+		}
288
+		return false;
289
+	}
290
+
291
+
292
+
293
+	/**
294
+	 * @return array
295
+	 */
296
+	public function dependency_map()
297
+	{
298
+		return $this->_dependency_map;
299
+	}
300
+
301
+
302
+
303
+	/**
304
+	 * returns TRUE if dependency map contains a listing for the provided class name
305
+	 *
306
+	 * @param string $class_name
307
+	 * @return boolean
308
+	 */
309
+	public function has($class_name = '')
310
+	{
311
+		// all legacy models have the same dependencies
312
+		if (strpos($class_name, 'EEM_') === 0) {
313
+			$class_name = 'LEGACY_MODELS';
314
+		}
315
+		return isset($this->_dependency_map[$class_name]) ? true : false;
316
+	}
317
+
318
+
319
+
320
+	/**
321
+	 * returns TRUE if dependency map contains a listing for the provided class name AND dependency
322
+	 *
323
+	 * @param string $class_name
324
+	 * @param string $dependency
325
+	 * @return bool
326
+	 */
327
+	public function has_dependency_for_class($class_name = '', $dependency = '')
328
+	{
329
+		// all legacy models have the same dependencies
330
+		if (strpos($class_name, 'EEM_') === 0) {
331
+			$class_name = 'LEGACY_MODELS';
332
+		}
333
+		$dependency = $this->get_alias($dependency);
334
+		return isset($this->_dependency_map[$class_name][$dependency])
335
+			? true
336
+			: false;
337
+	}
338
+
339
+
340
+
341
+	/**
342
+	 * returns loading strategy for whether a previously cached dependency should be loaded or a new instance returned
343
+	 *
344
+	 * @param string $class_name
345
+	 * @param string $dependency
346
+	 * @return int
347
+	 */
348
+	public function loading_strategy_for_class_dependency($class_name = '', $dependency = '')
349
+	{
350
+		// all legacy models have the same dependencies
351
+		if (strpos($class_name, 'EEM_') === 0) {
352
+			$class_name = 'LEGACY_MODELS';
353
+		}
354
+		$dependency = $this->get_alias($dependency);
355
+		return $this->has_dependency_for_class($class_name, $dependency)
356
+			? $this->_dependency_map[$class_name][$dependency]
357
+			: EE_Dependency_Map::not_registered;
358
+	}
359
+
360
+
361
+
362
+	/**
363
+	 * @param string $class_name
364
+	 * @return string | Closure
365
+	 */
366
+	public function class_loader($class_name)
367
+	{
368
+		// all legacy models use load_model()
369
+		if(strpos($class_name, 'EEM_') === 0){
370
+			return 'load_model';
371
+		}
372
+		$class_name = $this->get_alias($class_name);
373
+		return isset($this->_class_loaders[$class_name]) ? $this->_class_loaders[$class_name] : '';
374
+	}
375
+
376
+
377
+
378
+	/**
379
+	 * @return array
380
+	 */
381
+	public function class_loaders()
382
+	{
383
+		return $this->_class_loaders;
384
+	}
385
+
386
+
387
+
388
+	/**
389
+	 * adds an alias for a classname
390
+	 *
391
+	 * @param string $class_name the class name that should be used (concrete class to replace interface)
392
+	 * @param string $alias      the class name that would be type hinted for (abstract parent or interface)
393
+	 * @param string $for_class  the class that has the dependency (is type hinting for the interface)
394
+	 */
395
+	public function add_alias($class_name, $alias, $for_class = '')
396
+	{
397
+		if ($for_class !== '') {
398
+			if (! isset($this->_aliases[$for_class])) {
399
+				$this->_aliases[$for_class] = array();
400
+			}
401
+			$this->_aliases[$for_class][$class_name] = $alias;
402
+		}
403
+		$this->_aliases[$class_name] = $alias;
404
+	}
405
+
406
+
407
+
408
+	/**
409
+	 * returns TRUE if the provided class name has an alias
410
+	 *
411
+	 * @param string $class_name
412
+	 * @param string $for_class
413
+	 * @return bool
414
+	 */
415
+	public function has_alias($class_name = '', $for_class = '')
416
+	{
417
+		return isset($this->_aliases[$for_class][$class_name])
418
+			   || (
419
+				   isset($this->_aliases[$class_name])
420
+				   && ! is_array($this->_aliases[$class_name])
421
+			   );
422
+	}
423
+
424
+
425
+
426
+	/**
427
+	 * returns alias for class name if one exists, otherwise returns the original classname
428
+	 * functions recursively, so that multiple aliases can be used to drill down to a classname
429
+	 *  for example:
430
+	 *      if the following two entries were added to the _aliases array:
431
+	 *          array(
432
+	 *              'interface_alias'           => 'some\namespace\interface'
433
+	 *              'some\namespace\interface'  => 'some\namespace\classname'
434
+	 *          )
435
+	 *      then one could use EE_Registry::instance()->create( 'interface_alias' )
436
+	 *      to load an instance of 'some\namespace\classname'
437
+	 *
438
+	 * @param string $class_name
439
+	 * @param string $for_class
440
+	 * @return string
441
+	 */
442
+	public function get_alias($class_name = '', $for_class = '')
443
+	{
444
+		if (! $this->has_alias($class_name, $for_class)) {
445
+			return $class_name;
446
+		}
447
+		if ($for_class !== '' && isset($this->_aliases[ $for_class ][ $class_name ])) {
448
+			return $this->get_alias($this->_aliases[$for_class][$class_name], $for_class);
449
+		}
450
+		return $this->get_alias($this->_aliases[$class_name]);
451
+	}
452
+
453
+
454
+
455
+	/**
456
+	 * Registers the core dependencies and whether a previously instantiated object should be loaded from the cache,
457
+	 * if one exists, or whether a new object should be generated every time the requested class is loaded.
458
+	 * This is done by using the following class constants:
459
+	 *        EE_Dependency_Map::load_from_cache - loads previously instantiated object
460
+	 *        EE_Dependency_Map::load_new_object - generates a new object every time
461
+	 */
462
+	protected function _register_core_dependencies()
463
+	{
464
+		$this->_dependency_map = array(
465
+			'EE_Request_Handler'                                                                                          => array(
466
+				'EE_Request' => EE_Dependency_Map::load_from_cache,
467
+			),
468
+			'EE_System'                                                                                                   => array(
469
+				'EE_Registry'                                 => EE_Dependency_Map::load_from_cache,
470
+				'EventEspresso\core\services\loaders\Loader'  => EE_Dependency_Map::load_from_cache,
471
+				'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
472
+				'EE_Maintenance_Mode'                         => EE_Dependency_Map::load_from_cache,
473
+			),
474
+			'EE_Session'                                                                                                  => array(
475
+				'EventEspresso\core\services\cache\TransientCacheStorage'  => EE_Dependency_Map::load_from_cache,
476
+				'EventEspresso\core\domain\values\session\SessionLifespan' => EE_Dependency_Map::load_from_cache,
477
+				'EventEspresso\core\services\request\Request'              => EE_Dependency_Map::load_from_cache,
478
+				'EE_Encryption'                                            => EE_Dependency_Map::load_from_cache,
479
+			),
480
+			'EE_Cart'                                                                                                     => array(
481
+				'EE_Session' => EE_Dependency_Map::load_from_cache,
482
+			),
483
+			'EE_Front_Controller'                                                                                         => array(
484
+				'EE_Registry'              => EE_Dependency_Map::load_from_cache,
485
+				'EE_Request_Handler'       => EE_Dependency_Map::load_from_cache,
486
+				'EE_Module_Request_Router' => EE_Dependency_Map::load_from_cache,
487
+			),
488
+			'EE_Messenger_Collection_Loader'                                                                              => array(
489
+				'EE_Messenger_Collection' => EE_Dependency_Map::load_new_object,
490
+			),
491
+			'EE_Message_Type_Collection_Loader'                                                                           => array(
492
+				'EE_Message_Type_Collection' => EE_Dependency_Map::load_new_object,
493
+			),
494
+			'EE_Message_Resource_Manager'                                                                                 => array(
495
+				'EE_Messenger_Collection_Loader'    => EE_Dependency_Map::load_new_object,
496
+				'EE_Message_Type_Collection_Loader' => EE_Dependency_Map::load_new_object,
497
+				'EEM_Message_Template_Group'        => EE_Dependency_Map::load_from_cache,
498
+			),
499
+			'EE_Message_Factory'                                                                                          => array(
500
+				'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
501
+			),
502
+			'EE_messages'                                                                                                 => array(
503
+				'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
504
+			),
505
+			'EE_Messages_Generator'                                                                                       => array(
506
+				'EE_Messages_Queue'                    => EE_Dependency_Map::load_new_object,
507
+				'EE_Messages_Data_Handler_Collection'  => EE_Dependency_Map::load_new_object,
508
+				'EE_Message_Template_Group_Collection' => EE_Dependency_Map::load_new_object,
509
+				'EEH_Parse_Shortcodes'                 => EE_Dependency_Map::load_from_cache,
510
+			),
511
+			'EE_Messages_Processor'                                                                                       => array(
512
+				'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
513
+			),
514
+			'EE_Messages_Queue'                                                                                           => array(
515
+				'EE_Message_Repository' => EE_Dependency_Map::load_new_object,
516
+			),
517
+			'EE_Messages_Template_Defaults'                                                                               => array(
518
+				'EEM_Message_Template_Group' => EE_Dependency_Map::load_from_cache,
519
+				'EEM_Message_Template'       => EE_Dependency_Map::load_from_cache,
520
+			),
521
+			'EE_Message_To_Generate_From_Request'                                                                         => array(
522
+				'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
523
+				'EE_Request_Handler'          => EE_Dependency_Map::load_from_cache,
524
+			),
525
+			'EventEspresso\core\services\commands\CommandBus'                                                             => array(
526
+				'EventEspresso\core\services\commands\CommandHandlerManager' => EE_Dependency_Map::load_from_cache,
527
+			),
528
+			'EventEspresso\services\commands\CommandHandler'                                                              => array(
529
+				'EE_Registry'         => EE_Dependency_Map::load_from_cache,
530
+				'CommandBusInterface' => EE_Dependency_Map::load_from_cache,
531
+			),
532
+			'EventEspresso\core\services\commands\CommandHandlerManager'                                                  => array(
533
+				'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
534
+			),
535
+			'EventEspresso\core\services\commands\CompositeCommandHandler'                                                => array(
536
+				'EventEspresso\core\services\commands\CommandBus'     => EE_Dependency_Map::load_from_cache,
537
+				'EventEspresso\core\services\commands\CommandFactory' => EE_Dependency_Map::load_from_cache,
538
+			),
539
+			'EventEspresso\core\services\commands\CommandFactory'                                                         => array(
540
+				'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
541
+			),
542
+			'EventEspresso\core\services\commands\middleware\CapChecker'                                                  => array(
543
+				'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker' => EE_Dependency_Map::load_from_cache,
544
+			),
545
+			'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker'                                         => array(
546
+				'EE_Capabilities' => EE_Dependency_Map::load_from_cache,
547
+			),
548
+			'EventEspresso\core\domain\services\capabilities\RegistrationsCapChecker'                                     => array(
549
+				'EE_Capabilities' => EE_Dependency_Map::load_from_cache,
550
+			),
551
+			'EventEspresso\core\services\commands\registration\CreateRegistrationCommandHandler'                          => array(
552
+				'EventEspresso\core\domain\services\registration\CreateRegistrationService' => EE_Dependency_Map::load_from_cache,
553
+			),
554
+			'EventEspresso\core\services\commands\registration\CopyRegistrationDetailsCommandHandler'                     => array(
555
+				'EventEspresso\core\domain\services\registration\CopyRegistrationService' => EE_Dependency_Map::load_from_cache,
556
+			),
557
+			'EventEspresso\core\services\commands\registration\CopyRegistrationPaymentsCommandHandler'                    => array(
558
+				'EventEspresso\core\domain\services\registration\CopyRegistrationService' => EE_Dependency_Map::load_from_cache,
559
+			),
560
+			'EventEspresso\core\services\commands\registration\CancelRegistrationAndTicketLineItemCommandHandler'         => array(
561
+				'EventEspresso\core\domain\services\registration\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache,
562
+			),
563
+			'EventEspresso\core\services\commands\registration\UpdateRegistrationAndTransactionAfterChangeCommandHandler' => array(
564
+				'EventEspresso\core\domain\services\registration\UpdateRegistrationService' => EE_Dependency_Map::load_from_cache,
565
+			),
566
+			'EventEspresso\core\services\commands\ticket\CreateTicketLineItemCommandHandler'                              => array(
567
+				'EventEspresso\core\domain\services\ticket\CreateTicketLineItemService' => EE_Dependency_Map::load_from_cache,
568
+			),
569
+			'EventEspresso\core\services\commands\ticket\CancelTicketLineItemCommandHandler'                              => array(
570
+				'EventEspresso\core\domain\services\ticket\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache,
571
+			),
572
+			'EventEspresso\core\domain\services\registration\CancelRegistrationService'                                   => array(
573
+				'EventEspresso\core\domain\services\ticket\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache,
574
+			),
575
+			'EventEspresso\core\services\commands\attendee\CreateAttendeeCommandHandler'                                  => array(
576
+				'EEM_Attendee' => EE_Dependency_Map::load_from_cache,
577
+			),
578
+			'EventEspresso\core\services\database\TableManager'                                                           => array(
579
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
580
+			),
581
+			'EE_Data_Migration_Class_Base'                                                                                => array(
582
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
583
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
584
+			),
585
+			'EE_DMS_Core_4_1_0'                                                                                           => array(
586
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
587
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
588
+			),
589
+			'EE_DMS_Core_4_2_0'                                                                                           => array(
590
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
591
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
592
+			),
593
+			'EE_DMS_Core_4_3_0'                                                                                           => array(
594
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
595
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
596
+			),
597
+			'EE_DMS_Core_4_4_0'                                                                                           => array(
598
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
599
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
600
+			),
601
+			'EE_DMS_Core_4_5_0'                                                                                           => array(
602
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
603
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
604
+			),
605
+			'EE_DMS_Core_4_6_0'                                                                                           => array(
606
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
607
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
608
+			),
609
+			'EE_DMS_Core_4_7_0'                                                                                           => array(
610
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
611
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
612
+			),
613
+			'EE_DMS_Core_4_8_0'                                                                                           => array(
614
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
615
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
616
+			),
617
+			'EE_DMS_Core_4_9_0'                                                                                           => array(
618
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
619
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
620
+			),
621
+			'EventEspresso\core\services\assets\Registry'                                                                 => array(
622
+				'EE_Template_Config' => EE_Dependency_Map::load_from_cache,
623
+				'EE_Currency_Config' => EE_Dependency_Map::load_from_cache,
624
+				'EventEspresso\core\domain\Domain' => EE_Dependency_Map::load_from_cache
625
+			),
626
+			'EventEspresso\core\domain\entities\shortcodes\EspressoCancelled'                                             => array(
627
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
628
+			),
629
+			'EventEspresso\core\domain\entities\shortcodes\EspressoCheckout'                                              => array(
630
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
631
+			),
632
+			'EventEspresso\core\domain\entities\shortcodes\EspressoEventAttendees'                                        => array(
633
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
634
+			),
635
+			'EventEspresso\core\domain\entities\shortcodes\EspressoEvents'                                                => array(
636
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
637
+			),
638
+			'EventEspresso\core\domain\entities\shortcodes\EspressoThankYou'                                              => array(
639
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
640
+			),
641
+			'EventEspresso\core\domain\entities\shortcodes\EspressoTicketSelector'                                        => array(
642
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
643
+			),
644
+			'EventEspresso\core\domain\entities\shortcodes\EspressoTxnPage'                                               => array(
645
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
646
+			),
647
+			'EventEspresso\core\services\cache\BasicCacheManager'                        => array(
648
+				'EventEspresso\core\services\cache\TransientCacheStorage' => EE_Dependency_Map::load_from_cache,
649
+			),
650
+			'EventEspresso\core\services\cache\PostRelatedCacheManager'                  => array(
651
+				'EventEspresso\core\services\cache\TransientCacheStorage' => EE_Dependency_Map::load_from_cache,
652
+			),
653
+			'EventEspresso\core\domain\services\validation\email\EmailValidationService' => array(
654
+				'EE_Registration_Config'                                  => EE_Dependency_Map::load_from_cache,
655
+				'EventEspresso\core\services\loaders\Loader'              => EE_Dependency_Map::load_from_cache,
656
+			),
657
+			'EventEspresso\core\domain\values\EmailAddress'                              => array(
658
+				null,
659
+				'EventEspresso\core\domain\services\validation\email\EmailValidationService' => EE_Dependency_Map::load_from_cache,
660
+			),
661
+			'EventEspresso\core\services\orm\ModelFieldFactory' => array(
662
+				'EventEspresso\core\services\loaders\Loader'              => EE_Dependency_Map::load_from_cache,
663
+			),
664
+			'LEGACY_MODELS'                                                   => array(
665
+				null,
666
+				'EventEspresso\core\services\database\ModelFieldFactory' => EE_Dependency_Map::load_from_cache,
667
+			),
668
+			'EE_Module_Request_Router' => array(
669
+				'EE_Request' => EE_Dependency_Map::load_from_cache,
670
+			),
671
+			'EE_Registration_Processor' => array(
672
+				'EE_Request' => EE_Dependency_Map::load_from_cache,
673
+			),
674
+			'EventEspresso\core\services\notifications\PersistentAdminNoticeManager' => array(
675
+				null,
676
+				'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker' => EE_Dependency_Map::load_from_cache,
677
+				'EE_Request' => EE_Dependency_Map::load_from_cache,
678
+			),
679
+			'EE_Admin_Transactions_List_Table' => array(
680
+				null,
681
+				'EventEspresso\core\domain\values\session\SessionLifespan' => EE_Dependency_Map::load_from_cache,
682
+			),
683
+		);
684
+	}
685
+
686
+
687
+
688
+	/**
689
+	 * Registers how core classes are loaded.
690
+	 * This can either be done by simply providing the name of one of the EE_Registry loader methods such as:
691
+	 *        'EE_Request_Handler' => 'load_core'
692
+	 *        'EE_Messages_Queue'  => 'load_lib'
693
+	 *        'EEH_Debug_Tools'    => 'load_helper'
694
+	 * or, if greater control is required, by providing a custom closure. For example:
695
+	 *        'Some_Class' => function () {
696
+	 *            return new Some_Class();
697
+	 *        },
698
+	 * This is required for instantiating dependencies
699
+	 * where an interface has been type hinted in a class constructor. For example:
700
+	 *        'Required_Interface' => function () {
701
+	 *            return new A_Class_That_Implements_Required_Interface();
702
+	 *        },
703
+	 *
704
+	 * @throws InvalidInterfaceException
705
+	 * @throws InvalidDataTypeException
706
+	 * @throws InvalidArgumentException
707
+	 */
708
+	protected function _register_core_class_loaders()
709
+	{
710
+		//for PHP5.3 compat, we need to register any properties called here in a variable because `$this` cannot
711
+		//be used in a closure.
712
+		$request = &$this->request;
713
+		$response = &$this->response;
714
+		$legacy_request = &$this->legacy_request;
715
+		// $loader = &$this->loader;
716
+		$this->_class_loaders = array(
717
+			//load_core
718
+			'EE_Capabilities'          => 'load_core',
719
+			'EE_Encryption'            => 'load_core',
720
+			'EE_Front_Controller'      => 'load_core',
721
+			'EE_Module_Request_Router' => 'load_core',
722
+			'EE_Registry'              => 'load_core',
723
+			'EE_Request'               => function () use (&$legacy_request) {
724
+				return $legacy_request;
725
+			},
726
+			'EventEspresso\core\services\request\Request' => function () use (&$request) {
727
+				return $request;
728
+			},
729
+			'EventEspresso\core\services\request\Response' => function () use (&$response) {
730
+				return $response;
731
+			},
732
+			'EE_Request_Handler'       => 'load_core',
733
+			'EE_Session'               => 'load_core',
734
+			'EE_Cron_Tasks'            => 'load_core',
735
+			'EE_System'                => 'load_core',
736
+			'EE_Maintenance_Mode'      => 'load_core',
737
+			'EE_Register_CPTs'         => 'load_core',
738
+			'EE_Admin'                 => 'load_core',
739
+			//load_lib
740
+			'EE_Message_Resource_Manager'          => 'load_lib',
741
+			'EE_Message_Type_Collection'           => 'load_lib',
742
+			'EE_Message_Type_Collection_Loader'    => 'load_lib',
743
+			'EE_Messenger_Collection'              => 'load_lib',
744
+			'EE_Messenger_Collection_Loader'       => 'load_lib',
745
+			'EE_Messages_Processor'                => 'load_lib',
746
+			'EE_Message_Repository'                => 'load_lib',
747
+			'EE_Messages_Queue'                    => 'load_lib',
748
+			'EE_Messages_Data_Handler_Collection'  => 'load_lib',
749
+			'EE_Message_Template_Group_Collection' => 'load_lib',
750
+			'EE_Payment_Method_Manager'            => 'load_lib',
751
+			'EE_Messages_Generator'                => function () {
752
+				return EE_Registry::instance()->load_lib(
753
+					'Messages_Generator',
754
+					array(),
755
+					false,
756
+					false
757
+				);
758
+			},
759
+			'EE_Messages_Template_Defaults'        => function ($arguments = array()) {
760
+				return EE_Registry::instance()->load_lib(
761
+					'Messages_Template_Defaults',
762
+					$arguments,
763
+					false,
764
+					false
765
+				);
766
+			},
767
+			//load_model
768
+			// 'EEM_Attendee'                         => 'load_model',
769
+			// 'EEM_Message_Template_Group'           => 'load_model',
770
+			// 'EEM_Message_Template'                 => 'load_model',
771
+			//load_helper
772
+			'EEH_Parse_Shortcodes'                 => function () {
773
+				if (EE_Registry::instance()->load_helper('Parse_Shortcodes')) {
774
+					return new EEH_Parse_Shortcodes();
775
+				}
776
+				return null;
777
+			},
778
+			'EE_Template_Config'                   => function () {
779
+				return EE_Config::instance()->template_settings;
780
+			},
781
+			'EE_Currency_Config'                   => function () {
782
+				return EE_Config::instance()->currency;
783
+			},
784
+			'EE_Registration_Config'                   => function () {
785
+				return EE_Config::instance()->registration;
786
+			},
787
+			'EventEspresso\core\services\loaders\Loader' => function () {
788
+				return LoaderFactory::getLoader();
789
+			},
790
+		);
791
+	}
792
+
793
+
794
+
795
+	/**
796
+	 * can be used for supplying alternate names for classes,
797
+	 * or for connecting interface names to instantiable classes
798
+	 */
799
+	protected function _register_core_aliases()
800
+	{
801
+		$this->_aliases = array(
802
+			'CommandBusInterface'                                                          => 'EventEspresso\core\services\commands\CommandBusInterface',
803
+			'EventEspresso\core\services\commands\CommandBusInterface'                     => 'EventEspresso\core\services\commands\CommandBus',
804
+			'CommandHandlerManagerInterface'                                               => 'EventEspresso\core\services\commands\CommandHandlerManagerInterface',
805
+			'EventEspresso\core\services\commands\CommandHandlerManagerInterface'          => 'EventEspresso\core\services\commands\CommandHandlerManager',
806
+			'CapChecker'                                                                   => 'EventEspresso\core\services\commands\middleware\CapChecker',
807
+			'AddActionHook'                                                                => 'EventEspresso\core\services\commands\middleware\AddActionHook',
808
+			'CapabilitiesChecker'                                                          => 'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker',
809
+			'CapabilitiesCheckerInterface'                                                 => 'EventEspresso\core\domain\services\capabilities\CapabilitiesCheckerInterface',
810
+			'EventEspresso\core\domain\services\capabilities\CapabilitiesCheckerInterface' => 'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker',
811
+			'CreateRegistrationService'                                                    => 'EventEspresso\core\domain\services\registration\CreateRegistrationService',
812
+			'CreateRegCodeCommandHandler'                                                  => 'EventEspresso\core\services\commands\registration\CreateRegCodeCommand',
813
+			'CreateRegUrlLinkCommandHandler'                                               => 'EventEspresso\core\services\commands\registration\CreateRegUrlLinkCommand',
814
+			'CreateRegistrationCommandHandler'                                             => 'EventEspresso\core\services\commands\registration\CreateRegistrationCommand',
815
+			'CopyRegistrationDetailsCommandHandler'                                        => 'EventEspresso\core\services\commands\registration\CopyRegistrationDetailsCommand',
816
+			'CopyRegistrationPaymentsCommandHandler'                                       => 'EventEspresso\core\services\commands\registration\CopyRegistrationPaymentsCommand',
817
+			'CancelRegistrationAndTicketLineItemCommandHandler'                            => 'EventEspresso\core\services\commands\registration\CancelRegistrationAndTicketLineItemCommandHandler',
818
+			'UpdateRegistrationAndTransactionAfterChangeCommandHandler'                    => 'EventEspresso\core\services\commands\registration\UpdateRegistrationAndTransactionAfterChangeCommandHandler',
819
+			'CreateTicketLineItemCommandHandler'                                           => 'EventEspresso\core\services\commands\ticket\CreateTicketLineItemCommand',
820
+			'CreateTransactionCommandHandler'                                     => 'EventEspresso\core\services\commands\transaction\CreateTransactionCommandHandler',
821
+			'CreateAttendeeCommandHandler'                                        => 'EventEspresso\core\services\commands\attendee\CreateAttendeeCommandHandler',
822
+			'TableManager'                                                                 => 'EventEspresso\core\services\database\TableManager',
823
+			'TableAnalysis'                                                                => 'EventEspresso\core\services\database\TableAnalysis',
824
+			'EspressoShortcode'                                                            => 'EventEspresso\core\services\shortcodes\EspressoShortcode',
825
+			'ShortcodeInterface'                                                           => 'EventEspresso\core\services\shortcodes\ShortcodeInterface',
826
+			'EventEspresso\core\services\shortcodes\ShortcodeInterface'                    => 'EventEspresso\core\services\shortcodes\EspressoShortcode',
827
+			'EventEspresso\core\services\cache\CacheStorageInterface'                      => 'EventEspresso\core\services\cache\TransientCacheStorage',
828
+			'LoaderInterface'                                                              => 'EventEspresso\core\services\loaders\LoaderInterface',
829
+			'EventEspresso\core\services\loaders\LoaderInterface'                          => 'EventEspresso\core\services\loaders\Loader',
830
+			'CommandFactoryInterface'                                                     => 'EventEspresso\core\services\commands\CommandFactoryInterface',
831
+			'EventEspresso\core\services\commands\CommandFactoryInterface'                => 'EventEspresso\core\services\commands\CommandFactory',
832
+			'EventEspresso\core\domain\services\session\SessionIdentifierInterface'       => 'EE_Session',
833
+			'EmailValidatorInterface'                                                     => 'EventEspresso\core\domain\services\validation\email\EmailValidatorInterface',
834
+			'EventEspresso\core\domain\services\validation\email\EmailValidatorInterface' => 'EventEspresso\core\domain\services\validation\email\EmailValidationService',
835
+			'NoticeConverterInterface'                                            => 'EventEspresso\core\services\notices\NoticeConverterInterface',
836
+			'EventEspresso\core\services\notices\NoticeConverterInterface'        => 'EventEspresso\core\services\notices\ConvertNoticesToEeErrors',
837
+			'NoticesContainerInterface'                                           => 'EventEspresso\core\services\notices\NoticesContainerInterface',
838
+			'EventEspresso\core\services\notices\NoticesContainerInterface'       => 'EventEspresso\core\services\notices\NoticesContainer',
839
+			'EventEspresso\core\services\request\RequestInterface'                => 'EventEspresso\core\services\request\Request',
840
+			'EventEspresso\core\services\request\ResponseInterface'               => 'EventEspresso\core\services\request\Response',
841
+			'EventEspresso\core\domain\DomainInterface'                           => 'EventEspresso\core\domain\Domain',
842
+		);
843
+		if (! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) {
844
+			$this->_aliases['EventEspresso\core\services\notices\NoticeConverterInterface'] = 'EventEspresso\core\services\notices\ConvertNoticesToAdminNotices';
845
+		}
846
+	}
847
+
848
+
849
+
850
+	/**
851
+	 * This is used to reset the internal map and class_loaders to their original default state at the beginning of the
852
+	 * request Primarily used by unit tests.
853
+	 *
854
+	 * @throws InvalidDataTypeException
855
+	 * @throws InvalidInterfaceException
856
+	 * @throws InvalidArgumentException
857
+	 */
858
+	public function reset()
859
+	{
860
+		$this->_register_core_class_loaders();
861
+		$this->_register_core_dependencies();
862
+	}
863 863
 
864 864
 
865 865
 }
Please login to merge, or discard this patch.
core/EE_Session.core.php 2 patches
Indentation   +1179 added lines, -1179 removed lines patch added patch discarded remove patch
@@ -22,1180 +22,1180 @@  discard block
 block discarded – undo
22 22
 class EE_Session implements SessionIdentifierInterface
23 23
 {
24 24
 
25
-    const session_id_prefix    = 'ee_ssn_';
26
-
27
-    const hash_check_prefix    = 'ee_shc_';
28
-
29
-    const OPTION_NAME_SETTINGS = 'ee_session_settings';
30
-
31
-    /**
32
-     * instance of the EE_Session object
33
-     *
34
-     * @var EE_Session
35
-     */
36
-    private static $_instance;
37
-
38
-    /**
39
-     * @var CacheStorageInterface $cache_storage
40
-     */
41
-    protected $cache_storage;
42
-
43
-    /**
44
-     * EE_Encryption object
45
-     *
46
-     * @var EE_Encryption
47
-     */
48
-    protected $encryption;
49
-
50
-    /**
51
-     * the session id
52
-     *
53
-     * @var string
54
-     */
55
-    private $_sid;
56
-
57
-    /**
58
-     * session id salt
59
-     *
60
-     * @var string
61
-     */
62
-    private $_sid_salt;
63
-
64
-    /**
65
-     * session data
66
-     *
67
-     * @var array
68
-     */
69
-    private $_session_data = array();
70
-
71
-    /**
72
-     * how long an EE session lasts
73
-     * default session lifespan of 1 hour (for not so instant IPNs)
74
-     *
75
-     * @var SessionLifespan $session_lifespan
76
-     */
77
-    private $session_lifespan;
78
-
79
-    /**
80
-     * session expiration time as Unix timestamp in GMT
81
-     *
82
-     * @var int
83
-     */
84
-    private $_expiration;
85
-
86
-    /**
87
-     * whether or not session has expired at some point
88
-     *
89
-     * @var boolean
90
-     */
91
-    private $_expired = false;
92
-
93
-    /**
94
-     * current time as Unix timestamp in GMT
95
-     *
96
-     * @var int
97
-     */
98
-    private $_time;
99
-
100
-    /**
101
-     * whether to encrypt session data
102
-     *
103
-     * @var bool
104
-     */
105
-    private $_use_encryption;
106
-
107
-    /**
108
-     * well... according to the server...
109
-     *
110
-     * @var null
111
-     */
112
-    private $_user_agent;
113
-
114
-    /**
115
-     * do you really trust the server ?
116
-     *
117
-     * @var null
118
-     */
119
-    private $_ip_address;
120
-
121
-    /**
122
-     * current WP user_id
123
-     *
124
-     * @var null
125
-     */
126
-    private $_wp_user_id;
127
-
128
-    /**
129
-     * array for defining default session vars
130
-     *
131
-     * @var array
132
-     */
133
-    private $_default_session_vars = array(
134
-        'id'            => null,
135
-        'user_id'       => null,
136
-        'ip_address'    => null,
137
-        'user_agent'    => null,
138
-        'init_access'   => null,
139
-        'last_access'   => null,
140
-        'expiration'    => null,
141
-        'pages_visited' => array(),
142
-    );
143
-
144
-    /**
145
-     * timestamp for when last garbage collection cycle was performed
146
-     *
147
-     * @var int $_last_gc
148
-     */
149
-    private $_last_gc;
150
-
151
-    /**
152
-     * @var RequestInterface $request
153
-     */
154
-    protected $request;
155
-
156
-
157
-    /**
158
-     * @singleton method used to instantiate class object
159
-     * @param CacheStorageInterface $cache_storage
160
-     * @param SessionLifespan|null  $lifespan
161
-     * @param RequestInterface      $request
162
-     * @param EE_Encryption         $encryption
163
-     * @return EE_Session
164
-     * @throws InvalidArgumentException
165
-     * @throws InvalidDataTypeException
166
-     * @throws InvalidInterfaceException
167
-     */
168
-    public static function instance(
169
-        CacheStorageInterface $cache_storage = null,
170
-        SessionLifespan $lifespan = null,
171
-        RequestInterface $request = null,
172
-        EE_Encryption $encryption = null
173
-    ) {
174
-        // check if class object is instantiated
175
-        // session loading is turned ON by default, but prior to the init hook, can be turned back OFF via:
176
-        // add_filter( 'FHEE_load_EE_Session', '__return_false' );
177
-        if (! self::$_instance instanceof EE_Session && apply_filters('FHEE_load_EE_Session', true)) {
178
-            self::$_instance = new self(
179
-                $cache_storage,
180
-                $lifespan,
181
-                $request,
182
-                $encryption
183
-            );
184
-        }
185
-        return self::$_instance;
186
-    }
187
-
188
-
189
-    /**
190
-     * protected constructor to prevent direct creation
191
-     *
192
-     * @param CacheStorageInterface $cache_storage
193
-     * @param SessionLifespan       $lifespan
194
-     * @param RequestInterface      $request
195
-     * @param EE_Encryption         $encryption
196
-     * @throws InvalidArgumentException
197
-     * @throws InvalidDataTypeException
198
-     * @throws InvalidInterfaceException
199
-     */
200
-    protected function __construct(
201
-        CacheStorageInterface $cache_storage,
202
-        SessionLifespan $lifespan,
203
-        RequestInterface $request,
204
-        EE_Encryption $encryption = null
205
-    ) {
206
-        // session loading is turned ON by default, but prior to the init hook, can be turned back OFF via: add_filter( 'FHEE_load_EE_Session', '__return_false' );
207
-        if (! apply_filters('FHEE_load_EE_Session', true)) {
208
-            return;
209
-        }
210
-        $this->session_lifespan = $lifespan;
211
-        $this->request          = $request;
212
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
213
-        if (! defined('ESPRESSO_SESSION')) {
214
-            define('ESPRESSO_SESSION', true);
215
-        }
216
-        // retrieve session options from db
217
-        $session_settings = (array) get_option(EE_Session::OPTION_NAME_SETTINGS, array());
218
-        if (! empty($session_settings)) {
219
-            // cycle though existing session options
220
-            foreach ($session_settings as $var_name => $session_setting) {
221
-                // set values for class properties
222
-                $var_name          = '_' . $var_name;
223
-                $this->{$var_name} = $session_setting;
224
-            }
225
-        }
226
-        $this->cache_storage = $cache_storage;
227
-        // are we using encryption?
228
-        $this->_use_encryption = $encryption instanceof EE_Encryption
229
-                                 && EE_Registry::instance()->CFG->admin->encode_session_data();
230
-        // \EEH_Debug_Tools::printr($this->_use_encryption, '$this->_use_encryption', __FILE__, __LINE__);
231
-        // encrypt data via: $this->encryption->encrypt();
232
-        $this->encryption = $encryption;
233
-        // filter hook allows outside functions/classes/plugins to change default empty cart
234
-        $extra_default_session_vars = apply_filters('FHEE__EE_Session__construct__extra_default_session_vars', array());
235
-        array_merge($this->_default_session_vars, $extra_default_session_vars);
236
-        // apply default session vars
237
-        $this->_set_defaults();
238
-        add_action('AHEE__EE_System__initialize', array($this, 'open_session'));
239
-        // check request for 'clear_session' param
240
-        add_action('AHEE__EE_Request_Handler__construct__complete', array($this, 'wp_loaded'));
241
-        // once everything is all said and done,
242
-        add_action('shutdown', array($this, 'update'), 100);
243
-        add_action('shutdown', array($this, 'garbageCollection'), 1000);
244
-        $this->configure_garbage_collection_filters();
245
-    }
246
-
247
-
248
-
249
-    /**
250
-     * @return void
251
-     * @throws EE_Error
252
-     * @throws InvalidArgumentException
253
-     * @throws InvalidDataTypeException
254
-     * @throws InvalidInterfaceException
255
-     * @throws InvalidSessionDataException
256
-     */
257
-    public function open_session()
258
-    {
259
-        // check for existing session and retrieve it from db
260
-        if (! $this->_espresso_session()) {
261
-            // or just start a new one
262
-            $this->_create_espresso_session();
263
-        }
264
-    }
265
-
266
-
267
-
268
-    /**
269
-     * @return bool
270
-     */
271
-    public function expired()
272
-    {
273
-        return $this->_expired;
274
-    }
275
-
276
-
277
-
278
-    /**
279
-     * @return void
280
-     */
281
-    public function reset_expired()
282
-    {
283
-        $this->_expired = false;
284
-    }
285
-
286
-
287
-    /**
288
-     * @return int
289
-     */
290
-    public function expiration()
291
-    {
292
-        return $this->_expiration;
293
-    }
294
-
295
-
296
-
297
-    /**
298
-     * @return int
299
-     */
300
-    public function extension()
301
-    {
302
-        return apply_filters('FHEE__EE_Session__extend_expiration__seconds_added', 10 * MINUTE_IN_SECONDS);
303
-    }
304
-
305
-
306
-
307
-    /**
308
-     * @param int $time number of seconds to add to session expiration
309
-     */
310
-    public function extend_expiration($time = 0)
311
-    {
312
-        $time              = $time ? $time : $this->extension();
313
-        $this->_expiration += absint($time);
314
-    }
315
-
316
-
317
-
318
-    /**
319
-     * @return int
320
-     */
321
-    public function lifespan()
322
-    {
323
-        return $this->session_lifespan->inSeconds();
324
-    }
325
-
326
-
327
-
328
-    /**
329
-     * This just sets some defaults for the _session data property
330
-     *
331
-     * @access private
332
-     * @return void
333
-     */
334
-    private function _set_defaults()
335
-    {
336
-        // set some defaults
337
-        foreach ($this->_default_session_vars as $key => $default_var) {
338
-            if (is_array($default_var)) {
339
-                $this->_session_data[ $key ] = array();
340
-            } else {
341
-                $this->_session_data[ $key ] = '';
342
-            }
343
-        }
344
-    }
25
+	const session_id_prefix    = 'ee_ssn_';
26
+
27
+	const hash_check_prefix    = 'ee_shc_';
28
+
29
+	const OPTION_NAME_SETTINGS = 'ee_session_settings';
30
+
31
+	/**
32
+	 * instance of the EE_Session object
33
+	 *
34
+	 * @var EE_Session
35
+	 */
36
+	private static $_instance;
37
+
38
+	/**
39
+	 * @var CacheStorageInterface $cache_storage
40
+	 */
41
+	protected $cache_storage;
42
+
43
+	/**
44
+	 * EE_Encryption object
45
+	 *
46
+	 * @var EE_Encryption
47
+	 */
48
+	protected $encryption;
49
+
50
+	/**
51
+	 * the session id
52
+	 *
53
+	 * @var string
54
+	 */
55
+	private $_sid;
56
+
57
+	/**
58
+	 * session id salt
59
+	 *
60
+	 * @var string
61
+	 */
62
+	private $_sid_salt;
63
+
64
+	/**
65
+	 * session data
66
+	 *
67
+	 * @var array
68
+	 */
69
+	private $_session_data = array();
70
+
71
+	/**
72
+	 * how long an EE session lasts
73
+	 * default session lifespan of 1 hour (for not so instant IPNs)
74
+	 *
75
+	 * @var SessionLifespan $session_lifespan
76
+	 */
77
+	private $session_lifespan;
78
+
79
+	/**
80
+	 * session expiration time as Unix timestamp in GMT
81
+	 *
82
+	 * @var int
83
+	 */
84
+	private $_expiration;
85
+
86
+	/**
87
+	 * whether or not session has expired at some point
88
+	 *
89
+	 * @var boolean
90
+	 */
91
+	private $_expired = false;
92
+
93
+	/**
94
+	 * current time as Unix timestamp in GMT
95
+	 *
96
+	 * @var int
97
+	 */
98
+	private $_time;
99
+
100
+	/**
101
+	 * whether to encrypt session data
102
+	 *
103
+	 * @var bool
104
+	 */
105
+	private $_use_encryption;
106
+
107
+	/**
108
+	 * well... according to the server...
109
+	 *
110
+	 * @var null
111
+	 */
112
+	private $_user_agent;
113
+
114
+	/**
115
+	 * do you really trust the server ?
116
+	 *
117
+	 * @var null
118
+	 */
119
+	private $_ip_address;
120
+
121
+	/**
122
+	 * current WP user_id
123
+	 *
124
+	 * @var null
125
+	 */
126
+	private $_wp_user_id;
127
+
128
+	/**
129
+	 * array for defining default session vars
130
+	 *
131
+	 * @var array
132
+	 */
133
+	private $_default_session_vars = array(
134
+		'id'            => null,
135
+		'user_id'       => null,
136
+		'ip_address'    => null,
137
+		'user_agent'    => null,
138
+		'init_access'   => null,
139
+		'last_access'   => null,
140
+		'expiration'    => null,
141
+		'pages_visited' => array(),
142
+	);
143
+
144
+	/**
145
+	 * timestamp for when last garbage collection cycle was performed
146
+	 *
147
+	 * @var int $_last_gc
148
+	 */
149
+	private $_last_gc;
150
+
151
+	/**
152
+	 * @var RequestInterface $request
153
+	 */
154
+	protected $request;
155
+
156
+
157
+	/**
158
+	 * @singleton method used to instantiate class object
159
+	 * @param CacheStorageInterface $cache_storage
160
+	 * @param SessionLifespan|null  $lifespan
161
+	 * @param RequestInterface      $request
162
+	 * @param EE_Encryption         $encryption
163
+	 * @return EE_Session
164
+	 * @throws InvalidArgumentException
165
+	 * @throws InvalidDataTypeException
166
+	 * @throws InvalidInterfaceException
167
+	 */
168
+	public static function instance(
169
+		CacheStorageInterface $cache_storage = null,
170
+		SessionLifespan $lifespan = null,
171
+		RequestInterface $request = null,
172
+		EE_Encryption $encryption = null
173
+	) {
174
+		// check if class object is instantiated
175
+		// session loading is turned ON by default, but prior to the init hook, can be turned back OFF via:
176
+		// add_filter( 'FHEE_load_EE_Session', '__return_false' );
177
+		if (! self::$_instance instanceof EE_Session && apply_filters('FHEE_load_EE_Session', true)) {
178
+			self::$_instance = new self(
179
+				$cache_storage,
180
+				$lifespan,
181
+				$request,
182
+				$encryption
183
+			);
184
+		}
185
+		return self::$_instance;
186
+	}
187
+
188
+
189
+	/**
190
+	 * protected constructor to prevent direct creation
191
+	 *
192
+	 * @param CacheStorageInterface $cache_storage
193
+	 * @param SessionLifespan       $lifespan
194
+	 * @param RequestInterface      $request
195
+	 * @param EE_Encryption         $encryption
196
+	 * @throws InvalidArgumentException
197
+	 * @throws InvalidDataTypeException
198
+	 * @throws InvalidInterfaceException
199
+	 */
200
+	protected function __construct(
201
+		CacheStorageInterface $cache_storage,
202
+		SessionLifespan $lifespan,
203
+		RequestInterface $request,
204
+		EE_Encryption $encryption = null
205
+	) {
206
+		// session loading is turned ON by default, but prior to the init hook, can be turned back OFF via: add_filter( 'FHEE_load_EE_Session', '__return_false' );
207
+		if (! apply_filters('FHEE_load_EE_Session', true)) {
208
+			return;
209
+		}
210
+		$this->session_lifespan = $lifespan;
211
+		$this->request          = $request;
212
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
213
+		if (! defined('ESPRESSO_SESSION')) {
214
+			define('ESPRESSO_SESSION', true);
215
+		}
216
+		// retrieve session options from db
217
+		$session_settings = (array) get_option(EE_Session::OPTION_NAME_SETTINGS, array());
218
+		if (! empty($session_settings)) {
219
+			// cycle though existing session options
220
+			foreach ($session_settings as $var_name => $session_setting) {
221
+				// set values for class properties
222
+				$var_name          = '_' . $var_name;
223
+				$this->{$var_name} = $session_setting;
224
+			}
225
+		}
226
+		$this->cache_storage = $cache_storage;
227
+		// are we using encryption?
228
+		$this->_use_encryption = $encryption instanceof EE_Encryption
229
+								 && EE_Registry::instance()->CFG->admin->encode_session_data();
230
+		// \EEH_Debug_Tools::printr($this->_use_encryption, '$this->_use_encryption', __FILE__, __LINE__);
231
+		// encrypt data via: $this->encryption->encrypt();
232
+		$this->encryption = $encryption;
233
+		// filter hook allows outside functions/classes/plugins to change default empty cart
234
+		$extra_default_session_vars = apply_filters('FHEE__EE_Session__construct__extra_default_session_vars', array());
235
+		array_merge($this->_default_session_vars, $extra_default_session_vars);
236
+		// apply default session vars
237
+		$this->_set_defaults();
238
+		add_action('AHEE__EE_System__initialize', array($this, 'open_session'));
239
+		// check request for 'clear_session' param
240
+		add_action('AHEE__EE_Request_Handler__construct__complete', array($this, 'wp_loaded'));
241
+		// once everything is all said and done,
242
+		add_action('shutdown', array($this, 'update'), 100);
243
+		add_action('shutdown', array($this, 'garbageCollection'), 1000);
244
+		$this->configure_garbage_collection_filters();
245
+	}
246
+
247
+
248
+
249
+	/**
250
+	 * @return void
251
+	 * @throws EE_Error
252
+	 * @throws InvalidArgumentException
253
+	 * @throws InvalidDataTypeException
254
+	 * @throws InvalidInterfaceException
255
+	 * @throws InvalidSessionDataException
256
+	 */
257
+	public function open_session()
258
+	{
259
+		// check for existing session and retrieve it from db
260
+		if (! $this->_espresso_session()) {
261
+			// or just start a new one
262
+			$this->_create_espresso_session();
263
+		}
264
+	}
265
+
266
+
267
+
268
+	/**
269
+	 * @return bool
270
+	 */
271
+	public function expired()
272
+	{
273
+		return $this->_expired;
274
+	}
275
+
276
+
277
+
278
+	/**
279
+	 * @return void
280
+	 */
281
+	public function reset_expired()
282
+	{
283
+		$this->_expired = false;
284
+	}
285
+
286
+
287
+	/**
288
+	 * @return int
289
+	 */
290
+	public function expiration()
291
+	{
292
+		return $this->_expiration;
293
+	}
294
+
295
+
296
+
297
+	/**
298
+	 * @return int
299
+	 */
300
+	public function extension()
301
+	{
302
+		return apply_filters('FHEE__EE_Session__extend_expiration__seconds_added', 10 * MINUTE_IN_SECONDS);
303
+	}
304
+
305
+
306
+
307
+	/**
308
+	 * @param int $time number of seconds to add to session expiration
309
+	 */
310
+	public function extend_expiration($time = 0)
311
+	{
312
+		$time              = $time ? $time : $this->extension();
313
+		$this->_expiration += absint($time);
314
+	}
315
+
316
+
317
+
318
+	/**
319
+	 * @return int
320
+	 */
321
+	public function lifespan()
322
+	{
323
+		return $this->session_lifespan->inSeconds();
324
+	}
325
+
326
+
327
+
328
+	/**
329
+	 * This just sets some defaults for the _session data property
330
+	 *
331
+	 * @access private
332
+	 * @return void
333
+	 */
334
+	private function _set_defaults()
335
+	{
336
+		// set some defaults
337
+		foreach ($this->_default_session_vars as $key => $default_var) {
338
+			if (is_array($default_var)) {
339
+				$this->_session_data[ $key ] = array();
340
+			} else {
341
+				$this->_session_data[ $key ] = '';
342
+			}
343
+		}
344
+	}
345 345
 
346 346
 
347
-
348
-    /**
349
-     * @retrieve  session data
350
-     * @access    public
351
-     * @return    string
352
-     */
353
-    public function id()
354
-    {
355
-        return $this->_sid;
356
-    }
347
+
348
+	/**
349
+	 * @retrieve  session data
350
+	 * @access    public
351
+	 * @return    string
352
+	 */
353
+	public function id()
354
+	{
355
+		return $this->_sid;
356
+	}
357 357
 
358 358
 
359 359
 
360
-    /**
361
-     * @param \EE_Cart $cart
362
-     * @return bool
363
-     */
364
-    public function set_cart(EE_Cart $cart)
365
-    {
366
-        $this->_session_data['cart'] = $cart;
367
-        return true;
368
-    }
360
+	/**
361
+	 * @param \EE_Cart $cart
362
+	 * @return bool
363
+	 */
364
+	public function set_cart(EE_Cart $cart)
365
+	{
366
+		$this->_session_data['cart'] = $cart;
367
+		return true;
368
+	}
369 369
 
370 370
 
371 371
 
372
-    /**
373
-     * reset_cart
374
-     */
375
-    public function reset_cart()
376
-    {
377
-        do_action('AHEE__EE_Session__reset_cart__before_reset', $this);
378
-        $this->_session_data['cart'] = null;
379
-    }
380
-
381
-
382
-
383
-    /**
384
-     * @return \EE_Cart
385
-     */
386
-    public function cart()
387
-    {
388
-        return isset($this->_session_data['cart']) && $this->_session_data['cart'] instanceof EE_Cart
389
-            ? $this->_session_data['cart']
390
-            : null;
391
-    }
392
-
393
-
394
-
395
-    /**
396
-     * @param \EE_Checkout $checkout
397
-     * @return bool
398
-     */
399
-    public function set_checkout(EE_Checkout $checkout)
400
-    {
401
-        $this->_session_data['checkout'] = $checkout;
402
-        return true;
403
-    }
404
-
405
-
406
-
407
-    /**
408
-     * reset_checkout
409
-     */
410
-    public function reset_checkout()
411
-    {
412
-        do_action('AHEE__EE_Session__reset_checkout__before_reset', $this);
413
-        $this->_session_data['checkout'] = null;
414
-    }
415
-
416
-
417
-
418
-    /**
419
-     * @return \EE_Checkout
420
-     */
421
-    public function checkout()
422
-    {
423
-        return isset($this->_session_data['checkout']) && $this->_session_data['checkout'] instanceof EE_Checkout
424
-            ? $this->_session_data['checkout']
425
-            : null;
426
-    }
427
-
428
-
429
-
430
-    /**
431
-     * @param \EE_Transaction $transaction
432
-     * @return bool
433
-     * @throws EE_Error
434
-     */
435
-    public function set_transaction(EE_Transaction $transaction)
436
-    {
437
-        // first remove the session from the transaction before we save the transaction in the session
438
-        $transaction->set_txn_session_data(null);
439
-        $this->_session_data['transaction'] = $transaction;
440
-        return true;
441
-    }
442
-
443
-
444
-
445
-    /**
446
-     * reset_transaction
447
-     */
448
-    public function reset_transaction()
449
-    {
450
-        do_action('AHEE__EE_Session__reset_transaction__before_reset', $this);
451
-        $this->_session_data['transaction'] = null;
452
-    }
453
-
454
-
455
-
456
-    /**
457
-     * @return \EE_Transaction
458
-     */
459
-    public function transaction()
460
-    {
461
-        return isset($this->_session_data['transaction'])
462
-               && $this->_session_data['transaction'] instanceof EE_Transaction
463
-            ? $this->_session_data['transaction']
464
-            : null;
465
-    }
466
-
467
-
468
-
469
-    /**
470
-     * retrieve session data
471
-     *
472
-     * @access    public
473
-     * @param null $key
474
-     * @param bool $reset_cache
475
-     * @return    array
476
-     */
477
-    public function get_session_data($key = null, $reset_cache = false)
478
-    {
479
-        if ($reset_cache) {
480
-            $this->reset_cart();
481
-            $this->reset_checkout();
482
-            $this->reset_transaction();
483
-        }
484
-        if (! empty($key)) {
485
-            return isset($this->_session_data[ $key ]) ? $this->_session_data[ $key ] : null;
486
-        }
487
-        return $this->_session_data;
488
-    }
489
-
490
-
491
-
492
-    /**
493
-     * set session data
494
-     *
495
-     * @access    public
496
-     * @param    array $data
497
-     * @return    TRUE on success, FALSE on fail
498
-     */
499
-    public function set_session_data($data)
500
-    {
501
-
502
-        // nothing ??? bad data ??? go home!
503
-        if (empty($data) || ! is_array($data)) {
504
-            EE_Error::add_error(__('No session data or invalid session data was provided.', 'event_espresso'), __FILE__,
505
-                __FUNCTION__, __LINE__);
506
-            return false;
507
-        }
508
-        foreach ($data as $key => $value) {
509
-            if (isset($this->_default_session_vars[ $key ])) {
510
-                EE_Error::add_error(sprintf(__('Sorry! %s is a default session datum and can not be reset.',
511
-                    'event_espresso'), $key), __FILE__, __FUNCTION__, __LINE__);
512
-                return false;
513
-            }
514
-            $this->_session_data[ $key ] = $value;
515
-        }
516
-        return true;
517
-    }
518
-
519
-
520
-
521
-    /**
522
-     * @initiate session
523
-     * @access   private
524
-     * @return TRUE on success, FALSE on fail
525
-     * @throws EE_Error
526
-     * @throws InvalidArgumentException
527
-     * @throws InvalidDataTypeException
528
-     * @throws InvalidInterfaceException
529
-     * @throws InvalidSessionDataException
530
-     */
531
-    private function _espresso_session()
532
-    {
533
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
534
-        // check that session has started
535
-        if (session_id() === '') {
536
-            //starts a new session if one doesn't already exist, or re-initiates an existing one
537
-            session_start();
538
-        }
539
-        // get our modified session ID
540
-        $this->_sid = $this->_generate_session_id();
541
-        // and the visitors IP
542
-        $this->_ip_address = $this->request->ipAddress();
543
-        // set the "user agent"
544
-        $this->_user_agent = $this->request->userAgent();
545
-        // now let's retrieve what's in the db
546
-        $session_data = $this->_retrieve_session_data();
547
-        if (! empty($session_data)) {
548
-            // get the current time in UTC
549
-            $this->_time = $this->_time !== null ? $this->_time : time();
550
-            // and reset the session expiration
551
-            $this->_expiration = isset($session_data['expiration'])
552
-                ? $session_data['expiration']
553
-                : $this->_time + $this->session_lifespan->inSeconds();
554
-        } else {
555
-            // set initial site access time and the session expiration
556
-            $this->_set_init_access_and_expiration();
557
-            // set referer
558
-            $this->_session_data['pages_visited'][ $this->_session_data['init_access'] ] = isset($_SERVER['HTTP_REFERER'])
559
-                ? esc_attr($_SERVER['HTTP_REFERER'])
560
-                : '';
561
-            // no previous session = go back and create one (on top of the data above)
562
-            return false;
563
-        }
564
-        // now the user agent
565
-        if ($session_data['user_agent'] !== $this->_user_agent) {
566
-            return false;
567
-        }
568
-        // wait a minute... how old are you?
569
-        if ($this->_time > $this->_expiration) {
570
-            // yer too old fer me!
571
-            $this->_expired = true;
572
-            // wipe out everything that isn't a default session datum
573
-            $this->clear_session(__CLASS__, __FUNCTION__);
574
-        }
575
-        // make event espresso session data available to plugin
576
-        $this->_session_data = array_merge($this->_session_data, $session_data);
577
-        return true;
578
-    }
579
-
580
-
581
-
582
-    /**
583
-     * _get_session_data
584
-     * Retrieves the session data, and attempts to correct any encoding issues that can occur due to improperly setup
585
-     * databases
586
-     *
587
-     * @return array
588
-     * @throws EE_Error
589
-     * @throws InvalidArgumentException
590
-     * @throws InvalidSessionDataException
591
-     * @throws InvalidDataTypeException
592
-     * @throws InvalidInterfaceException
593
-     */
594
-    protected function _retrieve_session_data()
595
-    {
596
-        $ssn_key = EE_Session::session_id_prefix . $this->_sid;
597
-        try {
598
-            // we're using WP's Transient API to store session data using the PHP session ID as the option name
599
-            $session_data = $this->cache_storage->get($ssn_key, false);
600
-            if (empty($session_data)) {
601
-                return array();
602
-            }
603
-            if (apply_filters('FHEE__EE_Session___perform_session_id_hash_check', WP_DEBUG)) {
604
-                $hash_check = $this->cache_storage->get(
605
-                    EE_Session::hash_check_prefix . $this->_sid,
606
-                    false
607
-                );
608
-                if ($hash_check && $hash_check !== md5($session_data)) {
609
-                    EE_Error::add_error(
610
-                        sprintf(
611
-                            __(
612
-                                'The stored data for session %1$s failed to pass a hash check and therefore appears to be invalid.',
613
-                                'event_espresso'
614
-                            ),
615
-                            EE_Session::session_id_prefix . $this->_sid
616
-                        ),
617
-                        __FILE__, __FUNCTION__, __LINE__
618
-                    );
619
-                }
620
-            }
621
-        } catch (Exception $e) {
622
-            // let's just eat that error for now and attempt to correct any corrupted data
623
-            global $wpdb;
624
-            $row          = $wpdb->get_row(
625
-                $wpdb->prepare(
626
-                    "SELECT option_value FROM {$wpdb->options} WHERE option_name = %s LIMIT 1",
627
-                    '_transient_' . $ssn_key
628
-                )
629
-            );
630
-            $session_data = is_object($row) ? $row->option_value : null;
631
-            if ($session_data) {
632
-                $session_data = preg_replace_callback(
633
-                    '!s:(d+):"(.*?)";!',
634
-                    function ($match)
635
-                    {
636
-                        return $match[1] === strlen($match[2])
637
-                            ? $match[0]
638
-                            : 's:' . strlen($match[2]) . ':"' . $match[2] . '";';
639
-                    },
640
-                    $session_data
641
-                );
642
-            }
643
-            $session_data = maybe_unserialize($session_data);
644
-        }
645
-        // in case the data is encoded... try to decode it
646
-        $session_data = $this->encryption instanceof EE_Encryption
647
-            ? $this->encryption->base64_string_decode($session_data)
648
-            : $session_data;
649
-        if (! is_array($session_data)) {
650
-            try {
651
-                $session_data = maybe_unserialize($session_data);
652
-            } catch (Exception $e) {
653
-                $msg = esc_html__(
654
-                    'An error occurred while attempting to unserialize the session data.',
655
-                    'event_espresso'
656
-                );
657
-                $msg .= WP_DEBUG
658
-                    ? '<br><pre>'
659
-                      . print_r($session_data, true)
660
-                      . '</pre><br>'
661
-                      . $this->find_serialize_error($session_data)
662
-                    : '';
663
-                $this->cache_storage->delete(EE_Session::session_id_prefix . $this->_sid);
664
-                throw new InvalidSessionDataException($msg, 0, $e);
665
-            }
666
-        }
667
-        // just a check to make sure the session array is indeed an array
668
-        if (! is_array($session_data)) {
669
-            // no?!?! then something is wrong
670
-            $msg = esc_html__(
671
-                'The session data is missing, invalid, or corrupted.',
672
-                'event_espresso'
673
-            );
674
-            $msg .= WP_DEBUG
675
-                ? '<br><pre>' . print_r($session_data, true) . '</pre><br>' . $this->find_serialize_error($session_data)
676
-                : '';
677
-            $this->cache_storage->delete(EE_Session::session_id_prefix . $this->_sid);
678
-            throw new InvalidSessionDataException($msg);
679
-        }
680
-        if (isset($session_data['transaction']) && absint($session_data['transaction']) !== 0) {
681
-            $session_data['transaction'] = EEM_Transaction::instance()->get_one_by_ID(
682
-                $session_data['transaction']
683
-            );
684
-        }
685
-        return $session_data;
686
-    }
687
-
688
-
689
-
690
-    /**
691
-     * _generate_session_id
692
-     * Retrieves the PHP session id either directly from the PHP session,
693
-     * or from the $_REQUEST array if it was passed in from an AJAX request.
694
-     * The session id is then salted and hashed (mmm sounds tasty)
695
-     * so that it can be safely used as a $_REQUEST param
696
-     *
697
-     * @return string
698
-     */
699
-    protected function _generate_session_id()
700
-    {
701
-        // check if the SID was passed explicitly, otherwise get from session, then add salt and hash it to reduce length
702
-        if (isset($_REQUEST['EESID'])) {
703
-            $session_id = sanitize_text_field($_REQUEST['EESID']);
704
-        } else {
705
-            $session_id = md5(session_id() . get_current_blog_id() . $this->_get_sid_salt());
706
-        }
707
-        return apply_filters('FHEE__EE_Session___generate_session_id__session_id', $session_id);
708
-    }
709
-
710
-
711
-
712
-    /**
713
-     * _get_sid_salt
714
-     *
715
-     * @return string
716
-     */
717
-    protected function _get_sid_salt()
718
-    {
719
-        // was session id salt already saved to db ?
720
-        if (empty($this->_sid_salt)) {
721
-            // no?  then maybe use WP defined constant
722
-            if (defined('AUTH_SALT')) {
723
-                $this->_sid_salt = AUTH_SALT;
724
-            }
725
-            // if salt doesn't exist or is too short
726
-            if (strlen($this->_sid_salt) < 32) {
727
-                // create a new one
728
-                $this->_sid_salt = wp_generate_password(64);
729
-            }
730
-            // and save it as a permanent session setting
731
-            $this->updateSessionSettings(array('sid_salt' => $this->_sid_salt));
732
-        }
733
-        return $this->_sid_salt;
734
-    }
735
-
736
-
737
-
738
-    /**
739
-     * _set_init_access_and_expiration
740
-     *
741
-     * @return void
742
-     */
743
-    protected function _set_init_access_and_expiration()
744
-    {
745
-        $this->_time       = time();
746
-        $this->_expiration = $this->_time + $this->session_lifespan->inSeconds();
747
-        // set initial site access time
748
-        $this->_session_data['init_access'] = $this->_time;
749
-        // and the session expiration
750
-        $this->_session_data['expiration'] = $this->_expiration;
751
-    }
752
-
753
-
754
-
755
-    /**
756
-     * @update session data  prior to saving to the db
757
-     * @access public
758
-     * @param bool $new_session
759
-     * @return TRUE on success, FALSE on fail
760
-     * @throws EE_Error
761
-     * @throws InvalidArgumentException
762
-     * @throws InvalidDataTypeException
763
-     * @throws InvalidInterfaceException
764
-     */
765
-    public function update($new_session = false)
766
-    {
767
-        $this->_session_data = $this->_session_data !== null
768
-                               && is_array($this->_session_data)
769
-                               && isset($this->_session_data['id'])
770
-            ? $this->_session_data
771
-            : array();
772
-        if (empty($this->_session_data)) {
773
-            $this->_set_defaults();
774
-        }
775
-        $session_data = array();
776
-        foreach ($this->_session_data as $key => $value) {
777
-
778
-            switch ($key) {
779
-
780
-                case 'id' :
781
-                    // session ID
782
-                    $session_data['id'] = $this->_sid;
783
-                    break;
784
-                case 'ip_address' :
785
-                    // visitor ip address
786
-                    $session_data['ip_address'] = $this->request->ipAddress();
787
-                    break;
788
-                case 'user_agent' :
789
-                    // visitor user_agent
790
-                    $session_data['user_agent'] = $this->_user_agent;
791
-                    break;
792
-                case 'init_access' :
793
-                    $session_data['init_access'] = absint($value);
794
-                    break;
795
-                case 'last_access' :
796
-                    // current access time
797
-                    $session_data['last_access'] = $this->_time;
798
-                    break;
799
-                case 'expiration' :
800
-                    // when the session expires
801
-                    $session_data['expiration'] = ! empty($this->_expiration)
802
-                        ? $this->_expiration
803
-                        : $session_data['init_access'] + $this->session_lifespan->inSeconds();
804
-                    break;
805
-                case 'user_id' :
806
-                    // current user if logged in
807
-                    $session_data['user_id'] = $this->_wp_user_id();
808
-                    break;
809
-                case 'pages_visited' :
810
-                    $page_visit = $this->_get_page_visit();
811
-                    if ($page_visit) {
812
-                        // set pages visited where the first will be the http referrer
813
-                        $this->_session_data['pages_visited'][ $this->_time ] = $page_visit;
814
-                        // we'll only save the last 10 page visits.
815
-                        $session_data['pages_visited'] = array_slice($this->_session_data['pages_visited'], -10);
816
-                    }
817
-                    break;
818
-                default :
819
-                    // carry any other data over
820
-                    $session_data[ $key ] = $this->_session_data[ $key ];
821
-            }
822
-        }
823
-        $this->_session_data = $session_data;
824
-        // creating a new session does not require saving to the db just yet
825
-        if (! $new_session) {
826
-            // ready? let's save
827
-            if ($this->_save_session_to_db()) {
828
-                return true;
829
-            }
830
-            return false;
831
-        }
832
-        // meh, why not?
833
-        return true;
834
-    }
835
-
836
-
837
-
838
-    /**
839
-     * @create session data array
840
-     * @access public
841
-     * @return bool
842
-     * @throws EE_Error
843
-     * @throws InvalidArgumentException
844
-     * @throws InvalidDataTypeException
845
-     * @throws InvalidInterfaceException
846
-     */
847
-    private function _create_espresso_session()
848
-    {
849
-        do_action('AHEE_log', __CLASS__, __FUNCTION__, '');
850
-        // use the update function for now with $new_session arg set to TRUE
851
-        return $this->update(true) ? true : false;
852
-    }
853
-
854
-
855
-
856
-    /**
857
-     * _save_session_to_db
858
-     *
859
-     * @param bool $clear_session
860
-     * @return string
861
-     * @throws EE_Error
862
-     * @throws InvalidArgumentException
863
-     * @throws InvalidDataTypeException
864
-     * @throws InvalidInterfaceException
865
-     */
866
-    private function _save_session_to_db($clear_session = false)
867
-    {
868
-        // don't save sessions for crawlers
869
-        // and unless we're deleting the session data, don't save anything if there isn't a cart
870
-        if ($this->request->isBot() || (! $clear_session && ! $this->cart() instanceof EE_Cart)) {
871
-            return false;
872
-        }
873
-        $transaction = $this->transaction();
874
-        if ($transaction instanceof EE_Transaction) {
875
-            if (! $transaction->ID()) {
876
-                $transaction->save();
877
-            }
878
-            $this->_session_data['transaction'] = $transaction->ID();
879
-        }
880
-        // then serialize all of our session data
881
-        $session_data = serialize($this->_session_data);
882
-        // do we need to also encode it to avoid corrupted data when saved to the db?
883
-        $session_data = $this->_use_encryption
884
-            ? $this->encryption->base64_string_encode($session_data)
885
-            : $session_data;
886
-        // maybe save hash check
887
-        if (apply_filters('FHEE__EE_Session___perform_session_id_hash_check', WP_DEBUG)) {
888
-            $this->cache_storage->add(
889
-                EE_Session::hash_check_prefix . $this->_sid,
890
-                md5($session_data),
891
-                $this->session_lifespan->inSeconds()
892
-            );
893
-        }
894
-        // we're using the Transient API for storing session data,
895
-        return $this->cache_storage->add(
896
-            EE_Session::session_id_prefix . $this->_sid,
897
-            $session_data,
898
-            $this->session_lifespan->inSeconds()
899
-        );
900
-    }
901
-
902
-
903
-    /**
904
-     * @get    the full page request the visitor is accessing
905
-     * @access public
906
-     * @return string
907
-     */
908
-    public function _get_page_visit()
909
-    {
910
-        $page_visit = home_url('/') . 'wp-admin/admin-ajax.php';
911
-        // check for request url
912
-        if (isset($_SERVER['REQUEST_URI'])) {
913
-            $http_host   = '';
914
-            $page_id     = '?';
915
-            $e_reg       = '';
916
-            $request_uri = esc_url($_SERVER['REQUEST_URI']);
917
-            $ru_bits     = explode('?', $request_uri);
918
-            $request_uri = $ru_bits[0];
919
-            // check for and grab host as well
920
-            if (isset($_SERVER['HTTP_HOST'])) {
921
-                $http_host = esc_url($_SERVER['HTTP_HOST']);
922
-            }
923
-            // check for page_id in SERVER REQUEST
924
-            if (isset($_REQUEST['page_id'])) {
925
-                // rebuild $e_reg without any of the extra parameters
926
-                $page_id = '?page_id=' . esc_attr($_REQUEST['page_id']) . '&amp;';
927
-            }
928
-            // check for $e_reg in SERVER REQUEST
929
-            if (isset($_REQUEST['ee'])) {
930
-                // rebuild $e_reg without any of the extra parameters
931
-                $e_reg = 'ee=' . esc_attr($_REQUEST['ee']);
932
-            }
933
-            $page_visit = rtrim($http_host . $request_uri . $page_id . $e_reg, '?');
934
-        }
935
-        return $page_visit !== home_url('/wp-admin/admin-ajax.php') ? $page_visit : '';
936
-    }
937
-
938
-
939
-
940
-    /**
941
-     * @the    current wp user id
942
-     * @access public
943
-     * @return int
944
-     */
945
-    public function _wp_user_id()
946
-    {
947
-        // if I need to explain the following lines of code, then you shouldn't be looking at this!
948
-        $this->_wp_user_id = get_current_user_id();
949
-        return $this->_wp_user_id;
950
-    }
951
-
952
-
953
-
954
-    /**
955
-     * Clear EE_Session data
956
-     *
957
-     * @access public
958
-     * @param string $class
959
-     * @param string $function
960
-     * @return void
961
-     * @throws EE_Error
962
-     * @throws InvalidArgumentException
963
-     * @throws InvalidDataTypeException
964
-     * @throws InvalidInterfaceException
965
-     */
966
-    public function clear_session($class = '', $function = '')
967
-    {
968
-        do_action('AHEE_log', __FILE__, __FUNCTION__, 'session cleared by : ' . $class . '::' . $function . '()');
969
-        $this->reset_cart();
970
-        $this->reset_checkout();
971
-        $this->reset_transaction();
972
-        // wipe out everything that isn't a default session datum
973
-        $this->reset_data(array_keys($this->_session_data));
974
-        // reset initial site access time and the session expiration
975
-        $this->_set_init_access_and_expiration();
976
-        $this->_save_session_to_db(true);
977
-    }
978
-
979
-
980
-
981
-    /**
982
-     * @resets all non-default session vars
983
-     * @access public
984
-     * @param array|mixed $data_to_reset
985
-     * @param bool        $show_all_notices
986
-     * @return TRUE on success, FALSE on fail
987
-     */
988
-    public function reset_data($data_to_reset = array(), $show_all_notices = false)
989
-    {
990
-        // if $data_to_reset is not in an array, then put it in one
991
-        if (! is_array($data_to_reset)) {
992
-            $data_to_reset = array($data_to_reset);
993
-        }
994
-        // nothing ??? go home!
995
-        if (empty($data_to_reset)) {
996
-            EE_Error::add_error(__('No session data could be reset, because no session var name was provided.',
997
-                'event_espresso'), __FILE__, __FUNCTION__, __LINE__);
998
-            return false;
999
-        }
1000
-        $return_value = true;
1001
-        // since $data_to_reset is an array, cycle through the values
1002
-        foreach ($data_to_reset as $reset) {
1003
-
1004
-            // first check to make sure it is a valid session var
1005
-            if (isset($this->_session_data[ $reset ])) {
1006
-                // then check to make sure it is not a default var
1007
-                if (! array_key_exists($reset, $this->_default_session_vars)) {
1008
-                    // remove session var
1009
-                    unset($this->_session_data[ $reset ]);
1010
-                    if ($show_all_notices) {
1011
-                        EE_Error::add_success(sprintf(__('The session variable %s was removed.', 'event_espresso'),
1012
-                            $reset), __FILE__, __FUNCTION__, __LINE__);
1013
-                    }
1014
-                } else {
1015
-                    // yeeeeeeeeerrrrrrrrrrr OUT !!!!
1016
-                    if ($show_all_notices) {
1017
-                        EE_Error::add_error(sprintf(__('Sorry! %s is a default session datum and can not be reset.',
1018
-                            'event_espresso'), $reset), __FILE__, __FUNCTION__, __LINE__);
1019
-                    }
1020
-                    $return_value = false;
1021
-                }
1022
-            } elseif ($show_all_notices) {
1023
-                // oops! that session var does not exist!
1024
-                EE_Error::add_error(sprintf(__('The session item provided, %s, is invalid or does not exist.',
1025
-                    'event_espresso'), $reset), __FILE__, __FUNCTION__, __LINE__);
1026
-                $return_value = false;
1027
-            }
1028
-        } // end of foreach
1029
-        return $return_value;
1030
-    }
1031
-
1032
-
1033
-
1034
-    /**
1035
-     *   wp_loaded
1036
-     *
1037
-     * @access public
1038
-     * @throws EE_Error
1039
-     * @throws InvalidDataTypeException
1040
-     * @throws InvalidInterfaceException
1041
-     * @throws InvalidArgumentException
1042
-     */
1043
-    public function wp_loaded()
1044
-    {
1045
-        if ($this->request->requestParamIsSet('clear_session')) {
1046
-            $this->clear_session(__CLASS__, __FUNCTION__);
1047
-        }
1048
-    }
1049
-
1050
-
1051
-
1052
-    /**
1053
-     * Used to reset the entire object (for tests).
1054
-     *
1055
-     * @since 4.3.0
1056
-     * @throws EE_Error
1057
-     * @throws InvalidDataTypeException
1058
-     * @throws InvalidInterfaceException
1059
-     * @throws InvalidArgumentException
1060
-     */
1061
-    public function reset_instance()
1062
-    {
1063
-        $this->clear_session();
1064
-        self::$_instance = null;
1065
-    }
1066
-
1067
-
1068
-
1069
-    public function configure_garbage_collection_filters()
1070
-    {
1071
-        // run old filter we had for controlling session cleanup
1072
-        $expired_session_transient_delete_query_limit = absint(
1073
-            apply_filters(
1074
-                'FHEE__EE_Session__garbage_collection___expired_session_transient_delete_query_limit',
1075
-                50
1076
-            )
1077
-        );
1078
-        // is there a value? or one that is different than the default 50 records?
1079
-        if ($expired_session_transient_delete_query_limit === 0) {
1080
-            // hook into TransientCacheStorage in case Session cleanup was turned off
1081
-            add_filter('FHEE__TransientCacheStorage__transient_cleanup_schedule', '__return_zero');
1082
-        } elseif ($expired_session_transient_delete_query_limit !== 50) {
1083
-            // or use that for the new transient cleanup query limit
1084
-            add_filter(
1085
-                'FHEE__TransientCacheStorage__clearExpiredTransients__limit',
1086
-                function () use ($expired_session_transient_delete_query_limit)
1087
-                {
1088
-                    return $expired_session_transient_delete_query_limit;
1089
-                }
1090
-            );
1091
-        }
1092
-    }
1093
-
1094
-
1095
-
1096
-    /**
1097
-     * @see http://stackoverflow.com/questions/10152904/unserialize-function-unserialize-error-at-offset/21389439#10152996
1098
-     * @param $data1
1099
-     * @return string
1100
-     */
1101
-    private function find_serialize_error($data1)
1102
-    {
1103
-        $error = '<pre>';
1104
-        $data2 = preg_replace_callback(
1105
-            '!s:(\d+):"(.*?)";!',
1106
-            function ($match)
1107
-            {
1108
-                return ($match[1] === strlen($match[2]))
1109
-                    ? $match[0]
1110
-                    : 's:'
1111
-                      . strlen($match[2])
1112
-                      . ':"'
1113
-                      . $match[2]
1114
-                      . '";';
1115
-            },
1116
-            $data1
1117
-        );
1118
-        $max   = (strlen($data1) > strlen($data2)) ? strlen($data1) : strlen($data2);
1119
-        $error .= $data1 . PHP_EOL;
1120
-        $error .= $data2 . PHP_EOL;
1121
-        for ($i = 0; $i < $max; $i++) {
1122
-            if (@$data1[ $i ] !== @$data2[ $i ]) {
1123
-                $error  .= 'Difference ' . @$data1[ $i ] . ' != ' . @$data2[ $i ] . PHP_EOL;
1124
-                $error  .= "\t-> ORD number " . ord(@$data1[ $i ]) . ' != ' . ord(@$data2[ $i ]) . PHP_EOL;
1125
-                $error  .= "\t-> Line Number = $i" . PHP_EOL;
1126
-                $start  = ($i - 20);
1127
-                $start  = ($start < 0) ? 0 : $start;
1128
-                $length = 40;
1129
-                $point  = $max - $i;
1130
-                if ($point < 20) {
1131
-                    $rlength = 1;
1132
-                    $rpoint  = -$point;
1133
-                } else {
1134
-                    $rpoint  = $length - 20;
1135
-                    $rlength = 1;
1136
-                }
1137
-                $error .= "\t-> Section Data1  = ";
1138
-                $error .= substr_replace(
1139
-                    substr($data1, $start, $length),
1140
-                    "<b style=\"color:green\">{$data1[ $i ]}</b>",
1141
-                    $rpoint,
1142
-                    $rlength
1143
-                );
1144
-                $error .= PHP_EOL;
1145
-                $error .= "\t-> Section Data2  = ";
1146
-                $error .= substr_replace(
1147
-                    substr($data2, $start, $length),
1148
-                    "<b style=\"color:red\">{$data2[ $i ]}</b>",
1149
-                    $rpoint,
1150
-                    $rlength
1151
-                );
1152
-                $error .= PHP_EOL;
1153
-            }
1154
-        }
1155
-        $error .= '</pre>';
1156
-        return $error;
1157
-    }
1158
-
1159
-
1160
-    /**
1161
-     * Saves an  array of settings used for configuring aspects of session behaviour
1162
-     *
1163
-     * @param array $updated_settings
1164
-     */
1165
-    private function updateSessionSettings(array $updated_settings = array())
1166
-    {
1167
-        // add existing settings, but only if not included in incoming $updated_settings array
1168
-        $updated_settings += get_option(EE_Session::OPTION_NAME_SETTINGS, array());
1169
-        update_option(EE_Session::OPTION_NAME_SETTINGS, $updated_settings);
1170
-    }
1171
-
1172
-
1173
-    /**
1174
-     * garbage_collection
1175
-     */
1176
-    public function garbageCollection()
1177
-    {
1178
-        // only perform during regular requests if last garbage collection was over an hour ago
1179
-        if (! (defined('DOING_AJAX') && DOING_AJAX) && (time() - HOUR_IN_SECONDS) >= $this->_last_gc) {
1180
-            $this->_last_gc = time();
1181
-            $this->updateSessionSettings(array('last_gc' => $this->_last_gc));
1182
-            /** @type WPDB $wpdb */
1183
-            global $wpdb;
1184
-            // filter the query limit. Set to 0 to turn off garbage collection
1185
-            $expired_session_transient_delete_query_limit = absint(
1186
-                apply_filters(
1187
-                    'FHEE__EE_Session__garbage_collection___expired_session_transient_delete_query_limit',
1188
-                    50
1189
-                )
1190
-            );
1191
-            // non-zero LIMIT means take out the trash
1192
-            if ($expired_session_transient_delete_query_limit) {
1193
-                $session_key    = str_replace('_', '\_', EE_Session::session_id_prefix);
1194
-                $hash_check_key = str_replace('_', '\_', EE_Session::hash_check_prefix);
1195
-                // since transient expiration timestamps are set in the future, we can compare against NOW
1196
-                // but we only want to pick up any trash that's been around for more than a day
1197
-                $expiration = time() - DAY_IN_SECONDS;
1198
-                $SQL        = "
372
+	/**
373
+	 * reset_cart
374
+	 */
375
+	public function reset_cart()
376
+	{
377
+		do_action('AHEE__EE_Session__reset_cart__before_reset', $this);
378
+		$this->_session_data['cart'] = null;
379
+	}
380
+
381
+
382
+
383
+	/**
384
+	 * @return \EE_Cart
385
+	 */
386
+	public function cart()
387
+	{
388
+		return isset($this->_session_data['cart']) && $this->_session_data['cart'] instanceof EE_Cart
389
+			? $this->_session_data['cart']
390
+			: null;
391
+	}
392
+
393
+
394
+
395
+	/**
396
+	 * @param \EE_Checkout $checkout
397
+	 * @return bool
398
+	 */
399
+	public function set_checkout(EE_Checkout $checkout)
400
+	{
401
+		$this->_session_data['checkout'] = $checkout;
402
+		return true;
403
+	}
404
+
405
+
406
+
407
+	/**
408
+	 * reset_checkout
409
+	 */
410
+	public function reset_checkout()
411
+	{
412
+		do_action('AHEE__EE_Session__reset_checkout__before_reset', $this);
413
+		$this->_session_data['checkout'] = null;
414
+	}
415
+
416
+
417
+
418
+	/**
419
+	 * @return \EE_Checkout
420
+	 */
421
+	public function checkout()
422
+	{
423
+		return isset($this->_session_data['checkout']) && $this->_session_data['checkout'] instanceof EE_Checkout
424
+			? $this->_session_data['checkout']
425
+			: null;
426
+	}
427
+
428
+
429
+
430
+	/**
431
+	 * @param \EE_Transaction $transaction
432
+	 * @return bool
433
+	 * @throws EE_Error
434
+	 */
435
+	public function set_transaction(EE_Transaction $transaction)
436
+	{
437
+		// first remove the session from the transaction before we save the transaction in the session
438
+		$transaction->set_txn_session_data(null);
439
+		$this->_session_data['transaction'] = $transaction;
440
+		return true;
441
+	}
442
+
443
+
444
+
445
+	/**
446
+	 * reset_transaction
447
+	 */
448
+	public function reset_transaction()
449
+	{
450
+		do_action('AHEE__EE_Session__reset_transaction__before_reset', $this);
451
+		$this->_session_data['transaction'] = null;
452
+	}
453
+
454
+
455
+
456
+	/**
457
+	 * @return \EE_Transaction
458
+	 */
459
+	public function transaction()
460
+	{
461
+		return isset($this->_session_data['transaction'])
462
+			   && $this->_session_data['transaction'] instanceof EE_Transaction
463
+			? $this->_session_data['transaction']
464
+			: null;
465
+	}
466
+
467
+
468
+
469
+	/**
470
+	 * retrieve session data
471
+	 *
472
+	 * @access    public
473
+	 * @param null $key
474
+	 * @param bool $reset_cache
475
+	 * @return    array
476
+	 */
477
+	public function get_session_data($key = null, $reset_cache = false)
478
+	{
479
+		if ($reset_cache) {
480
+			$this->reset_cart();
481
+			$this->reset_checkout();
482
+			$this->reset_transaction();
483
+		}
484
+		if (! empty($key)) {
485
+			return isset($this->_session_data[ $key ]) ? $this->_session_data[ $key ] : null;
486
+		}
487
+		return $this->_session_data;
488
+	}
489
+
490
+
491
+
492
+	/**
493
+	 * set session data
494
+	 *
495
+	 * @access    public
496
+	 * @param    array $data
497
+	 * @return    TRUE on success, FALSE on fail
498
+	 */
499
+	public function set_session_data($data)
500
+	{
501
+
502
+		// nothing ??? bad data ??? go home!
503
+		if (empty($data) || ! is_array($data)) {
504
+			EE_Error::add_error(__('No session data or invalid session data was provided.', 'event_espresso'), __FILE__,
505
+				__FUNCTION__, __LINE__);
506
+			return false;
507
+		}
508
+		foreach ($data as $key => $value) {
509
+			if (isset($this->_default_session_vars[ $key ])) {
510
+				EE_Error::add_error(sprintf(__('Sorry! %s is a default session datum and can not be reset.',
511
+					'event_espresso'), $key), __FILE__, __FUNCTION__, __LINE__);
512
+				return false;
513
+			}
514
+			$this->_session_data[ $key ] = $value;
515
+		}
516
+		return true;
517
+	}
518
+
519
+
520
+
521
+	/**
522
+	 * @initiate session
523
+	 * @access   private
524
+	 * @return TRUE on success, FALSE on fail
525
+	 * @throws EE_Error
526
+	 * @throws InvalidArgumentException
527
+	 * @throws InvalidDataTypeException
528
+	 * @throws InvalidInterfaceException
529
+	 * @throws InvalidSessionDataException
530
+	 */
531
+	private function _espresso_session()
532
+	{
533
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
534
+		// check that session has started
535
+		if (session_id() === '') {
536
+			//starts a new session if one doesn't already exist, or re-initiates an existing one
537
+			session_start();
538
+		}
539
+		// get our modified session ID
540
+		$this->_sid = $this->_generate_session_id();
541
+		// and the visitors IP
542
+		$this->_ip_address = $this->request->ipAddress();
543
+		// set the "user agent"
544
+		$this->_user_agent = $this->request->userAgent();
545
+		// now let's retrieve what's in the db
546
+		$session_data = $this->_retrieve_session_data();
547
+		if (! empty($session_data)) {
548
+			// get the current time in UTC
549
+			$this->_time = $this->_time !== null ? $this->_time : time();
550
+			// and reset the session expiration
551
+			$this->_expiration = isset($session_data['expiration'])
552
+				? $session_data['expiration']
553
+				: $this->_time + $this->session_lifespan->inSeconds();
554
+		} else {
555
+			// set initial site access time and the session expiration
556
+			$this->_set_init_access_and_expiration();
557
+			// set referer
558
+			$this->_session_data['pages_visited'][ $this->_session_data['init_access'] ] = isset($_SERVER['HTTP_REFERER'])
559
+				? esc_attr($_SERVER['HTTP_REFERER'])
560
+				: '';
561
+			// no previous session = go back and create one (on top of the data above)
562
+			return false;
563
+		}
564
+		// now the user agent
565
+		if ($session_data['user_agent'] !== $this->_user_agent) {
566
+			return false;
567
+		}
568
+		// wait a minute... how old are you?
569
+		if ($this->_time > $this->_expiration) {
570
+			// yer too old fer me!
571
+			$this->_expired = true;
572
+			// wipe out everything that isn't a default session datum
573
+			$this->clear_session(__CLASS__, __FUNCTION__);
574
+		}
575
+		// make event espresso session data available to plugin
576
+		$this->_session_data = array_merge($this->_session_data, $session_data);
577
+		return true;
578
+	}
579
+
580
+
581
+
582
+	/**
583
+	 * _get_session_data
584
+	 * Retrieves the session data, and attempts to correct any encoding issues that can occur due to improperly setup
585
+	 * databases
586
+	 *
587
+	 * @return array
588
+	 * @throws EE_Error
589
+	 * @throws InvalidArgumentException
590
+	 * @throws InvalidSessionDataException
591
+	 * @throws InvalidDataTypeException
592
+	 * @throws InvalidInterfaceException
593
+	 */
594
+	protected function _retrieve_session_data()
595
+	{
596
+		$ssn_key = EE_Session::session_id_prefix . $this->_sid;
597
+		try {
598
+			// we're using WP's Transient API to store session data using the PHP session ID as the option name
599
+			$session_data = $this->cache_storage->get($ssn_key, false);
600
+			if (empty($session_data)) {
601
+				return array();
602
+			}
603
+			if (apply_filters('FHEE__EE_Session___perform_session_id_hash_check', WP_DEBUG)) {
604
+				$hash_check = $this->cache_storage->get(
605
+					EE_Session::hash_check_prefix . $this->_sid,
606
+					false
607
+				);
608
+				if ($hash_check && $hash_check !== md5($session_data)) {
609
+					EE_Error::add_error(
610
+						sprintf(
611
+							__(
612
+								'The stored data for session %1$s failed to pass a hash check and therefore appears to be invalid.',
613
+								'event_espresso'
614
+							),
615
+							EE_Session::session_id_prefix . $this->_sid
616
+						),
617
+						__FILE__, __FUNCTION__, __LINE__
618
+					);
619
+				}
620
+			}
621
+		} catch (Exception $e) {
622
+			// let's just eat that error for now and attempt to correct any corrupted data
623
+			global $wpdb;
624
+			$row          = $wpdb->get_row(
625
+				$wpdb->prepare(
626
+					"SELECT option_value FROM {$wpdb->options} WHERE option_name = %s LIMIT 1",
627
+					'_transient_' . $ssn_key
628
+				)
629
+			);
630
+			$session_data = is_object($row) ? $row->option_value : null;
631
+			if ($session_data) {
632
+				$session_data = preg_replace_callback(
633
+					'!s:(d+):"(.*?)";!',
634
+					function ($match)
635
+					{
636
+						return $match[1] === strlen($match[2])
637
+							? $match[0]
638
+							: 's:' . strlen($match[2]) . ':"' . $match[2] . '";';
639
+					},
640
+					$session_data
641
+				);
642
+			}
643
+			$session_data = maybe_unserialize($session_data);
644
+		}
645
+		// in case the data is encoded... try to decode it
646
+		$session_data = $this->encryption instanceof EE_Encryption
647
+			? $this->encryption->base64_string_decode($session_data)
648
+			: $session_data;
649
+		if (! is_array($session_data)) {
650
+			try {
651
+				$session_data = maybe_unserialize($session_data);
652
+			} catch (Exception $e) {
653
+				$msg = esc_html__(
654
+					'An error occurred while attempting to unserialize the session data.',
655
+					'event_espresso'
656
+				);
657
+				$msg .= WP_DEBUG
658
+					? '<br><pre>'
659
+					  . print_r($session_data, true)
660
+					  . '</pre><br>'
661
+					  . $this->find_serialize_error($session_data)
662
+					: '';
663
+				$this->cache_storage->delete(EE_Session::session_id_prefix . $this->_sid);
664
+				throw new InvalidSessionDataException($msg, 0, $e);
665
+			}
666
+		}
667
+		// just a check to make sure the session array is indeed an array
668
+		if (! is_array($session_data)) {
669
+			// no?!?! then something is wrong
670
+			$msg = esc_html__(
671
+				'The session data is missing, invalid, or corrupted.',
672
+				'event_espresso'
673
+			);
674
+			$msg .= WP_DEBUG
675
+				? '<br><pre>' . print_r($session_data, true) . '</pre><br>' . $this->find_serialize_error($session_data)
676
+				: '';
677
+			$this->cache_storage->delete(EE_Session::session_id_prefix . $this->_sid);
678
+			throw new InvalidSessionDataException($msg);
679
+		}
680
+		if (isset($session_data['transaction']) && absint($session_data['transaction']) !== 0) {
681
+			$session_data['transaction'] = EEM_Transaction::instance()->get_one_by_ID(
682
+				$session_data['transaction']
683
+			);
684
+		}
685
+		return $session_data;
686
+	}
687
+
688
+
689
+
690
+	/**
691
+	 * _generate_session_id
692
+	 * Retrieves the PHP session id either directly from the PHP session,
693
+	 * or from the $_REQUEST array if it was passed in from an AJAX request.
694
+	 * The session id is then salted and hashed (mmm sounds tasty)
695
+	 * so that it can be safely used as a $_REQUEST param
696
+	 *
697
+	 * @return string
698
+	 */
699
+	protected function _generate_session_id()
700
+	{
701
+		// check if the SID was passed explicitly, otherwise get from session, then add salt and hash it to reduce length
702
+		if (isset($_REQUEST['EESID'])) {
703
+			$session_id = sanitize_text_field($_REQUEST['EESID']);
704
+		} else {
705
+			$session_id = md5(session_id() . get_current_blog_id() . $this->_get_sid_salt());
706
+		}
707
+		return apply_filters('FHEE__EE_Session___generate_session_id__session_id', $session_id);
708
+	}
709
+
710
+
711
+
712
+	/**
713
+	 * _get_sid_salt
714
+	 *
715
+	 * @return string
716
+	 */
717
+	protected function _get_sid_salt()
718
+	{
719
+		// was session id salt already saved to db ?
720
+		if (empty($this->_sid_salt)) {
721
+			// no?  then maybe use WP defined constant
722
+			if (defined('AUTH_SALT')) {
723
+				$this->_sid_salt = AUTH_SALT;
724
+			}
725
+			// if salt doesn't exist or is too short
726
+			if (strlen($this->_sid_salt) < 32) {
727
+				// create a new one
728
+				$this->_sid_salt = wp_generate_password(64);
729
+			}
730
+			// and save it as a permanent session setting
731
+			$this->updateSessionSettings(array('sid_salt' => $this->_sid_salt));
732
+		}
733
+		return $this->_sid_salt;
734
+	}
735
+
736
+
737
+
738
+	/**
739
+	 * _set_init_access_and_expiration
740
+	 *
741
+	 * @return void
742
+	 */
743
+	protected function _set_init_access_and_expiration()
744
+	{
745
+		$this->_time       = time();
746
+		$this->_expiration = $this->_time + $this->session_lifespan->inSeconds();
747
+		// set initial site access time
748
+		$this->_session_data['init_access'] = $this->_time;
749
+		// and the session expiration
750
+		$this->_session_data['expiration'] = $this->_expiration;
751
+	}
752
+
753
+
754
+
755
+	/**
756
+	 * @update session data  prior to saving to the db
757
+	 * @access public
758
+	 * @param bool $new_session
759
+	 * @return TRUE on success, FALSE on fail
760
+	 * @throws EE_Error
761
+	 * @throws InvalidArgumentException
762
+	 * @throws InvalidDataTypeException
763
+	 * @throws InvalidInterfaceException
764
+	 */
765
+	public function update($new_session = false)
766
+	{
767
+		$this->_session_data = $this->_session_data !== null
768
+							   && is_array($this->_session_data)
769
+							   && isset($this->_session_data['id'])
770
+			? $this->_session_data
771
+			: array();
772
+		if (empty($this->_session_data)) {
773
+			$this->_set_defaults();
774
+		}
775
+		$session_data = array();
776
+		foreach ($this->_session_data as $key => $value) {
777
+
778
+			switch ($key) {
779
+
780
+				case 'id' :
781
+					// session ID
782
+					$session_data['id'] = $this->_sid;
783
+					break;
784
+				case 'ip_address' :
785
+					// visitor ip address
786
+					$session_data['ip_address'] = $this->request->ipAddress();
787
+					break;
788
+				case 'user_agent' :
789
+					// visitor user_agent
790
+					$session_data['user_agent'] = $this->_user_agent;
791
+					break;
792
+				case 'init_access' :
793
+					$session_data['init_access'] = absint($value);
794
+					break;
795
+				case 'last_access' :
796
+					// current access time
797
+					$session_data['last_access'] = $this->_time;
798
+					break;
799
+				case 'expiration' :
800
+					// when the session expires
801
+					$session_data['expiration'] = ! empty($this->_expiration)
802
+						? $this->_expiration
803
+						: $session_data['init_access'] + $this->session_lifespan->inSeconds();
804
+					break;
805
+				case 'user_id' :
806
+					// current user if logged in
807
+					$session_data['user_id'] = $this->_wp_user_id();
808
+					break;
809
+				case 'pages_visited' :
810
+					$page_visit = $this->_get_page_visit();
811
+					if ($page_visit) {
812
+						// set pages visited where the first will be the http referrer
813
+						$this->_session_data['pages_visited'][ $this->_time ] = $page_visit;
814
+						// we'll only save the last 10 page visits.
815
+						$session_data['pages_visited'] = array_slice($this->_session_data['pages_visited'], -10);
816
+					}
817
+					break;
818
+				default :
819
+					// carry any other data over
820
+					$session_data[ $key ] = $this->_session_data[ $key ];
821
+			}
822
+		}
823
+		$this->_session_data = $session_data;
824
+		// creating a new session does not require saving to the db just yet
825
+		if (! $new_session) {
826
+			// ready? let's save
827
+			if ($this->_save_session_to_db()) {
828
+				return true;
829
+			}
830
+			return false;
831
+		}
832
+		// meh, why not?
833
+		return true;
834
+	}
835
+
836
+
837
+
838
+	/**
839
+	 * @create session data array
840
+	 * @access public
841
+	 * @return bool
842
+	 * @throws EE_Error
843
+	 * @throws InvalidArgumentException
844
+	 * @throws InvalidDataTypeException
845
+	 * @throws InvalidInterfaceException
846
+	 */
847
+	private function _create_espresso_session()
848
+	{
849
+		do_action('AHEE_log', __CLASS__, __FUNCTION__, '');
850
+		// use the update function for now with $new_session arg set to TRUE
851
+		return $this->update(true) ? true : false;
852
+	}
853
+
854
+
855
+
856
+	/**
857
+	 * _save_session_to_db
858
+	 *
859
+	 * @param bool $clear_session
860
+	 * @return string
861
+	 * @throws EE_Error
862
+	 * @throws InvalidArgumentException
863
+	 * @throws InvalidDataTypeException
864
+	 * @throws InvalidInterfaceException
865
+	 */
866
+	private function _save_session_to_db($clear_session = false)
867
+	{
868
+		// don't save sessions for crawlers
869
+		// and unless we're deleting the session data, don't save anything if there isn't a cart
870
+		if ($this->request->isBot() || (! $clear_session && ! $this->cart() instanceof EE_Cart)) {
871
+			return false;
872
+		}
873
+		$transaction = $this->transaction();
874
+		if ($transaction instanceof EE_Transaction) {
875
+			if (! $transaction->ID()) {
876
+				$transaction->save();
877
+			}
878
+			$this->_session_data['transaction'] = $transaction->ID();
879
+		}
880
+		// then serialize all of our session data
881
+		$session_data = serialize($this->_session_data);
882
+		// do we need to also encode it to avoid corrupted data when saved to the db?
883
+		$session_data = $this->_use_encryption
884
+			? $this->encryption->base64_string_encode($session_data)
885
+			: $session_data;
886
+		// maybe save hash check
887
+		if (apply_filters('FHEE__EE_Session___perform_session_id_hash_check', WP_DEBUG)) {
888
+			$this->cache_storage->add(
889
+				EE_Session::hash_check_prefix . $this->_sid,
890
+				md5($session_data),
891
+				$this->session_lifespan->inSeconds()
892
+			);
893
+		}
894
+		// we're using the Transient API for storing session data,
895
+		return $this->cache_storage->add(
896
+			EE_Session::session_id_prefix . $this->_sid,
897
+			$session_data,
898
+			$this->session_lifespan->inSeconds()
899
+		);
900
+	}
901
+
902
+
903
+	/**
904
+	 * @get    the full page request the visitor is accessing
905
+	 * @access public
906
+	 * @return string
907
+	 */
908
+	public function _get_page_visit()
909
+	{
910
+		$page_visit = home_url('/') . 'wp-admin/admin-ajax.php';
911
+		// check for request url
912
+		if (isset($_SERVER['REQUEST_URI'])) {
913
+			$http_host   = '';
914
+			$page_id     = '?';
915
+			$e_reg       = '';
916
+			$request_uri = esc_url($_SERVER['REQUEST_URI']);
917
+			$ru_bits     = explode('?', $request_uri);
918
+			$request_uri = $ru_bits[0];
919
+			// check for and grab host as well
920
+			if (isset($_SERVER['HTTP_HOST'])) {
921
+				$http_host = esc_url($_SERVER['HTTP_HOST']);
922
+			}
923
+			// check for page_id in SERVER REQUEST
924
+			if (isset($_REQUEST['page_id'])) {
925
+				// rebuild $e_reg without any of the extra parameters
926
+				$page_id = '?page_id=' . esc_attr($_REQUEST['page_id']) . '&amp;';
927
+			}
928
+			// check for $e_reg in SERVER REQUEST
929
+			if (isset($_REQUEST['ee'])) {
930
+				// rebuild $e_reg without any of the extra parameters
931
+				$e_reg = 'ee=' . esc_attr($_REQUEST['ee']);
932
+			}
933
+			$page_visit = rtrim($http_host . $request_uri . $page_id . $e_reg, '?');
934
+		}
935
+		return $page_visit !== home_url('/wp-admin/admin-ajax.php') ? $page_visit : '';
936
+	}
937
+
938
+
939
+
940
+	/**
941
+	 * @the    current wp user id
942
+	 * @access public
943
+	 * @return int
944
+	 */
945
+	public function _wp_user_id()
946
+	{
947
+		// if I need to explain the following lines of code, then you shouldn't be looking at this!
948
+		$this->_wp_user_id = get_current_user_id();
949
+		return $this->_wp_user_id;
950
+	}
951
+
952
+
953
+
954
+	/**
955
+	 * Clear EE_Session data
956
+	 *
957
+	 * @access public
958
+	 * @param string $class
959
+	 * @param string $function
960
+	 * @return void
961
+	 * @throws EE_Error
962
+	 * @throws InvalidArgumentException
963
+	 * @throws InvalidDataTypeException
964
+	 * @throws InvalidInterfaceException
965
+	 */
966
+	public function clear_session($class = '', $function = '')
967
+	{
968
+		do_action('AHEE_log', __FILE__, __FUNCTION__, 'session cleared by : ' . $class . '::' . $function . '()');
969
+		$this->reset_cart();
970
+		$this->reset_checkout();
971
+		$this->reset_transaction();
972
+		// wipe out everything that isn't a default session datum
973
+		$this->reset_data(array_keys($this->_session_data));
974
+		// reset initial site access time and the session expiration
975
+		$this->_set_init_access_and_expiration();
976
+		$this->_save_session_to_db(true);
977
+	}
978
+
979
+
980
+
981
+	/**
982
+	 * @resets all non-default session vars
983
+	 * @access public
984
+	 * @param array|mixed $data_to_reset
985
+	 * @param bool        $show_all_notices
986
+	 * @return TRUE on success, FALSE on fail
987
+	 */
988
+	public function reset_data($data_to_reset = array(), $show_all_notices = false)
989
+	{
990
+		// if $data_to_reset is not in an array, then put it in one
991
+		if (! is_array($data_to_reset)) {
992
+			$data_to_reset = array($data_to_reset);
993
+		}
994
+		// nothing ??? go home!
995
+		if (empty($data_to_reset)) {
996
+			EE_Error::add_error(__('No session data could be reset, because no session var name was provided.',
997
+				'event_espresso'), __FILE__, __FUNCTION__, __LINE__);
998
+			return false;
999
+		}
1000
+		$return_value = true;
1001
+		// since $data_to_reset is an array, cycle through the values
1002
+		foreach ($data_to_reset as $reset) {
1003
+
1004
+			// first check to make sure it is a valid session var
1005
+			if (isset($this->_session_data[ $reset ])) {
1006
+				// then check to make sure it is not a default var
1007
+				if (! array_key_exists($reset, $this->_default_session_vars)) {
1008
+					// remove session var
1009
+					unset($this->_session_data[ $reset ]);
1010
+					if ($show_all_notices) {
1011
+						EE_Error::add_success(sprintf(__('The session variable %s was removed.', 'event_espresso'),
1012
+							$reset), __FILE__, __FUNCTION__, __LINE__);
1013
+					}
1014
+				} else {
1015
+					// yeeeeeeeeerrrrrrrrrrr OUT !!!!
1016
+					if ($show_all_notices) {
1017
+						EE_Error::add_error(sprintf(__('Sorry! %s is a default session datum and can not be reset.',
1018
+							'event_espresso'), $reset), __FILE__, __FUNCTION__, __LINE__);
1019
+					}
1020
+					$return_value = false;
1021
+				}
1022
+			} elseif ($show_all_notices) {
1023
+				// oops! that session var does not exist!
1024
+				EE_Error::add_error(sprintf(__('The session item provided, %s, is invalid or does not exist.',
1025
+					'event_espresso'), $reset), __FILE__, __FUNCTION__, __LINE__);
1026
+				$return_value = false;
1027
+			}
1028
+		} // end of foreach
1029
+		return $return_value;
1030
+	}
1031
+
1032
+
1033
+
1034
+	/**
1035
+	 *   wp_loaded
1036
+	 *
1037
+	 * @access public
1038
+	 * @throws EE_Error
1039
+	 * @throws InvalidDataTypeException
1040
+	 * @throws InvalidInterfaceException
1041
+	 * @throws InvalidArgumentException
1042
+	 */
1043
+	public function wp_loaded()
1044
+	{
1045
+		if ($this->request->requestParamIsSet('clear_session')) {
1046
+			$this->clear_session(__CLASS__, __FUNCTION__);
1047
+		}
1048
+	}
1049
+
1050
+
1051
+
1052
+	/**
1053
+	 * Used to reset the entire object (for tests).
1054
+	 *
1055
+	 * @since 4.3.0
1056
+	 * @throws EE_Error
1057
+	 * @throws InvalidDataTypeException
1058
+	 * @throws InvalidInterfaceException
1059
+	 * @throws InvalidArgumentException
1060
+	 */
1061
+	public function reset_instance()
1062
+	{
1063
+		$this->clear_session();
1064
+		self::$_instance = null;
1065
+	}
1066
+
1067
+
1068
+
1069
+	public function configure_garbage_collection_filters()
1070
+	{
1071
+		// run old filter we had for controlling session cleanup
1072
+		$expired_session_transient_delete_query_limit = absint(
1073
+			apply_filters(
1074
+				'FHEE__EE_Session__garbage_collection___expired_session_transient_delete_query_limit',
1075
+				50
1076
+			)
1077
+		);
1078
+		// is there a value? or one that is different than the default 50 records?
1079
+		if ($expired_session_transient_delete_query_limit === 0) {
1080
+			// hook into TransientCacheStorage in case Session cleanup was turned off
1081
+			add_filter('FHEE__TransientCacheStorage__transient_cleanup_schedule', '__return_zero');
1082
+		} elseif ($expired_session_transient_delete_query_limit !== 50) {
1083
+			// or use that for the new transient cleanup query limit
1084
+			add_filter(
1085
+				'FHEE__TransientCacheStorage__clearExpiredTransients__limit',
1086
+				function () use ($expired_session_transient_delete_query_limit)
1087
+				{
1088
+					return $expired_session_transient_delete_query_limit;
1089
+				}
1090
+			);
1091
+		}
1092
+	}
1093
+
1094
+
1095
+
1096
+	/**
1097
+	 * @see http://stackoverflow.com/questions/10152904/unserialize-function-unserialize-error-at-offset/21389439#10152996
1098
+	 * @param $data1
1099
+	 * @return string
1100
+	 */
1101
+	private function find_serialize_error($data1)
1102
+	{
1103
+		$error = '<pre>';
1104
+		$data2 = preg_replace_callback(
1105
+			'!s:(\d+):"(.*?)";!',
1106
+			function ($match)
1107
+			{
1108
+				return ($match[1] === strlen($match[2]))
1109
+					? $match[0]
1110
+					: 's:'
1111
+					  . strlen($match[2])
1112
+					  . ':"'
1113
+					  . $match[2]
1114
+					  . '";';
1115
+			},
1116
+			$data1
1117
+		);
1118
+		$max   = (strlen($data1) > strlen($data2)) ? strlen($data1) : strlen($data2);
1119
+		$error .= $data1 . PHP_EOL;
1120
+		$error .= $data2 . PHP_EOL;
1121
+		for ($i = 0; $i < $max; $i++) {
1122
+			if (@$data1[ $i ] !== @$data2[ $i ]) {
1123
+				$error  .= 'Difference ' . @$data1[ $i ] . ' != ' . @$data2[ $i ] . PHP_EOL;
1124
+				$error  .= "\t-> ORD number " . ord(@$data1[ $i ]) . ' != ' . ord(@$data2[ $i ]) . PHP_EOL;
1125
+				$error  .= "\t-> Line Number = $i" . PHP_EOL;
1126
+				$start  = ($i - 20);
1127
+				$start  = ($start < 0) ? 0 : $start;
1128
+				$length = 40;
1129
+				$point  = $max - $i;
1130
+				if ($point < 20) {
1131
+					$rlength = 1;
1132
+					$rpoint  = -$point;
1133
+				} else {
1134
+					$rpoint  = $length - 20;
1135
+					$rlength = 1;
1136
+				}
1137
+				$error .= "\t-> Section Data1  = ";
1138
+				$error .= substr_replace(
1139
+					substr($data1, $start, $length),
1140
+					"<b style=\"color:green\">{$data1[ $i ]}</b>",
1141
+					$rpoint,
1142
+					$rlength
1143
+				);
1144
+				$error .= PHP_EOL;
1145
+				$error .= "\t-> Section Data2  = ";
1146
+				$error .= substr_replace(
1147
+					substr($data2, $start, $length),
1148
+					"<b style=\"color:red\">{$data2[ $i ]}</b>",
1149
+					$rpoint,
1150
+					$rlength
1151
+				);
1152
+				$error .= PHP_EOL;
1153
+			}
1154
+		}
1155
+		$error .= '</pre>';
1156
+		return $error;
1157
+	}
1158
+
1159
+
1160
+	/**
1161
+	 * Saves an  array of settings used for configuring aspects of session behaviour
1162
+	 *
1163
+	 * @param array $updated_settings
1164
+	 */
1165
+	private function updateSessionSettings(array $updated_settings = array())
1166
+	{
1167
+		// add existing settings, but only if not included in incoming $updated_settings array
1168
+		$updated_settings += get_option(EE_Session::OPTION_NAME_SETTINGS, array());
1169
+		update_option(EE_Session::OPTION_NAME_SETTINGS, $updated_settings);
1170
+	}
1171
+
1172
+
1173
+	/**
1174
+	 * garbage_collection
1175
+	 */
1176
+	public function garbageCollection()
1177
+	{
1178
+		// only perform during regular requests if last garbage collection was over an hour ago
1179
+		if (! (defined('DOING_AJAX') && DOING_AJAX) && (time() - HOUR_IN_SECONDS) >= $this->_last_gc) {
1180
+			$this->_last_gc = time();
1181
+			$this->updateSessionSettings(array('last_gc' => $this->_last_gc));
1182
+			/** @type WPDB $wpdb */
1183
+			global $wpdb;
1184
+			// filter the query limit. Set to 0 to turn off garbage collection
1185
+			$expired_session_transient_delete_query_limit = absint(
1186
+				apply_filters(
1187
+					'FHEE__EE_Session__garbage_collection___expired_session_transient_delete_query_limit',
1188
+					50
1189
+				)
1190
+			);
1191
+			// non-zero LIMIT means take out the trash
1192
+			if ($expired_session_transient_delete_query_limit) {
1193
+				$session_key    = str_replace('_', '\_', EE_Session::session_id_prefix);
1194
+				$hash_check_key = str_replace('_', '\_', EE_Session::hash_check_prefix);
1195
+				// since transient expiration timestamps are set in the future, we can compare against NOW
1196
+				// but we only want to pick up any trash that's been around for more than a day
1197
+				$expiration = time() - DAY_IN_SECONDS;
1198
+				$SQL        = "
1199 1199
                     SELECT option_name
1200 1200
                     FROM {$wpdb->options}
1201 1201
                     WHERE
@@ -1204,19 +1204,19 @@  discard block
 block discarded – undo
1204 1204
                     AND option_value < {$expiration}
1205 1205
                     LIMIT {$expired_session_transient_delete_query_limit}
1206 1206
                 ";
1207
-                // produces something like:
1208
-                // SELECT option_name FROM wp_options
1209
-                // WHERE ( option_name LIKE '\_transient\_timeout\_ee\_ssn\_%'
1210
-                // OR option_name LIKE '\_transient\_timeout\_ee\_shc\_%' )
1211
-                // AND option_value < 1508368198 LIMIT 50
1212
-                $expired_sessions = $wpdb->get_col($SQL);
1213
-                // valid results?
1214
-                if (! $expired_sessions instanceof WP_Error && ! empty($expired_sessions)) {
1215
-                    $this->cache_storage->deleteMany($expired_sessions, true);
1216
-                }
1217
-            }
1218
-        }
1219
-    }
1207
+				// produces something like:
1208
+				// SELECT option_name FROM wp_options
1209
+				// WHERE ( option_name LIKE '\_transient\_timeout\_ee\_ssn\_%'
1210
+				// OR option_name LIKE '\_transient\_timeout\_ee\_shc\_%' )
1211
+				// AND option_value < 1508368198 LIMIT 50
1212
+				$expired_sessions = $wpdb->get_col($SQL);
1213
+				// valid results?
1214
+				if (! $expired_sessions instanceof WP_Error && ! empty($expired_sessions)) {
1215
+					$this->cache_storage->deleteMany($expired_sessions, true);
1216
+				}
1217
+			}
1218
+		}
1219
+	}
1220 1220
 
1221 1221
 
1222 1222
 
Please login to merge, or discard this patch.
Spacing   +57 added lines, -57 removed lines patch added patch discarded remove patch
@@ -174,7 +174,7 @@  discard block
 block discarded – undo
174 174
         // check if class object is instantiated
175 175
         // session loading is turned ON by default, but prior to the init hook, can be turned back OFF via:
176 176
         // add_filter( 'FHEE_load_EE_Session', '__return_false' );
177
-        if (! self::$_instance instanceof EE_Session && apply_filters('FHEE_load_EE_Session', true)) {
177
+        if ( ! self::$_instance instanceof EE_Session && apply_filters('FHEE_load_EE_Session', true)) {
178 178
             self::$_instance = new self(
179 179
                 $cache_storage,
180 180
                 $lifespan,
@@ -204,22 +204,22 @@  discard block
 block discarded – undo
204 204
         EE_Encryption $encryption = null
205 205
     ) {
206 206
         // session loading is turned ON by default, but prior to the init hook, can be turned back OFF via: add_filter( 'FHEE_load_EE_Session', '__return_false' );
207
-        if (! apply_filters('FHEE_load_EE_Session', true)) {
207
+        if ( ! apply_filters('FHEE_load_EE_Session', true)) {
208 208
             return;
209 209
         }
210 210
         $this->session_lifespan = $lifespan;
211 211
         $this->request          = $request;
212 212
         do_action('AHEE_log', __FILE__, __FUNCTION__, '');
213
-        if (! defined('ESPRESSO_SESSION')) {
213
+        if ( ! defined('ESPRESSO_SESSION')) {
214 214
             define('ESPRESSO_SESSION', true);
215 215
         }
216 216
         // retrieve session options from db
217 217
         $session_settings = (array) get_option(EE_Session::OPTION_NAME_SETTINGS, array());
218
-        if (! empty($session_settings)) {
218
+        if ( ! empty($session_settings)) {
219 219
             // cycle though existing session options
220 220
             foreach ($session_settings as $var_name => $session_setting) {
221 221
                 // set values for class properties
222
-                $var_name          = '_' . $var_name;
222
+                $var_name          = '_'.$var_name;
223 223
                 $this->{$var_name} = $session_setting;
224 224
             }
225 225
         }
@@ -257,7 +257,7 @@  discard block
 block discarded – undo
257 257
     public function open_session()
258 258
     {
259 259
         // check for existing session and retrieve it from db
260
-        if (! $this->_espresso_session()) {
260
+        if ( ! $this->_espresso_session()) {
261 261
             // or just start a new one
262 262
             $this->_create_espresso_session();
263 263
         }
@@ -309,7 +309,7 @@  discard block
 block discarded – undo
309 309
      */
310 310
     public function extend_expiration($time = 0)
311 311
     {
312
-        $time              = $time ? $time : $this->extension();
312
+        $time = $time ? $time : $this->extension();
313 313
         $this->_expiration += absint($time);
314 314
     }
315 315
 
@@ -336,9 +336,9 @@  discard block
 block discarded – undo
336 336
         // set some defaults
337 337
         foreach ($this->_default_session_vars as $key => $default_var) {
338 338
             if (is_array($default_var)) {
339
-                $this->_session_data[ $key ] = array();
339
+                $this->_session_data[$key] = array();
340 340
             } else {
341
-                $this->_session_data[ $key ] = '';
341
+                $this->_session_data[$key] = '';
342 342
             }
343 343
         }
344 344
     }
@@ -481,8 +481,8 @@  discard block
 block discarded – undo
481 481
             $this->reset_checkout();
482 482
             $this->reset_transaction();
483 483
         }
484
-        if (! empty($key)) {
485
-            return isset($this->_session_data[ $key ]) ? $this->_session_data[ $key ] : null;
484
+        if ( ! empty($key)) {
485
+            return isset($this->_session_data[$key]) ? $this->_session_data[$key] : null;
486 486
         }
487 487
         return $this->_session_data;
488 488
     }
@@ -506,12 +506,12 @@  discard block
 block discarded – undo
506 506
             return false;
507 507
         }
508 508
         foreach ($data as $key => $value) {
509
-            if (isset($this->_default_session_vars[ $key ])) {
509
+            if (isset($this->_default_session_vars[$key])) {
510 510
                 EE_Error::add_error(sprintf(__('Sorry! %s is a default session datum and can not be reset.',
511 511
                     'event_espresso'), $key), __FILE__, __FUNCTION__, __LINE__);
512 512
                 return false;
513 513
             }
514
-            $this->_session_data[ $key ] = $value;
514
+            $this->_session_data[$key] = $value;
515 515
         }
516 516
         return true;
517 517
     }
@@ -544,7 +544,7 @@  discard block
 block discarded – undo
544 544
         $this->_user_agent = $this->request->userAgent();
545 545
         // now let's retrieve what's in the db
546 546
         $session_data = $this->_retrieve_session_data();
547
-        if (! empty($session_data)) {
547
+        if ( ! empty($session_data)) {
548 548
             // get the current time in UTC
549 549
             $this->_time = $this->_time !== null ? $this->_time : time();
550 550
             // and reset the session expiration
@@ -555,7 +555,7 @@  discard block
 block discarded – undo
555 555
             // set initial site access time and the session expiration
556 556
             $this->_set_init_access_and_expiration();
557 557
             // set referer
558
-            $this->_session_data['pages_visited'][ $this->_session_data['init_access'] ] = isset($_SERVER['HTTP_REFERER'])
558
+            $this->_session_data['pages_visited'][$this->_session_data['init_access']] = isset($_SERVER['HTTP_REFERER'])
559 559
                 ? esc_attr($_SERVER['HTTP_REFERER'])
560 560
                 : '';
561 561
             // no previous session = go back and create one (on top of the data above)
@@ -593,7 +593,7 @@  discard block
 block discarded – undo
593 593
      */
594 594
     protected function _retrieve_session_data()
595 595
     {
596
-        $ssn_key = EE_Session::session_id_prefix . $this->_sid;
596
+        $ssn_key = EE_Session::session_id_prefix.$this->_sid;
597 597
         try {
598 598
             // we're using WP's Transient API to store session data using the PHP session ID as the option name
599 599
             $session_data = $this->cache_storage->get($ssn_key, false);
@@ -602,7 +602,7 @@  discard block
 block discarded – undo
602 602
             }
603 603
             if (apply_filters('FHEE__EE_Session___perform_session_id_hash_check', WP_DEBUG)) {
604 604
                 $hash_check = $this->cache_storage->get(
605
-                    EE_Session::hash_check_prefix . $this->_sid,
605
+                    EE_Session::hash_check_prefix.$this->_sid,
606 606
                     false
607 607
                 );
608 608
                 if ($hash_check && $hash_check !== md5($session_data)) {
@@ -612,7 +612,7 @@  discard block
 block discarded – undo
612 612
                                 'The stored data for session %1$s failed to pass a hash check and therefore appears to be invalid.',
613 613
                                 'event_espresso'
614 614
                             ),
615
-                            EE_Session::session_id_prefix . $this->_sid
615
+                            EE_Session::session_id_prefix.$this->_sid
616 616
                         ),
617 617
                         __FILE__, __FUNCTION__, __LINE__
618 618
                     );
@@ -621,21 +621,21 @@  discard block
 block discarded – undo
621 621
         } catch (Exception $e) {
622 622
             // let's just eat that error for now and attempt to correct any corrupted data
623 623
             global $wpdb;
624
-            $row          = $wpdb->get_row(
624
+            $row = $wpdb->get_row(
625 625
                 $wpdb->prepare(
626 626
                     "SELECT option_value FROM {$wpdb->options} WHERE option_name = %s LIMIT 1",
627
-                    '_transient_' . $ssn_key
627
+                    '_transient_'.$ssn_key
628 628
                 )
629 629
             );
630 630
             $session_data = is_object($row) ? $row->option_value : null;
631 631
             if ($session_data) {
632 632
                 $session_data = preg_replace_callback(
633 633
                     '!s:(d+):"(.*?)";!',
634
-                    function ($match)
634
+                    function($match)
635 635
                     {
636 636
                         return $match[1] === strlen($match[2])
637 637
                             ? $match[0]
638
-                            : 's:' . strlen($match[2]) . ':"' . $match[2] . '";';
638
+                            : 's:'.strlen($match[2]).':"'.$match[2].'";';
639 639
                     },
640 640
                     $session_data
641 641
                 );
@@ -646,7 +646,7 @@  discard block
 block discarded – undo
646 646
         $session_data = $this->encryption instanceof EE_Encryption
647 647
             ? $this->encryption->base64_string_decode($session_data)
648 648
             : $session_data;
649
-        if (! is_array($session_data)) {
649
+        if ( ! is_array($session_data)) {
650 650
             try {
651 651
                 $session_data = maybe_unserialize($session_data);
652 652
             } catch (Exception $e) {
@@ -660,21 +660,21 @@  discard block
 block discarded – undo
660 660
                       . '</pre><br>'
661 661
                       . $this->find_serialize_error($session_data)
662 662
                     : '';
663
-                $this->cache_storage->delete(EE_Session::session_id_prefix . $this->_sid);
663
+                $this->cache_storage->delete(EE_Session::session_id_prefix.$this->_sid);
664 664
                 throw new InvalidSessionDataException($msg, 0, $e);
665 665
             }
666 666
         }
667 667
         // just a check to make sure the session array is indeed an array
668
-        if (! is_array($session_data)) {
668
+        if ( ! is_array($session_data)) {
669 669
             // no?!?! then something is wrong
670 670
             $msg = esc_html__(
671 671
                 'The session data is missing, invalid, or corrupted.',
672 672
                 'event_espresso'
673 673
             );
674 674
             $msg .= WP_DEBUG
675
-                ? '<br><pre>' . print_r($session_data, true) . '</pre><br>' . $this->find_serialize_error($session_data)
675
+                ? '<br><pre>'.print_r($session_data, true).'</pre><br>'.$this->find_serialize_error($session_data)
676 676
                 : '';
677
-            $this->cache_storage->delete(EE_Session::session_id_prefix . $this->_sid);
677
+            $this->cache_storage->delete(EE_Session::session_id_prefix.$this->_sid);
678 678
             throw new InvalidSessionDataException($msg);
679 679
         }
680 680
         if (isset($session_data['transaction']) && absint($session_data['transaction']) !== 0) {
@@ -702,7 +702,7 @@  discard block
 block discarded – undo
702 702
         if (isset($_REQUEST['EESID'])) {
703 703
             $session_id = sanitize_text_field($_REQUEST['EESID']);
704 704
         } else {
705
-            $session_id = md5(session_id() . get_current_blog_id() . $this->_get_sid_salt());
705
+            $session_id = md5(session_id().get_current_blog_id().$this->_get_sid_salt());
706 706
         }
707 707
         return apply_filters('FHEE__EE_Session___generate_session_id__session_id', $session_id);
708 708
     }
@@ -810,19 +810,19 @@  discard block
 block discarded – undo
810 810
                     $page_visit = $this->_get_page_visit();
811 811
                     if ($page_visit) {
812 812
                         // set pages visited where the first will be the http referrer
813
-                        $this->_session_data['pages_visited'][ $this->_time ] = $page_visit;
813
+                        $this->_session_data['pages_visited'][$this->_time] = $page_visit;
814 814
                         // we'll only save the last 10 page visits.
815 815
                         $session_data['pages_visited'] = array_slice($this->_session_data['pages_visited'], -10);
816 816
                     }
817 817
                     break;
818 818
                 default :
819 819
                     // carry any other data over
820
-                    $session_data[ $key ] = $this->_session_data[ $key ];
820
+                    $session_data[$key] = $this->_session_data[$key];
821 821
             }
822 822
         }
823 823
         $this->_session_data = $session_data;
824 824
         // creating a new session does not require saving to the db just yet
825
-        if (! $new_session) {
825
+        if ( ! $new_session) {
826 826
             // ready? let's save
827 827
             if ($this->_save_session_to_db()) {
828 828
                 return true;
@@ -867,12 +867,12 @@  discard block
 block discarded – undo
867 867
     {
868 868
         // don't save sessions for crawlers
869 869
         // and unless we're deleting the session data, don't save anything if there isn't a cart
870
-        if ($this->request->isBot() || (! $clear_session && ! $this->cart() instanceof EE_Cart)) {
870
+        if ($this->request->isBot() || ( ! $clear_session && ! $this->cart() instanceof EE_Cart)) {
871 871
             return false;
872 872
         }
873 873
         $transaction = $this->transaction();
874 874
         if ($transaction instanceof EE_Transaction) {
875
-            if (! $transaction->ID()) {
875
+            if ( ! $transaction->ID()) {
876 876
                 $transaction->save();
877 877
             }
878 878
             $this->_session_data['transaction'] = $transaction->ID();
@@ -886,14 +886,14 @@  discard block
 block discarded – undo
886 886
         // maybe save hash check
887 887
         if (apply_filters('FHEE__EE_Session___perform_session_id_hash_check', WP_DEBUG)) {
888 888
             $this->cache_storage->add(
889
-                EE_Session::hash_check_prefix . $this->_sid,
889
+                EE_Session::hash_check_prefix.$this->_sid,
890 890
                 md5($session_data),
891 891
                 $this->session_lifespan->inSeconds()
892 892
             );
893 893
         }
894 894
         // we're using the Transient API for storing session data,
895 895
         return $this->cache_storage->add(
896
-            EE_Session::session_id_prefix . $this->_sid,
896
+            EE_Session::session_id_prefix.$this->_sid,
897 897
             $session_data,
898 898
             $this->session_lifespan->inSeconds()
899 899
         );
@@ -907,7 +907,7 @@  discard block
 block discarded – undo
907 907
      */
908 908
     public function _get_page_visit()
909 909
     {
910
-        $page_visit = home_url('/') . 'wp-admin/admin-ajax.php';
910
+        $page_visit = home_url('/').'wp-admin/admin-ajax.php';
911 911
         // check for request url
912 912
         if (isset($_SERVER['REQUEST_URI'])) {
913 913
             $http_host   = '';
@@ -923,14 +923,14 @@  discard block
 block discarded – undo
923 923
             // check for page_id in SERVER REQUEST
924 924
             if (isset($_REQUEST['page_id'])) {
925 925
                 // rebuild $e_reg without any of the extra parameters
926
-                $page_id = '?page_id=' . esc_attr($_REQUEST['page_id']) . '&amp;';
926
+                $page_id = '?page_id='.esc_attr($_REQUEST['page_id']).'&amp;';
927 927
             }
928 928
             // check for $e_reg in SERVER REQUEST
929 929
             if (isset($_REQUEST['ee'])) {
930 930
                 // rebuild $e_reg without any of the extra parameters
931
-                $e_reg = 'ee=' . esc_attr($_REQUEST['ee']);
931
+                $e_reg = 'ee='.esc_attr($_REQUEST['ee']);
932 932
             }
933
-            $page_visit = rtrim($http_host . $request_uri . $page_id . $e_reg, '?');
933
+            $page_visit = rtrim($http_host.$request_uri.$page_id.$e_reg, '?');
934 934
         }
935 935
         return $page_visit !== home_url('/wp-admin/admin-ajax.php') ? $page_visit : '';
936 936
     }
@@ -965,7 +965,7 @@  discard block
 block discarded – undo
965 965
      */
966 966
     public function clear_session($class = '', $function = '')
967 967
     {
968
-        do_action('AHEE_log', __FILE__, __FUNCTION__, 'session cleared by : ' . $class . '::' . $function . '()');
968
+        do_action('AHEE_log', __FILE__, __FUNCTION__, 'session cleared by : '.$class.'::'.$function.'()');
969 969
         $this->reset_cart();
970 970
         $this->reset_checkout();
971 971
         $this->reset_transaction();
@@ -988,7 +988,7 @@  discard block
 block discarded – undo
988 988
     public function reset_data($data_to_reset = array(), $show_all_notices = false)
989 989
     {
990 990
         // if $data_to_reset is not in an array, then put it in one
991
-        if (! is_array($data_to_reset)) {
991
+        if ( ! is_array($data_to_reset)) {
992 992
             $data_to_reset = array($data_to_reset);
993 993
         }
994 994
         // nothing ??? go home!
@@ -1002,11 +1002,11 @@  discard block
 block discarded – undo
1002 1002
         foreach ($data_to_reset as $reset) {
1003 1003
 
1004 1004
             // first check to make sure it is a valid session var
1005
-            if (isset($this->_session_data[ $reset ])) {
1005
+            if (isset($this->_session_data[$reset])) {
1006 1006
                 // then check to make sure it is not a default var
1007
-                if (! array_key_exists($reset, $this->_default_session_vars)) {
1007
+                if ( ! array_key_exists($reset, $this->_default_session_vars)) {
1008 1008
                     // remove session var
1009
-                    unset($this->_session_data[ $reset ]);
1009
+                    unset($this->_session_data[$reset]);
1010 1010
                     if ($show_all_notices) {
1011 1011
                         EE_Error::add_success(sprintf(__('The session variable %s was removed.', 'event_espresso'),
1012 1012
                             $reset), __FILE__, __FUNCTION__, __LINE__);
@@ -1083,7 +1083,7 @@  discard block
 block discarded – undo
1083 1083
             // or use that for the new transient cleanup query limit
1084 1084
             add_filter(
1085 1085
                 'FHEE__TransientCacheStorage__clearExpiredTransients__limit',
1086
-                function () use ($expired_session_transient_delete_query_limit)
1086
+                function() use ($expired_session_transient_delete_query_limit)
1087 1087
                 {
1088 1088
                     return $expired_session_transient_delete_query_limit;
1089 1089
                 }
@@ -1103,7 +1103,7 @@  discard block
 block discarded – undo
1103 1103
         $error = '<pre>';
1104 1104
         $data2 = preg_replace_callback(
1105 1105
             '!s:(\d+):"(.*?)";!',
1106
-            function ($match)
1106
+            function($match)
1107 1107
             {
1108 1108
                 return ($match[1] === strlen($match[2]))
1109 1109
                     ? $match[0]
@@ -1115,14 +1115,14 @@  discard block
 block discarded – undo
1115 1115
             },
1116 1116
             $data1
1117 1117
         );
1118
-        $max   = (strlen($data1) > strlen($data2)) ? strlen($data1) : strlen($data2);
1119
-        $error .= $data1 . PHP_EOL;
1120
-        $error .= $data2 . PHP_EOL;
1118
+        $max = (strlen($data1) > strlen($data2)) ? strlen($data1) : strlen($data2);
1119
+        $error .= $data1.PHP_EOL;
1120
+        $error .= $data2.PHP_EOL;
1121 1121
         for ($i = 0; $i < $max; $i++) {
1122
-            if (@$data1[ $i ] !== @$data2[ $i ]) {
1123
-                $error  .= 'Difference ' . @$data1[ $i ] . ' != ' . @$data2[ $i ] . PHP_EOL;
1124
-                $error  .= "\t-> ORD number " . ord(@$data1[ $i ]) . ' != ' . ord(@$data2[ $i ]) . PHP_EOL;
1125
-                $error  .= "\t-> Line Number = $i" . PHP_EOL;
1122
+            if (@$data1[$i] !== @$data2[$i]) {
1123
+                $error  .= 'Difference '.@$data1[$i].' != '.@$data2[$i].PHP_EOL;
1124
+                $error  .= "\t-> ORD number ".ord(@$data1[$i]).' != '.ord(@$data2[$i]).PHP_EOL;
1125
+                $error  .= "\t-> Line Number = $i".PHP_EOL;
1126 1126
                 $start  = ($i - 20);
1127 1127
                 $start  = ($start < 0) ? 0 : $start;
1128 1128
                 $length = 40;
@@ -1137,7 +1137,7 @@  discard block
 block discarded – undo
1137 1137
                 $error .= "\t-> Section Data1  = ";
1138 1138
                 $error .= substr_replace(
1139 1139
                     substr($data1, $start, $length),
1140
-                    "<b style=\"color:green\">{$data1[ $i ]}</b>",
1140
+                    "<b style=\"color:green\">{$data1[$i]}</b>",
1141 1141
                     $rpoint,
1142 1142
                     $rlength
1143 1143
                 );
@@ -1145,7 +1145,7 @@  discard block
 block discarded – undo
1145 1145
                 $error .= "\t-> Section Data2  = ";
1146 1146
                 $error .= substr_replace(
1147 1147
                     substr($data2, $start, $length),
1148
-                    "<b style=\"color:red\">{$data2[ $i ]}</b>",
1148
+                    "<b style=\"color:red\">{$data2[$i]}</b>",
1149 1149
                     $rpoint,
1150 1150
                     $rlength
1151 1151
                 );
@@ -1176,7 +1176,7 @@  discard block
 block discarded – undo
1176 1176
     public function garbageCollection()
1177 1177
     {
1178 1178
         // only perform during regular requests if last garbage collection was over an hour ago
1179
-        if (! (defined('DOING_AJAX') && DOING_AJAX) && (time() - HOUR_IN_SECONDS) >= $this->_last_gc) {
1179
+        if ( ! (defined('DOING_AJAX') && DOING_AJAX) && (time() - HOUR_IN_SECONDS) >= $this->_last_gc) {
1180 1180
             $this->_last_gc = time();
1181 1181
             $this->updateSessionSettings(array('last_gc' => $this->_last_gc));
1182 1182
             /** @type WPDB $wpdb */
@@ -1211,7 +1211,7 @@  discard block
 block discarded – undo
1211 1211
                 // AND option_value < 1508368198 LIMIT 50
1212 1212
                 $expired_sessions = $wpdb->get_col($SQL);
1213 1213
                 // valid results?
1214
-                if (! $expired_sessions instanceof WP_Error && ! empty($expired_sessions)) {
1214
+                if ( ! $expired_sessions instanceof WP_Error && ! empty($expired_sessions)) {
1215 1215
                     $this->cache_storage->deleteMany($expired_sessions, true);
1216 1216
                 }
1217 1217
             }
Please login to merge, or discard this patch.