Completed
Branch FET/11450/reserved-instance-in... (8a8133)
by
unknown
125:36 queued 112:25
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/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_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.
admin_pages/registrations/Registrations_Admin_Page.core.php 2 patches
Indentation   +3722 added lines, -3722 removed lines patch added patch discarded remove patch
@@ -30,2339 +30,2339 @@  discard block
 block discarded – undo
30 30
 class Registrations_Admin_Page extends EE_Admin_Page_CPT
31 31
 {
32 32
 
33
-    /**
34
-     * @var EE_Registration
35
-     */
36
-    private $_registration;
37
-
38
-    /**
39
-     * @var EE_Event
40
-     */
41
-    private $_reg_event;
42
-
43
-    /**
44
-     * @var EE_Session
45
-     */
46
-    private $_session;
47
-
48
-    private static $_reg_status;
49
-
50
-    /**
51
-     * Form for displaying the custom questions for this registration.
52
-     * This gets used a few times throughout the request so its best to cache it
53
-     *
54
-     * @var EE_Registration_Custom_Questions_Form
55
-     */
56
-    protected $_reg_custom_questions_form = null;
57
-
58
-
59
-    /**
60
-     *        constructor
61
-     *
62
-     * @Constructor
63
-     * @access public
64
-     * @param bool $routing
65
-     * @return Registrations_Admin_Page
66
-     */
67
-    public function __construct($routing = true)
68
-    {
69
-        parent::__construct($routing);
70
-        add_action('wp_loaded', array($this, 'wp_loaded'));
71
-    }
72
-
73
-
74
-    public function wp_loaded()
75
-    {
76
-        // when adding a new registration...
77
-        if (isset($this->_req_data['action']) && $this->_req_data['action'] === 'new_registration') {
78
-            EE_System::do_not_cache();
79
-            if (! isset($this->_req_data['processing_registration'])
80
-                 || absint($this->_req_data['processing_registration']) !== 1
81
-            ) {
82
-                // and it's NOT the attendee information reg step
83
-                // force cookie expiration by setting time to last week
84
-                setcookie('ee_registration_added', 0, time() - WEEK_IN_SECONDS, '/');
85
-                // and update the global
86
-                $_COOKIE['ee_registration_added'] = 0;
87
-            }
88
-        }
89
-    }
90
-
91
-
92
-    protected function _init_page_props()
93
-    {
94
-        $this->page_slug        = REG_PG_SLUG;
95
-        $this->_admin_base_url  = REG_ADMIN_URL;
96
-        $this->_admin_base_path = REG_ADMIN;
97
-        $this->page_label       = esc_html__('Registrations', 'event_espresso');
98
-        $this->_cpt_routes      = array(
99
-            'add_new_attendee' => 'espresso_attendees',
100
-            'edit_attendee'    => 'espresso_attendees',
101
-            'insert_attendee'  => 'espresso_attendees',
102
-            'update_attendee'  => 'espresso_attendees',
103
-        );
104
-        $this->_cpt_model_names = array(
105
-            'add_new_attendee' => 'EEM_Attendee',
106
-            'edit_attendee'    => 'EEM_Attendee',
107
-        );
108
-        $this->_cpt_edit_routes = array(
109
-            'espresso_attendees' => 'edit_attendee',
110
-        );
111
-        $this->_pagenow_map     = array(
112
-            'add_new_attendee' => 'post-new.php',
113
-            'edit_attendee'    => 'post.php',
114
-            'trash'            => 'post.php',
115
-        );
116
-        add_action('edit_form_after_title', array($this, 'after_title_form_fields'), 10);
117
-        //add filters so that the comment urls don't take users to a confusing 404 page
118
-        add_filter('get_comment_link', array($this, 'clear_comment_link'), 10, 3);
119
-    }
120
-
121
-
122
-    public function clear_comment_link($link, $comment, $args)
123
-    {
124
-        //gotta make sure this only happens on this route
125
-        $post_type = get_post_type($comment->comment_post_ID);
126
-        if ($post_type === 'espresso_attendees') {
127
-            return '#commentsdiv';
128
-        }
129
-        return $link;
130
-    }
131
-
132
-
133
-    protected function _ajax_hooks()
134
-    {
135
-        //todo: all hooks for registrations ajax goes in here
136
-        add_action('wp_ajax_toggle_checkin_status', array($this, 'toggle_checkin_status'));
137
-    }
138
-
139
-
140
-    protected function _define_page_props()
141
-    {
142
-        $this->_admin_page_title = $this->page_label;
143
-        $this->_labels           = array(
144
-            'buttons'                      => array(
145
-                'add-registrant'      => esc_html__('Add New Registration', 'event_espresso'),
146
-                'add-attendee'        => esc_html__('Add Contact', 'event_espresso'),
147
-                'edit'                => esc_html__('Edit Contact', 'event_espresso'),
148
-                'report'              => esc_html__("Event Registrations CSV Report", "event_espresso"),
149
-                'report_all'          => esc_html__('All Registrations CSV Report', 'event_espresso'),
150
-                'report_filtered'     => esc_html__('Filtered CSV Report', 'event_espresso'),
151
-                'contact_list_report' => esc_html__('Contact List Report', 'event_espresso'),
152
-                'contact_list_export' => esc_html__("Export Data", "event_espresso"),
153
-            ),
154
-            'publishbox'                   => array(
155
-                'add_new_attendee' => esc_html__("Add Contact Record", 'event_espresso'),
156
-                'edit_attendee'    => esc_html__("Update Contact Record", 'event_espresso'),
157
-            ),
158
-            'hide_add_button_on_cpt_route' => array(
159
-                'edit_attendee' => true,
160
-            ),
161
-        );
162
-    }
163
-
164
-
165
-    /**
166
-     *        grab url requests and route them
167
-     *
168
-     * @access private
169
-     * @return void
170
-     */
171
-    public function _set_page_routes()
172
-    {
173
-        $this->_get_registration_status_array();
174
-        $reg_id             = ! empty($this->_req_data['_REG_ID']) && ! is_array($this->_req_data['_REG_ID'])
175
-            ? $this->_req_data['_REG_ID'] : 0;
176
-        $reg_id = empty($reg_id) && ! empty($this->_req_data['reg_status_change_form']['REG_ID'])
177
-            ? $this->_req_data['reg_status_change_form']['REG_ID']
178
-            : $reg_id;
179
-        $att_id             = ! empty($this->_req_data['ATT_ID']) && ! is_array($this->_req_data['ATT_ID'])
180
-            ? $this->_req_data['ATT_ID'] : 0;
181
-        $att_id             = ! empty($this->_req_data['post']) && ! is_array($this->_req_data['post'])
182
-            ? $this->_req_data['post']
183
-            : $att_id;
184
-        $this->_page_routes = array(
185
-            'default'                            => array(
186
-                'func'       => '_registrations_overview_list_table',
187
-                'capability' => 'ee_read_registrations',
188
-            ),
189
-            'view_registration'                  => array(
190
-                'func'       => '_registration_details',
191
-                'capability' => 'ee_read_registration',
192
-                'obj_id'     => $reg_id,
193
-            ),
194
-            'edit_registration'                  => array(
195
-                'func'               => '_update_attendee_registration_form',
196
-                'noheader'           => true,
197
-                'headers_sent_route' => 'view_registration',
198
-                'capability'         => 'ee_edit_registration',
199
-                'obj_id'             => $reg_id,
200
-                '_REG_ID'            => $reg_id,
201
-            ),
202
-            'trash_registrations'                => array(
203
-                'func'       => '_trash_or_restore_registrations',
204
-                'args'       => array('trash' => true),
205
-                'noheader'   => true,
206
-                'capability' => 'ee_delete_registrations',
207
-            ),
208
-            'restore_registrations'              => array(
209
-                'func'       => '_trash_or_restore_registrations',
210
-                'args'       => array('trash' => false),
211
-                'noheader'   => true,
212
-                'capability' => 'ee_delete_registrations',
213
-            ),
214
-            'delete_registrations'               => array(
215
-                'func'       => '_delete_registrations',
216
-                'noheader'   => true,
217
-                'capability' => 'ee_delete_registrations',
218
-            ),
219
-            'new_registration'                   => array(
220
-                'func'       => 'new_registration',
221
-                'capability' => 'ee_edit_registrations',
222
-            ),
223
-            'process_reg_step'                   => array(
224
-                'func'       => 'process_reg_step',
225
-                'noheader'   => true,
226
-                'capability' => 'ee_edit_registrations',
227
-            ),
228
-            'redirect_to_txn'                    => array(
229
-                'func'       => 'redirect_to_txn',
230
-                'noheader'   => true,
231
-                'capability' => 'ee_edit_registrations',
232
-            ),
233
-            'change_reg_status'                  => array(
234
-                'func'       => '_change_reg_status',
235
-                'noheader'   => true,
236
-                'capability' => 'ee_edit_registration',
237
-                'obj_id'     => $reg_id,
238
-            ),
239
-            'approve_registration'               => array(
240
-                'func'       => 'approve_registration',
241
-                'noheader'   => true,
242
-                'capability' => 'ee_edit_registration',
243
-                'obj_id'     => $reg_id,
244
-            ),
245
-            'approve_and_notify_registration'    => array(
246
-                'func'       => 'approve_registration',
247
-                'noheader'   => true,
248
-                'args'       => array(true),
249
-                'capability' => 'ee_edit_registration',
250
-                'obj_id'     => $reg_id,
251
-            ),
252
-            'approve_registrations'               => array(
253
-                'func'       => 'bulk_action_on_registrations',
254
-                'noheader'   => true,
255
-                'capability' => 'ee_edit_registrations',
256
-                'args' => array('approve')
257
-            ),
258
-            'approve_and_notify_registrations'               => array(
259
-                'func'       => 'bulk_action_on_registrations',
260
-                'noheader'   => true,
261
-                'capability' => 'ee_edit_registrations',
262
-                'args' => array('approve', true)
263
-            ),
264
-            'decline_registration'               => array(
265
-                'func'       => 'decline_registration',
266
-                'noheader'   => true,
267
-                'capability' => 'ee_edit_registration',
268
-                'obj_id'     => $reg_id,
269
-            ),
270
-            'decline_and_notify_registration'    => array(
271
-                'func'       => 'decline_registration',
272
-                'noheader'   => true,
273
-                'args'       => array(true),
274
-                'capability' => 'ee_edit_registration',
275
-                'obj_id'     => $reg_id,
276
-            ),
277
-            'decline_registrations'               => array(
278
-                'func'       => 'bulk_action_on_registrations',
279
-                'noheader'   => true,
280
-                'capability' => 'ee_edit_registrations',
281
-                'args' => array('decline')
282
-            ),
283
-            'decline_and_notify_registrations'    => array(
284
-                'func'       => 'bulk_action_on_registrations',
285
-                'noheader'   => true,
286
-                'capability' => 'ee_edit_registrations',
287
-                'args' => array('decline', true)
288
-            ),
289
-            'pending_registration'               => array(
290
-                'func'       => 'pending_registration',
291
-                'noheader'   => true,
292
-                'capability' => 'ee_edit_registration',
293
-                'obj_id'     => $reg_id,
294
-            ),
295
-            'pending_and_notify_registration'    => array(
296
-                'func'       => 'pending_registration',
297
-                'noheader'   => true,
298
-                'args'       => array(true),
299
-                'capability' => 'ee_edit_registration',
300
-                'obj_id'     => $reg_id,
301
-            ),
302
-            'pending_registrations'               => array(
303
-                'func'       => 'bulk_action_on_registrations',
304
-                'noheader'   => true,
305
-                'capability' => 'ee_edit_registrations',
306
-                'args' => array('pending')
307
-            ),
308
-            'pending_and_notify_registrations'    => array(
309
-                'func'       => 'bulk_action_on_registrations',
310
-                'noheader'   => true,
311
-                'capability' => 'ee_edit_registrations',
312
-                'args' => array('pending', true)
313
-            ),
314
-            'no_approve_registration'            => array(
315
-                'func'       => 'not_approve_registration',
316
-                'noheader'   => true,
317
-                'capability' => 'ee_edit_registration',
318
-                'obj_id'     => $reg_id,
319
-            ),
320
-            'no_approve_and_notify_registration' => array(
321
-                'func'       => 'not_approve_registration',
322
-                'noheader'   => true,
323
-                'args'       => array(true),
324
-                'capability' => 'ee_edit_registration',
325
-                'obj_id'     => $reg_id,
326
-            ),
327
-            'no_approve_registrations'            => array(
328
-                'func'       => 'bulk_action_on_registrations',
329
-                'noheader'   => true,
330
-                'capability' => 'ee_edit_registrations',
331
-                'args' => array('not_approve')
332
-            ),
333
-            'no_approve_and_notify_registrations' => array(
334
-                'func'       => 'bulk_action_on_registrations',
335
-                'noheader'   => true,
336
-                'capability' => 'ee_edit_registrations',
337
-                'args' => array('not_approve', true)
338
-            ),
339
-            'cancel_registration'                => array(
340
-                'func'       => 'cancel_registration',
341
-                'noheader'   => true,
342
-                'capability' => 'ee_edit_registration',
343
-                'obj_id'     => $reg_id,
344
-            ),
345
-            'cancel_and_notify_registration'     => array(
346
-                'func'       => 'cancel_registration',
347
-                'noheader'   => true,
348
-                'args'       => array(true),
349
-                'capability' => 'ee_edit_registration',
350
-                'obj_id'     => $reg_id,
351
-            ),
352
-            'cancel_registrations'                => array(
353
-                'func'       => 'bulk_action_on_registrations',
354
-                'noheader'   => true,
355
-                'capability' => 'ee_edit_registrations',
356
-                'args' => array('cancel')
357
-            ),
358
-            'cancel_and_notify_registrations'     => array(
359
-                'func'       => 'bulk_action_on_registrations',
360
-                'noheader'   => true,
361
-                'capability' => 'ee_edit_registrations',
362
-                'args' => array('cancel', true)
363
-            ),
364
-            'wait_list_registration' => array(
365
-                'func'       => 'wait_list_registration',
366
-                'noheader'   => true,
367
-                'capability' => 'ee_edit_registration',
368
-                'obj_id'     => $reg_id,
369
-            ),
370
-            'wait_list_and_notify_registration' => array(
371
-                'func'       => 'wait_list_registration',
372
-                'noheader'   => true,
373
-                'args'       => array(true),
374
-                'capability' => 'ee_edit_registration',
375
-                'obj_id'     => $reg_id,
376
-            ),
377
-            'contact_list'                       => array(
378
-                'func'       => '_attendee_contact_list_table',
379
-                'capability' => 'ee_read_contacts',
380
-            ),
381
-            'add_new_attendee'                   => array(
382
-                'func' => '_create_new_cpt_item',
383
-                'args' => array(
384
-                    'new_attendee' => true,
385
-                    'capability'   => 'ee_edit_contacts',
386
-                ),
387
-            ),
388
-            'edit_attendee'                      => array(
389
-                'func'       => '_edit_cpt_item',
390
-                'capability' => 'ee_edit_contacts',
391
-                'obj_id'     => $att_id,
392
-            ),
393
-            'duplicate_attendee'                 => array(
394
-                'func'       => '_duplicate_attendee',
395
-                'noheader'   => true,
396
-                'capability' => 'ee_edit_contacts',
397
-                'obj_id'     => $att_id,
398
-            ),
399
-            'insert_attendee'                    => array(
400
-                'func'       => '_insert_or_update_attendee',
401
-                'args'       => array(
402
-                    'new_attendee' => true,
403
-                ),
404
-                'noheader'   => true,
405
-                'capability' => 'ee_edit_contacts',
406
-            ),
407
-            'update_attendee'                    => array(
408
-                'func'       => '_insert_or_update_attendee',
409
-                'args'       => array(
410
-                    'new_attendee' => false,
411
-                ),
412
-                'noheader'   => true,
413
-                'capability' => 'ee_edit_contacts',
414
-                'obj_id'     => $att_id,
415
-            ),
416
-            'trash_attendees' => array(
417
-                'func' => '_trash_or_restore_attendees',
418
-                'args' => array(
419
-                    'trash' => 'true'
420
-                ),
421
-                'noheader' => true,
422
-                'capability' => 'ee_delete_contacts'
423
-            ),
424
-            'trash_attendee'                    => array(
425
-                'func'       => '_trash_or_restore_attendees',
426
-                'args'       => array(
427
-                    'trash' => true,
428
-                ),
429
-                'noheader'   => true,
430
-                'capability' => 'ee_delete_contacts',
431
-                'obj_id'     => $att_id,
432
-            ),
433
-            'restore_attendees'                  => array(
434
-                'func'       => '_trash_or_restore_attendees',
435
-                'args'       => array(
436
-                    'trash' => false,
437
-                ),
438
-                'noheader'   => true,
439
-                'capability' => 'ee_delete_contacts',
440
-                'obj_id'     => $att_id,
441
-            ),
442
-            'resend_registration'                => array(
443
-                'func'       => '_resend_registration',
444
-                'noheader'   => true,
445
-                'capability' => 'ee_send_message',
446
-            ),
447
-            'registrations_report'               => array(
448
-                'func'       => '_registrations_report',
449
-                'noheader'   => true,
450
-                'capability' => 'ee_read_registrations',
451
-            ),
452
-            'contact_list_export'                => array(
453
-                'func'       => '_contact_list_export',
454
-                'noheader'   => true,
455
-                'capability' => 'export',
456
-            ),
457
-            'contact_list_report'                => array(
458
-                'func'       => '_contact_list_report',
459
-                'noheader'   => true,
460
-                'capability' => 'ee_read_contacts',
461
-            ),
462
-        );
463
-    }
464
-
465
-
466
-    protected function _set_page_config()
467
-    {
468
-        $this->_page_config = array(
469
-            'default'           => array(
470
-                'nav'           => array(
471
-                    'label' => esc_html__('Overview', 'event_espresso'),
472
-                    'order' => 5,
473
-                ),
474
-                'help_tabs'     => array(
475
-                    'registrations_overview_help_tab'                       => array(
476
-                        'title'    => esc_html__('Registrations Overview', 'event_espresso'),
477
-                        'filename' => 'registrations_overview',
478
-                    ),
479
-                    'registrations_overview_table_column_headings_help_tab' => array(
480
-                        'title'    => esc_html__('Registrations Table Column Headings', 'event_espresso'),
481
-                        'filename' => 'registrations_overview_table_column_headings',
482
-                    ),
483
-                    'registrations_overview_filters_help_tab'               => array(
484
-                        'title'    => esc_html__('Registration Filters', 'event_espresso'),
485
-                        'filename' => 'registrations_overview_filters',
486
-                    ),
487
-                    'registrations_overview_views_help_tab'                 => array(
488
-                        'title'    => esc_html__('Registration Views', 'event_espresso'),
489
-                        'filename' => 'registrations_overview_views',
490
-                    ),
491
-                    'registrations_regoverview_other_help_tab'              => array(
492
-                        'title'    => esc_html__('Registrations Other', 'event_espresso'),
493
-                        'filename' => 'registrations_overview_other',
494
-                    ),
495
-                ),
496
-                'help_tour'     => array('Registration_Overview_Help_Tour'),
497
-                'qtips'         => array('Registration_List_Table_Tips'),
498
-                'list_table'    => 'EE_Registrations_List_Table',
499
-                'require_nonce' => false,
500
-            ),
501
-            'view_registration' => array(
502
-                'nav'           => array(
503
-                    'label'      => esc_html__('REG Details', 'event_espresso'),
504
-                    'order'      => 15,
505
-                    'url'        => isset($this->_req_data['_REG_ID'])
506
-                        ? add_query_arg(array('_REG_ID' => $this->_req_data['_REG_ID']), $this->_current_page_view_url)
507
-                        : $this->_admin_base_url,
508
-                    'persistent' => false,
509
-                ),
510
-                'help_tabs'     => array(
511
-                    'registrations_details_help_tab'                    => array(
512
-                        'title'    => esc_html__('Registration Details', 'event_espresso'),
513
-                        'filename' => 'registrations_details',
514
-                    ),
515
-                    'registrations_details_table_help_tab'              => array(
516
-                        'title'    => esc_html__('Registration Details Table', 'event_espresso'),
517
-                        'filename' => 'registrations_details_table',
518
-                    ),
519
-                    'registrations_details_form_answers_help_tab'       => array(
520
-                        'title'    => esc_html__('Registration Form Answers', 'event_espresso'),
521
-                        'filename' => 'registrations_details_form_answers',
522
-                    ),
523
-                    'registrations_details_registrant_details_help_tab' => array(
524
-                        'title'    => esc_html__('Contact Details', 'event_espresso'),
525
-                        'filename' => 'registrations_details_registrant_details',
526
-                    ),
527
-                ),
528
-                'help_tour'     => array('Registration_Details_Help_Tour'),
529
-                'metaboxes'     => array_merge(
530
-                    $this->_default_espresso_metaboxes,
531
-                    array('_registration_details_metaboxes')
532
-                ),
533
-                'require_nonce' => false,
534
-            ),
535
-            'new_registration'  => array(
536
-                'nav'           => array(
537
-                    'label'      => esc_html__('Add New Registration', 'event_espresso'),
538
-                    'url'        => '#',
539
-                    'order'      => 15,
540
-                    'persistent' => false,
541
-                ),
542
-                'metaboxes'     => $this->_default_espresso_metaboxes,
543
-                'labels'        => array(
544
-                    'publishbox' => esc_html__('Save Registration', 'event_espresso'),
545
-                ),
546
-                'require_nonce' => false,
547
-            ),
548
-            'add_new_attendee'  => array(
549
-                'nav'           => array(
550
-                    'label'      => esc_html__('Add Contact', 'event_espresso'),
551
-                    'order'      => 15,
552
-                    'persistent' => false,
553
-                ),
554
-                'metaboxes'     => array_merge(
555
-                    $this->_default_espresso_metaboxes,
556
-                    array('_publish_post_box', 'attendee_editor_metaboxes')
557
-                ),
558
-                'require_nonce' => false,
559
-            ),
560
-            'edit_attendee'     => array(
561
-                'nav'           => array(
562
-                    'label'      => esc_html__('Edit Contact', 'event_espresso'),
563
-                    'order'      => 15,
564
-                    'persistent' => false,
565
-                    'url'        => isset($this->_req_data['ATT_ID'])
566
-                        ? add_query_arg(array('ATT_ID' => $this->_req_data['ATT_ID']), $this->_current_page_view_url)
567
-                        : $this->_admin_base_url,
568
-                ),
569
-                'metaboxes'     => array('attendee_editor_metaboxes'),
570
-                'require_nonce' => false,
571
-            ),
572
-            'contact_list'      => array(
573
-                'nav'           => array(
574
-                    'label' => esc_html__('Contact List', 'event_espresso'),
575
-                    'order' => 20,
576
-                ),
577
-                'list_table'    => 'EE_Attendee_Contact_List_Table',
578
-                'help_tabs'     => array(
579
-                    'registrations_contact_list_help_tab'                       => array(
580
-                        'title'    => esc_html__('Registrations Contact List', 'event_espresso'),
581
-                        'filename' => 'registrations_contact_list',
582
-                    ),
583
-                    'registrations_contact-list_table_column_headings_help_tab' => array(
584
-                        'title'    => esc_html__('Contact List Table Column Headings', 'event_espresso'),
585
-                        'filename' => 'registrations_contact_list_table_column_headings',
586
-                    ),
587
-                    'registrations_contact_list_views_help_tab'                 => array(
588
-                        'title'    => esc_html__('Contact List Views', 'event_espresso'),
589
-                        'filename' => 'registrations_contact_list_views',
590
-                    ),
591
-                    'registrations_contact_list_other_help_tab'                 => array(
592
-                        'title'    => esc_html__('Contact List Other', 'event_espresso'),
593
-                        'filename' => 'registrations_contact_list_other',
594
-                    ),
595
-                ),
596
-                'help_tour'     => array('Contact_List_Help_Tour'),
597
-                'metaboxes'     => array(),
598
-                'require_nonce' => false,
599
-            ),
600
-            //override default cpt routes
601
-            'create_new'        => '',
602
-            'edit'              => '',
603
-        );
604
-    }
605
-
606
-
607
-    /**
608
-     * The below methods aren't used by this class currently
609
-     */
610
-    protected function _add_screen_options()
611
-    {
612
-    }
613
-
614
-
615
-    protected function _add_feature_pointers()
616
-    {
617
-    }
618
-
619
-
620
-    public function admin_init()
621
-    {
622
-        EE_Registry::$i18n_js_strings['update_att_qstns'] = esc_html__(
623
-            'click "Update Registration Questions" to save your changes',
624
-            'event_espresso'
625
-        );
626
-    }
627
-
628
-
629
-    public function admin_notices()
630
-    {
631
-    }
632
-
633
-
634
-    public function admin_footer_scripts()
635
-    {
636
-    }
637
-
638
-
639
-    /**
640
-     *        get list of registration statuses
641
-     *
642
-     * @access private
643
-     * @return void
644
-     * @throws EE_Error
645
-     */
646
-    private function _get_registration_status_array()
647
-    {
648
-        self::$_reg_status = EEM_Registration::reg_status_array(array(), true);
649
-    }
650
-
651
-
652
-    protected function _add_screen_options_default()
653
-    {
654
-        $this->_per_page_screen_option();
655
-    }
656
-
657
-
658
-    protected function _add_screen_options_contact_list()
659
-    {
660
-        $page_title              = $this->_admin_page_title;
661
-        $this->_admin_page_title = esc_html__("Contacts", 'event_espresso');
662
-        $this->_per_page_screen_option();
663
-        $this->_admin_page_title = $page_title;
664
-    }
665
-
666
-
667
-    public function load_scripts_styles()
668
-    {
669
-        //style
670
-        wp_register_style(
671
-            'espresso_reg',
672
-            REG_ASSETS_URL . 'espresso_registrations_admin.css',
673
-            array('ee-admin-css'),
674
-            EVENT_ESPRESSO_VERSION
675
-        );
676
-        wp_enqueue_style('espresso_reg');
677
-        //script
678
-        wp_register_script(
679
-            'espresso_reg',
680
-            REG_ASSETS_URL . 'espresso_registrations_admin.js',
681
-            array('jquery-ui-datepicker', 'jquery-ui-draggable', 'ee_admin_js'),
682
-            EVENT_ESPRESSO_VERSION,
683
-            true
684
-        );
685
-        wp_enqueue_script('espresso_reg');
686
-    }
687
-
688
-
689
-    public function load_scripts_styles_edit_attendee()
690
-    {
691
-        //stuff to only show up on our attendee edit details page.
692
-        $attendee_details_translations = array(
693
-            'att_publish_text' => sprintf(
694
-                esc_html__('Created on: <b>%1$s</b>', 'event_espresso'),
695
-                $this->_cpt_model_obj->get_datetime('ATT_created')
696
-            ),
697
-        );
698
-        wp_localize_script('espresso_reg', 'ATTENDEE_DETAILS', $attendee_details_translations);
699
-        wp_enqueue_script('jquery-validate');
700
-    }
701
-
702
-
703
-    public function load_scripts_styles_view_registration()
704
-    {
705
-        //styles
706
-        wp_enqueue_style('espresso-ui-theme');
707
-        //scripts
708
-        $this->_get_reg_custom_questions_form($this->_registration->ID());
709
-        $this->_reg_custom_questions_form->wp_enqueue_scripts(true);
710
-    }
711
-
712
-
713
-    public function load_scripts_styles_contact_list()
714
-    {
715
-        wp_dequeue_style('espresso_reg');
716
-        wp_register_style(
717
-            'espresso_att',
718
-            REG_ASSETS_URL . 'espresso_attendees_admin.css',
719
-            array('ee-admin-css'),
720
-            EVENT_ESPRESSO_VERSION
721
-        );
722
-        wp_enqueue_style('espresso_att');
723
-    }
724
-
725
-
726
-    public function load_scripts_styles_new_registration()
727
-    {
728
-        wp_register_script(
729
-            'ee-spco-for-admin',
730
-            REG_ASSETS_URL . 'spco_for_admin.js',
731
-            array('underscore', 'jquery'),
732
-            EVENT_ESPRESSO_VERSION,
733
-            true
734
-        );
735
-        wp_enqueue_script('ee-spco-for-admin');
736
-        add_filter('FHEE__EED_Ticket_Selector__load_tckt_slctr_assets', '__return_true');
737
-        EE_Form_Section_Proper::wp_enqueue_scripts();
738
-        EED_Ticket_Selector::load_tckt_slctr_assets();
739
-        EE_Datepicker_Input::enqueue_styles_and_scripts();
740
-    }
741
-
742
-
743
-    public function AHEE__EE_Admin_Page__route_admin_request_resend_registration()
744
-    {
745
-        add_filter('FHEE_load_EE_messages', '__return_true');
746
-    }
747
-
748
-
749
-    public function AHEE__EE_Admin_Page__route_admin_request_approve_registration()
750
-    {
751
-        add_filter('FHEE_load_EE_messages', '__return_true');
752
-    }
753
-
754
-
755
-    protected function _set_list_table_views_default()
756
-    {
757
-        //for notification related bulk actions we need to make sure only active messengers have an option.
758
-        EED_Messages::set_autoloaders();
759
-        /** @type EE_Message_Resource_Manager $message_resource_manager */
760
-        $message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
761
-        $active_mts               = $message_resource_manager->list_of_active_message_types();
762
-        //key= bulk_action_slug, value= message type.
763
-        $match_array = array(
764
-            'approve_registrations'    => 'registration',
765
-            'decline_registrations'    => 'declined_registration',
766
-            'pending_registrations'    => 'pending_approval',
767
-            'no_approve_registrations' => 'not_approved_registration',
768
-            'cancel_registrations'     => 'cancelled_registration',
769
-        );
770
-        $can_send = EE_Registry::instance()->CAP->current_user_can(
771
-            'ee_send_message',
772
-            'batch_send_messages'
773
-        );
774
-        /** setup reg status bulk actions **/
775
-        $def_reg_status_actions['approve_registrations'] = esc_html__('Approve Registrations', 'event_espresso');
776
-        if ($can_send && in_array($match_array['approve_registrations'], $active_mts, true)) {
777
-                $def_reg_status_actions['approve_and_notify_registrations'] = esc_html__(
778
-                    'Approve and Notify Registrations',
779
-                    'event_espresso'
780
-                );
781
-        }
782
-        $def_reg_status_actions['decline_registrations'] = esc_html__('Decline Registrations', 'event_espresso');
783
-        if ($can_send && in_array($match_array['decline_registrations'], $active_mts, true)) {
784
-                $def_reg_status_actions['decline_and_notify_registrations'] = esc_html__(
785
-                    'Decline and Notify Registrations',
786
-                    'event_espresso'
787
-                );
788
-        }
789
-        $def_reg_status_actions['pending_registrations'] = esc_html__(
790
-            'Set Registrations to Pending Payment',
791
-            'event_espresso'
792
-        );
793
-        if ($can_send && in_array($match_array['pending_registrations'], $active_mts, true)) {
794
-                $def_reg_status_actions['pending_and_notify_registrations'] = esc_html__(
795
-                    'Set Registrations to Pending Payment and Notify',
796
-                    'event_espresso'
797
-                );
798
-        }
799
-        $def_reg_status_actions['no_approve_registrations'] = esc_html__(
800
-            'Set Registrations to Not Approved',
801
-            'event_espresso'
802
-        );
803
-        if ($can_send && in_array($match_array['no_approve_registrations'], $active_mts, true)) {
804
-                $def_reg_status_actions['no_approve_and_notify_registrations'] = esc_html__(
805
-                    'Set Registrations to Not Approved and Notify',
806
-                    'event_espresso'
807
-                );
808
-        }
809
-        $def_reg_status_actions['cancel_registrations'] = esc_html__('Cancel Registrations', 'event_espresso');
810
-        if ($can_send && in_array($match_array['cancel_registrations'], $active_mts, true)) {
811
-                $def_reg_status_actions['cancel_and_notify_registrations'] = esc_html__(
812
-                    'Cancel Registrations and Notify',
813
-                    'event_espresso'
814
-                );
815
-        }
816
-        $def_reg_status_actions = apply_filters(
817
-            'FHEE__Registrations_Admin_Page___set_list_table_views_default__def_reg_status_actions_array',
818
-            $def_reg_status_actions,
819
-            $active_mts,
820
-            $can_send
821
-        );
822
-
823
-        $this->_views = array(
824
-            'all'   => array(
825
-                'slug'        => 'all',
826
-                'label'       => esc_html__('View All Registrations', 'event_espresso'),
827
-                'count'       => 0,
828
-                'bulk_action' => array_merge($def_reg_status_actions, array(
829
-                    'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
830
-                )),
831
-            ),
832
-            'month' => array(
833
-                'slug'        => 'month',
834
-                'label'       => esc_html__('This Month', 'event_espresso'),
835
-                'count'       => 0,
836
-                'bulk_action' => array_merge($def_reg_status_actions, array(
837
-                    'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
838
-                )),
839
-            ),
840
-            'today' => array(
841
-                'slug'        => 'today',
842
-                'label'       => sprintf(
843
-                    esc_html__('Today - %s', 'event_espresso'),
844
-                    date('M d, Y', current_time('timestamp'))
845
-                ),
846
-                'count'       => 0,
847
-                'bulk_action' => array_merge($def_reg_status_actions, array(
848
-                    'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
849
-                )),
850
-            ),
851
-        );
852
-        if (EE_Registry::instance()->CAP->current_user_can(
853
-            'ee_delete_registrations',
854
-            'espresso_registrations_delete_registration'
855
-        )) {
856
-            $this->_views['incomplete'] = array(
857
-                'slug'        => 'incomplete',
858
-                'label'       => esc_html__('Incomplete', 'event_espresso'),
859
-                'count'       => 0,
860
-                'bulk_action' => array(
861
-                    'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
862
-                ),
863
-            );
864
-            $this->_views['trash']      = array(
865
-                'slug'        => 'trash',
866
-                'label'       => esc_html__('Trash', 'event_espresso'),
867
-                'count'       => 0,
868
-                'bulk_action' => array(
869
-                    'restore_registrations' => esc_html__('Restore Registrations', 'event_espresso'),
870
-                    'delete_registrations'  => esc_html__('Delete Registrations Permanently', 'event_espresso'),
871
-                ),
872
-            );
873
-        }
874
-    }
875
-
876
-
877
-    protected function _set_list_table_views_contact_list()
878
-    {
879
-        $this->_views = array(
880
-            'in_use' => array(
881
-                'slug'        => 'in_use',
882
-                'label'       => esc_html__('In Use', 'event_espresso'),
883
-                'count'       => 0,
884
-                'bulk_action' => array(
885
-                    'trash_attendees' => esc_html__('Move to Trash', 'event_espresso'),
886
-                ),
887
-            ),
888
-        );
889
-        if (EE_Registry::instance()->CAP->current_user_can('ee_delete_contacts',
890
-            'espresso_registrations_trash_attendees')
891
-        ) {
892
-            $this->_views['trash'] = array(
893
-                'slug'        => 'trash',
894
-                'label'       => esc_html__('Trash', 'event_espresso'),
895
-                'count'       => 0,
896
-                'bulk_action' => array(
897
-                    'restore_attendees' => esc_html__('Restore from Trash', 'event_espresso'),
898
-                ),
899
-            );
900
-        }
901
-    }
902
-
903
-
904
-    protected function _registration_legend_items()
905
-    {
906
-        $fc_items = array(
907
-            'star-icon'        => array(
908
-                'class' => 'dashicons dashicons-star-filled lt-blue-icon ee-icon-size-8',
909
-                'desc'  => esc_html__('This is the Primary Registrant', 'event_espresso'),
910
-            ),
911
-            'view_details'     => array(
912
-                'class' => 'dashicons dashicons-clipboard',
913
-                'desc'  => esc_html__('View Registration Details', 'event_espresso'),
914
-            ),
915
-            'edit_attendee'    => array(
916
-                'class' => 'ee-icon ee-icon-user-edit ee-icon-size-16',
917
-                'desc'  => esc_html__('Edit Contact Details', 'event_espresso'),
918
-            ),
919
-            'view_transaction' => array(
920
-                'class' => 'dashicons dashicons-cart',
921
-                'desc'  => esc_html__('View Transaction Details', 'event_espresso'),
922
-            ),
923
-            'view_invoice'     => array(
924
-                'class' => 'dashicons dashicons-media-spreadsheet',
925
-                'desc'  => esc_html__('View Transaction Invoice', 'event_espresso'),
926
-            ),
927
-        );
928
-        if (EE_Registry::instance()->CAP->current_user_can(
929
-            'ee_send_message',
930
-            'espresso_registrations_resend_registration'
931
-        )) {
932
-            $fc_items['resend_registration'] = array(
933
-                'class' => 'dashicons dashicons-email-alt',
934
-                'desc'  => esc_html__('Resend Registration Details', 'event_espresso'),
935
-            );
936
-        } else {
937
-            $fc_items['blank'] = array('class' => 'blank', 'desc' => '');
938
-        }
939
-        if (EE_Registry::instance()->CAP->current_user_can(
940
-            'ee_read_global_messages',
941
-            'view_filtered_messages'
942
-        )) {
943
-            $related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
944
-            if (isset($related_for_icon['css_class']) && isset($related_for_icon['label'])) {
945
-                $fc_items['view_related_messages'] = array(
946
-                    'class' => $related_for_icon['css_class'],
947
-                    'desc'  => $related_for_icon['label'],
948
-                );
949
-            }
950
-        }
951
-        $sc_items = array(
952
-            'approved_status'   => array(
953
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_approved,
954
-                'desc'  => EEH_Template::pretty_status(
955
-                    EEM_Registration::status_id_approved,
956
-                    false,
957
-                    'sentence'
958
-                ),
959
-            ),
960
-            'pending_status'    => array(
961
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_pending_payment,
962
-                'desc'  => EEH_Template::pretty_status(
963
-                    EEM_Registration::status_id_pending_payment,
964
-                    false,
965
-                    'sentence'
966
-                ),
967
-            ),
968
-            'wait_list'         => array(
969
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_wait_list,
970
-                'desc'  => EEH_Template::pretty_status(
971
-                    EEM_Registration::status_id_wait_list,
972
-                    false,
973
-                    'sentence'
974
-                ),
975
-            ),
976
-            'incomplete_status' => array(
977
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_incomplete,
978
-                'desc'  => EEH_Template::pretty_status(
979
-                    EEM_Registration::status_id_incomplete,
980
-                    false,
981
-                    'sentence'
982
-                ),
983
-            ),
984
-            'not_approved'      => array(
985
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_not_approved,
986
-                'desc'  => EEH_Template::pretty_status(
987
-                    EEM_Registration::status_id_not_approved,
988
-                    false,
989
-                    'sentence'
990
-                ),
991
-            ),
992
-            'declined_status'   => array(
993
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_declined,
994
-                'desc'  => EEH_Template::pretty_status(
995
-                    EEM_Registration::status_id_declined,
996
-                    false,
997
-                    'sentence'
998
-                ),
999
-            ),
1000
-            'cancelled_status'  => array(
1001
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_cancelled,
1002
-                'desc'  => EEH_Template::pretty_status(
1003
-                    EEM_Registration::status_id_cancelled,
1004
-                    false,
1005
-                    'sentence'
1006
-                ),
1007
-            ),
1008
-        );
1009
-        return array_merge($fc_items, $sc_items);
1010
-    }
1011
-
1012
-
1013
-
1014
-    /***************************************        REGISTRATION OVERVIEW        **************************************/
1015
-    /**
1016
-     * @throws \EE_Error
1017
-     */
1018
-    protected function _registrations_overview_list_table()
1019
-    {
1020
-        $this->_template_args['admin_page_header'] = '';
1021
-        $EVT_ID                                    = ! empty($this->_req_data['event_id'])
1022
-            ? absint($this->_req_data['event_id'])
1023
-            : 0;
1024
-        $ATT_ID = !empty($this->_req_data['ATT_ID'])
1025
-            ? absint($this->_req_data['ATT_ID'])
1026
-            : 0;
1027
-        if ($ATT_ID) {
1028
-            $attendee = EEM_Attendee::instance()->get_one_by_ID($ATT_ID);
1029
-            if ($attendee instanceof EE_Attendee) {
1030
-                $this->_template_args['admin_page_header'] = sprintf(
1031
-                    esc_html__(
1032
-                        '%1$s Viewing registrations for %2$s%3$s',
1033
-                        'event_espresso'
1034
-                    ),
1035
-                    '<h3 style="line-height:1.5em;">',
1036
-                    '<a href="' . EE_Admin_Page::add_query_args_and_nonce(
1037
-                        array(
1038
-                            'action' => 'edit_attendee',
1039
-                            'post' => $ATT_ID
1040
-                        ),
1041
-                        REG_ADMIN_URL
1042
-                    ) . '">' . $attendee->full_name() . '</a>',
1043
-                    '</h3>'
1044
-                );
1045
-            }
1046
-        }
1047
-        if ($EVT_ID) {
1048
-            if (EE_Registry::instance()->CAP->current_user_can(
1049
-                'ee_edit_registrations',
1050
-                'espresso_registrations_new_registration',
1051
-                $EVT_ID
1052
-            )) {
1053
-                $this->_admin_page_title .= ' ' . $this->get_action_link_or_button(
1054
-                    'new_registration',
1055
-                    'add-registrant',
1056
-                    array('event_id' => $EVT_ID),
1057
-                    'add-new-h2'
1058
-                );
1059
-            }
1060
-            $event = EEM_Event::instance()->get_one_by_ID($EVT_ID);
1061
-            if ($event instanceof EE_Event) {
1062
-                $this->_template_args['admin_page_header'] = sprintf(
1063
-                    esc_html__(
1064
-                        '%s Viewing registrations for the event: %s%s',
1065
-                        'event_espresso'
1066
-                    ),
1067
-                    '<h3 style="line-height:1.5em;">',
1068
-                    '<br /><a href="'
1069
-                        . EE_Admin_Page::add_query_args_and_nonce(
1070
-                            array(
1071
-                                'action' => 'edit',
1072
-                                'post'   => $event->ID(),
1073
-                            ),
1074
-                            EVENTS_ADMIN_URL
1075
-                        )
1076
-                        . '">&nbsp;'
1077
-                        . $event->get('EVT_name')
1078
-                        . '&nbsp;</a>&nbsp;',
1079
-                    '</h3>'
1080
-                );
1081
-            }
1082
-            $DTT_ID   = ! empty($this->_req_data['datetime_id']) ? absint($this->_req_data['datetime_id']) : 0;
1083
-            $datetime = EEM_Datetime::instance()->get_one_by_ID($DTT_ID);
1084
-            if ($datetime instanceof EE_Datetime && $this->_template_args['admin_page_header'] !== '') {
1085
-                $this->_template_args['admin_page_header'] = substr(
1086
-                    $this->_template_args['admin_page_header'],
1087
-                    0,
1088
-                    -5
1089
-                );
1090
-                $this->_template_args['admin_page_header'] .= ' &nbsp;<span class="drk-grey-text">';
1091
-                $this->_template_args['admin_page_header'] .= '<span class="dashicons dashicons-calendar"></span>';
1092
-                $this->_template_args['admin_page_header'] .= $datetime->name();
1093
-                $this->_template_args['admin_page_header'] .= ' ( ' . $datetime->start_date() . ' )';
1094
-                $this->_template_args['admin_page_header'] .= '</span></h3>';
1095
-            }
1096
-        }
1097
-        $this->_template_args['after_list_table'] = $this->_display_legend($this->_registration_legend_items());
1098
-        $this->display_admin_list_table_page_with_no_sidebar();
1099
-    }
1100
-
1101
-
1102
-    /**
1103
-     * This sets the _registration property for the registration details screen
1104
-     *
1105
-     * @access private
1106
-     * @return bool
1107
-     * @throws EE_Error
1108
-     * @throws InvalidArgumentException
1109
-     * @throws InvalidDataTypeException
1110
-     * @throws InvalidInterfaceException
1111
-     */
1112
-    private function _set_registration_object()
1113
-    {
1114
-        //get out if we've already set the object
1115
-        if ($this->_registration instanceof EE_Registration) {
1116
-            return true;
1117
-        }
1118
-        $REG    = EEM_Registration::instance();
1119
-        $REG_ID = ( ! empty($this->_req_data['_REG_ID'])) ? absint($this->_req_data['_REG_ID']) : false;
1120
-        if ($this->_registration = $REG->get_one_by_ID($REG_ID)) {
1121
-            return true;
1122
-        } else {
1123
-            $error_msg = sprintf(
1124
-                esc_html__(
1125
-                    'An error occurred and the details for Registration ID #%s could not be retrieved.',
1126
-                    'event_espresso'
1127
-                ),
1128
-                $REG_ID
1129
-            );
1130
-            EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
1131
-            $this->_registration = null;
1132
-            return false;
1133
-        }
1134
-    }
1135
-
1136
-
1137
-    /**
1138
-     * Used to retrieve registrations for the list table.
1139
-     *
1140
-     * @param int  $per_page
1141
-     * @param bool $count
1142
-     * @param bool $this_month
1143
-     * @param bool $today
1144
-     * @return EE_Registration[]|int
1145
-     * @throws EE_Error
1146
-     * @throws InvalidArgumentException
1147
-     * @throws InvalidDataTypeException
1148
-     * @throws InvalidInterfaceException
1149
-     */
1150
-    public function get_registrations(
1151
-        $per_page = 10,
1152
-        $count = false,
1153
-        $this_month = false,
1154
-        $today = false
1155
-    ) {
1156
-        if ($this_month) {
1157
-            $this->_req_data['status'] = 'month';
1158
-        }
1159
-        if ($today) {
1160
-            $this->_req_data['status'] = 'today';
1161
-        }
1162
-        $query_params = $this->_get_registration_query_parameters($this->_req_data, $per_page, $count);
1163
-        /**
1164
-         * Override the default groupby added by EEM_Base so that sorts with multiple order bys work as expected
1165
-         * @link https://events.codebasehq.com/projects/event-espresso/tickets/10093
1166
-         * @see EEM_Base::get_all()
1167
-         */
1168
-        $query_params['group_by'] = '';
1169
-
1170
-        return $count
1171
-            ? EEM_Registration::instance()->count($query_params)
1172
-            /** @type EE_Registration[] */
1173
-            : EEM_Registration::instance()->get_all($query_params);
1174
-    }
1175
-
1176
-
1177
-    /**
1178
-     * Retrieves the query parameters to be used by the Registration model for getting registrations.
1179
-     * Note: this listens to values on the request for some of the query parameters.
1180
-     *
1181
-     * @param array $request
1182
-     * @param int   $per_page
1183
-     * @param bool  $count
1184
-     * @return array
1185
-     * @throws EE_Error
1186
-     */
1187
-    protected function _get_registration_query_parameters(
1188
-        $request = array(),
1189
-        $per_page = 10,
1190
-        $count = false
1191
-    ) {
1192
-
1193
-        $query_params = array(
1194
-            0                          => $this->_get_where_conditions_for_registrations_query(
1195
-                $request
1196
-            ),
1197
-            'caps'                     => EEM_Registration::caps_read_admin,
1198
-            'default_where_conditions' => 'this_model_only',
1199
-        );
1200
-        if (! $count) {
1201
-            $query_params = array_merge(
1202
-                $query_params,
1203
-                $this->_get_orderby_for_registrations_query(),
1204
-                $this->_get_limit($per_page)
1205
-            );
1206
-        }
1207
-
1208
-        return $query_params;
1209
-    }
1210
-
1211
-
1212
-    /**
1213
-     * This will add ATT_ID to the provided $where array for EE model query parameters.
1214
-     *
1215
-     * @param array $request usually the same as $this->_req_data but not necessarily
1216
-     * @return array
1217
-     */
1218
-    protected function addAttendeeIdToWhereConditions(array $request)
1219
-    {
1220
-        $where = array();
1221
-        if (! empty($request['ATT_ID'])) {
1222
-            $where['ATT_ID'] = absint($request['ATT_ID']);
1223
-        }
1224
-        return $where;
1225
-    }
1226
-
1227
-
1228
-    /**
1229
-     * This will add EVT_ID to the provided $where array for EE model query parameters.
1230
-     *
1231
-     * @param array $request usually the same as $this->_req_data but not necessarily
1232
-     * @return array
1233
-     */
1234
-    protected function _add_event_id_to_where_conditions(array $request)
1235
-    {
1236
-        $where = array();
1237
-        if (! empty($request['event_id'])) {
1238
-            $where['EVT_ID'] = absint($request['event_id']);
1239
-        }
1240
-        return $where;
1241
-    }
1242
-
1243
-
1244
-    /**
1245
-     * Adds category ID if it exists in the request to the where conditions for the registrations query.
1246
-     *
1247
-     * @param array $request usually the same as $this->_req_data but not necessarily
1248
-     * @return array
1249
-     */
1250
-    protected function _add_category_id_to_where_conditions(array $request)
1251
-    {
1252
-        $where = array();
1253
-        if (! empty($request['EVT_CAT']) && (int)$request['EVT_CAT'] !== -1) {
1254
-            $where['Event.Term_Taxonomy.term_id'] = absint($request['EVT_CAT']);
1255
-        }
1256
-        return $where;
1257
-    }
1258
-
1259
-
1260
-    /**
1261
-     * Adds the datetime ID if it exists in the request to the where conditions for the registrations query.
1262
-     *
1263
-     * @param array $request usually the same as $this->_req_data but not necessarily
1264
-     * @return array
1265
-     */
1266
-    protected function _add_datetime_id_to_where_conditions(array $request)
1267
-    {
1268
-        $where = array();
1269
-        if (! empty($request['datetime_id'])) {
1270
-            $where['Ticket.Datetime.DTT_ID'] = absint($request['datetime_id']);
1271
-        }
1272
-        if (! empty($request['DTT_ID'])) {
1273
-            $where['Ticket.Datetime.DTT_ID'] = absint($request['DTT_ID']);
1274
-        }
1275
-        return $where;
1276
-    }
1277
-
1278
-
1279
-    /**
1280
-     * Adds the correct registration status to the where conditions for the registrations query.
1281
-     *
1282
-     * @param array $request usually the same as $this->_req_data but not necessarily
1283
-     * @return array
1284
-     */
1285
-    protected function _add_registration_status_to_where_conditions(array $request)
1286
-    {
1287
-        $where = array();
1288
-        $view = EEH_Array::is_set($request, 'status', '');
1289
-        $registration_status = ! empty($request['_reg_status'])
1290
-            ? sanitize_text_field($request['_reg_status'])
1291
-            : '';
1292
-
1293
-        /*
33
+	/**
34
+	 * @var EE_Registration
35
+	 */
36
+	private $_registration;
37
+
38
+	/**
39
+	 * @var EE_Event
40
+	 */
41
+	private $_reg_event;
42
+
43
+	/**
44
+	 * @var EE_Session
45
+	 */
46
+	private $_session;
47
+
48
+	private static $_reg_status;
49
+
50
+	/**
51
+	 * Form for displaying the custom questions for this registration.
52
+	 * This gets used a few times throughout the request so its best to cache it
53
+	 *
54
+	 * @var EE_Registration_Custom_Questions_Form
55
+	 */
56
+	protected $_reg_custom_questions_form = null;
57
+
58
+
59
+	/**
60
+	 *        constructor
61
+	 *
62
+	 * @Constructor
63
+	 * @access public
64
+	 * @param bool $routing
65
+	 * @return Registrations_Admin_Page
66
+	 */
67
+	public function __construct($routing = true)
68
+	{
69
+		parent::__construct($routing);
70
+		add_action('wp_loaded', array($this, 'wp_loaded'));
71
+	}
72
+
73
+
74
+	public function wp_loaded()
75
+	{
76
+		// when adding a new registration...
77
+		if (isset($this->_req_data['action']) && $this->_req_data['action'] === 'new_registration') {
78
+			EE_System::do_not_cache();
79
+			if (! isset($this->_req_data['processing_registration'])
80
+				 || absint($this->_req_data['processing_registration']) !== 1
81
+			) {
82
+				// and it's NOT the attendee information reg step
83
+				// force cookie expiration by setting time to last week
84
+				setcookie('ee_registration_added', 0, time() - WEEK_IN_SECONDS, '/');
85
+				// and update the global
86
+				$_COOKIE['ee_registration_added'] = 0;
87
+			}
88
+		}
89
+	}
90
+
91
+
92
+	protected function _init_page_props()
93
+	{
94
+		$this->page_slug        = REG_PG_SLUG;
95
+		$this->_admin_base_url  = REG_ADMIN_URL;
96
+		$this->_admin_base_path = REG_ADMIN;
97
+		$this->page_label       = esc_html__('Registrations', 'event_espresso');
98
+		$this->_cpt_routes      = array(
99
+			'add_new_attendee' => 'espresso_attendees',
100
+			'edit_attendee'    => 'espresso_attendees',
101
+			'insert_attendee'  => 'espresso_attendees',
102
+			'update_attendee'  => 'espresso_attendees',
103
+		);
104
+		$this->_cpt_model_names = array(
105
+			'add_new_attendee' => 'EEM_Attendee',
106
+			'edit_attendee'    => 'EEM_Attendee',
107
+		);
108
+		$this->_cpt_edit_routes = array(
109
+			'espresso_attendees' => 'edit_attendee',
110
+		);
111
+		$this->_pagenow_map     = array(
112
+			'add_new_attendee' => 'post-new.php',
113
+			'edit_attendee'    => 'post.php',
114
+			'trash'            => 'post.php',
115
+		);
116
+		add_action('edit_form_after_title', array($this, 'after_title_form_fields'), 10);
117
+		//add filters so that the comment urls don't take users to a confusing 404 page
118
+		add_filter('get_comment_link', array($this, 'clear_comment_link'), 10, 3);
119
+	}
120
+
121
+
122
+	public function clear_comment_link($link, $comment, $args)
123
+	{
124
+		//gotta make sure this only happens on this route
125
+		$post_type = get_post_type($comment->comment_post_ID);
126
+		if ($post_type === 'espresso_attendees') {
127
+			return '#commentsdiv';
128
+		}
129
+		return $link;
130
+	}
131
+
132
+
133
+	protected function _ajax_hooks()
134
+	{
135
+		//todo: all hooks for registrations ajax goes in here
136
+		add_action('wp_ajax_toggle_checkin_status', array($this, 'toggle_checkin_status'));
137
+	}
138
+
139
+
140
+	protected function _define_page_props()
141
+	{
142
+		$this->_admin_page_title = $this->page_label;
143
+		$this->_labels           = array(
144
+			'buttons'                      => array(
145
+				'add-registrant'      => esc_html__('Add New Registration', 'event_espresso'),
146
+				'add-attendee'        => esc_html__('Add Contact', 'event_espresso'),
147
+				'edit'                => esc_html__('Edit Contact', 'event_espresso'),
148
+				'report'              => esc_html__("Event Registrations CSV Report", "event_espresso"),
149
+				'report_all'          => esc_html__('All Registrations CSV Report', 'event_espresso'),
150
+				'report_filtered'     => esc_html__('Filtered CSV Report', 'event_espresso'),
151
+				'contact_list_report' => esc_html__('Contact List Report', 'event_espresso'),
152
+				'contact_list_export' => esc_html__("Export Data", "event_espresso"),
153
+			),
154
+			'publishbox'                   => array(
155
+				'add_new_attendee' => esc_html__("Add Contact Record", 'event_espresso'),
156
+				'edit_attendee'    => esc_html__("Update Contact Record", 'event_espresso'),
157
+			),
158
+			'hide_add_button_on_cpt_route' => array(
159
+				'edit_attendee' => true,
160
+			),
161
+		);
162
+	}
163
+
164
+
165
+	/**
166
+	 *        grab url requests and route them
167
+	 *
168
+	 * @access private
169
+	 * @return void
170
+	 */
171
+	public function _set_page_routes()
172
+	{
173
+		$this->_get_registration_status_array();
174
+		$reg_id             = ! empty($this->_req_data['_REG_ID']) && ! is_array($this->_req_data['_REG_ID'])
175
+			? $this->_req_data['_REG_ID'] : 0;
176
+		$reg_id = empty($reg_id) && ! empty($this->_req_data['reg_status_change_form']['REG_ID'])
177
+			? $this->_req_data['reg_status_change_form']['REG_ID']
178
+			: $reg_id;
179
+		$att_id             = ! empty($this->_req_data['ATT_ID']) && ! is_array($this->_req_data['ATT_ID'])
180
+			? $this->_req_data['ATT_ID'] : 0;
181
+		$att_id             = ! empty($this->_req_data['post']) && ! is_array($this->_req_data['post'])
182
+			? $this->_req_data['post']
183
+			: $att_id;
184
+		$this->_page_routes = array(
185
+			'default'                            => array(
186
+				'func'       => '_registrations_overview_list_table',
187
+				'capability' => 'ee_read_registrations',
188
+			),
189
+			'view_registration'                  => array(
190
+				'func'       => '_registration_details',
191
+				'capability' => 'ee_read_registration',
192
+				'obj_id'     => $reg_id,
193
+			),
194
+			'edit_registration'                  => array(
195
+				'func'               => '_update_attendee_registration_form',
196
+				'noheader'           => true,
197
+				'headers_sent_route' => 'view_registration',
198
+				'capability'         => 'ee_edit_registration',
199
+				'obj_id'             => $reg_id,
200
+				'_REG_ID'            => $reg_id,
201
+			),
202
+			'trash_registrations'                => array(
203
+				'func'       => '_trash_or_restore_registrations',
204
+				'args'       => array('trash' => true),
205
+				'noheader'   => true,
206
+				'capability' => 'ee_delete_registrations',
207
+			),
208
+			'restore_registrations'              => array(
209
+				'func'       => '_trash_or_restore_registrations',
210
+				'args'       => array('trash' => false),
211
+				'noheader'   => true,
212
+				'capability' => 'ee_delete_registrations',
213
+			),
214
+			'delete_registrations'               => array(
215
+				'func'       => '_delete_registrations',
216
+				'noheader'   => true,
217
+				'capability' => 'ee_delete_registrations',
218
+			),
219
+			'new_registration'                   => array(
220
+				'func'       => 'new_registration',
221
+				'capability' => 'ee_edit_registrations',
222
+			),
223
+			'process_reg_step'                   => array(
224
+				'func'       => 'process_reg_step',
225
+				'noheader'   => true,
226
+				'capability' => 'ee_edit_registrations',
227
+			),
228
+			'redirect_to_txn'                    => array(
229
+				'func'       => 'redirect_to_txn',
230
+				'noheader'   => true,
231
+				'capability' => 'ee_edit_registrations',
232
+			),
233
+			'change_reg_status'                  => array(
234
+				'func'       => '_change_reg_status',
235
+				'noheader'   => true,
236
+				'capability' => 'ee_edit_registration',
237
+				'obj_id'     => $reg_id,
238
+			),
239
+			'approve_registration'               => array(
240
+				'func'       => 'approve_registration',
241
+				'noheader'   => true,
242
+				'capability' => 'ee_edit_registration',
243
+				'obj_id'     => $reg_id,
244
+			),
245
+			'approve_and_notify_registration'    => array(
246
+				'func'       => 'approve_registration',
247
+				'noheader'   => true,
248
+				'args'       => array(true),
249
+				'capability' => 'ee_edit_registration',
250
+				'obj_id'     => $reg_id,
251
+			),
252
+			'approve_registrations'               => array(
253
+				'func'       => 'bulk_action_on_registrations',
254
+				'noheader'   => true,
255
+				'capability' => 'ee_edit_registrations',
256
+				'args' => array('approve')
257
+			),
258
+			'approve_and_notify_registrations'               => array(
259
+				'func'       => 'bulk_action_on_registrations',
260
+				'noheader'   => true,
261
+				'capability' => 'ee_edit_registrations',
262
+				'args' => array('approve', true)
263
+			),
264
+			'decline_registration'               => array(
265
+				'func'       => 'decline_registration',
266
+				'noheader'   => true,
267
+				'capability' => 'ee_edit_registration',
268
+				'obj_id'     => $reg_id,
269
+			),
270
+			'decline_and_notify_registration'    => array(
271
+				'func'       => 'decline_registration',
272
+				'noheader'   => true,
273
+				'args'       => array(true),
274
+				'capability' => 'ee_edit_registration',
275
+				'obj_id'     => $reg_id,
276
+			),
277
+			'decline_registrations'               => array(
278
+				'func'       => 'bulk_action_on_registrations',
279
+				'noheader'   => true,
280
+				'capability' => 'ee_edit_registrations',
281
+				'args' => array('decline')
282
+			),
283
+			'decline_and_notify_registrations'    => array(
284
+				'func'       => 'bulk_action_on_registrations',
285
+				'noheader'   => true,
286
+				'capability' => 'ee_edit_registrations',
287
+				'args' => array('decline', true)
288
+			),
289
+			'pending_registration'               => array(
290
+				'func'       => 'pending_registration',
291
+				'noheader'   => true,
292
+				'capability' => 'ee_edit_registration',
293
+				'obj_id'     => $reg_id,
294
+			),
295
+			'pending_and_notify_registration'    => array(
296
+				'func'       => 'pending_registration',
297
+				'noheader'   => true,
298
+				'args'       => array(true),
299
+				'capability' => 'ee_edit_registration',
300
+				'obj_id'     => $reg_id,
301
+			),
302
+			'pending_registrations'               => array(
303
+				'func'       => 'bulk_action_on_registrations',
304
+				'noheader'   => true,
305
+				'capability' => 'ee_edit_registrations',
306
+				'args' => array('pending')
307
+			),
308
+			'pending_and_notify_registrations'    => array(
309
+				'func'       => 'bulk_action_on_registrations',
310
+				'noheader'   => true,
311
+				'capability' => 'ee_edit_registrations',
312
+				'args' => array('pending', true)
313
+			),
314
+			'no_approve_registration'            => array(
315
+				'func'       => 'not_approve_registration',
316
+				'noheader'   => true,
317
+				'capability' => 'ee_edit_registration',
318
+				'obj_id'     => $reg_id,
319
+			),
320
+			'no_approve_and_notify_registration' => array(
321
+				'func'       => 'not_approve_registration',
322
+				'noheader'   => true,
323
+				'args'       => array(true),
324
+				'capability' => 'ee_edit_registration',
325
+				'obj_id'     => $reg_id,
326
+			),
327
+			'no_approve_registrations'            => array(
328
+				'func'       => 'bulk_action_on_registrations',
329
+				'noheader'   => true,
330
+				'capability' => 'ee_edit_registrations',
331
+				'args' => array('not_approve')
332
+			),
333
+			'no_approve_and_notify_registrations' => array(
334
+				'func'       => 'bulk_action_on_registrations',
335
+				'noheader'   => true,
336
+				'capability' => 'ee_edit_registrations',
337
+				'args' => array('not_approve', true)
338
+			),
339
+			'cancel_registration'                => array(
340
+				'func'       => 'cancel_registration',
341
+				'noheader'   => true,
342
+				'capability' => 'ee_edit_registration',
343
+				'obj_id'     => $reg_id,
344
+			),
345
+			'cancel_and_notify_registration'     => array(
346
+				'func'       => 'cancel_registration',
347
+				'noheader'   => true,
348
+				'args'       => array(true),
349
+				'capability' => 'ee_edit_registration',
350
+				'obj_id'     => $reg_id,
351
+			),
352
+			'cancel_registrations'                => array(
353
+				'func'       => 'bulk_action_on_registrations',
354
+				'noheader'   => true,
355
+				'capability' => 'ee_edit_registrations',
356
+				'args' => array('cancel')
357
+			),
358
+			'cancel_and_notify_registrations'     => array(
359
+				'func'       => 'bulk_action_on_registrations',
360
+				'noheader'   => true,
361
+				'capability' => 'ee_edit_registrations',
362
+				'args' => array('cancel', true)
363
+			),
364
+			'wait_list_registration' => array(
365
+				'func'       => 'wait_list_registration',
366
+				'noheader'   => true,
367
+				'capability' => 'ee_edit_registration',
368
+				'obj_id'     => $reg_id,
369
+			),
370
+			'wait_list_and_notify_registration' => array(
371
+				'func'       => 'wait_list_registration',
372
+				'noheader'   => true,
373
+				'args'       => array(true),
374
+				'capability' => 'ee_edit_registration',
375
+				'obj_id'     => $reg_id,
376
+			),
377
+			'contact_list'                       => array(
378
+				'func'       => '_attendee_contact_list_table',
379
+				'capability' => 'ee_read_contacts',
380
+			),
381
+			'add_new_attendee'                   => array(
382
+				'func' => '_create_new_cpt_item',
383
+				'args' => array(
384
+					'new_attendee' => true,
385
+					'capability'   => 'ee_edit_contacts',
386
+				),
387
+			),
388
+			'edit_attendee'                      => array(
389
+				'func'       => '_edit_cpt_item',
390
+				'capability' => 'ee_edit_contacts',
391
+				'obj_id'     => $att_id,
392
+			),
393
+			'duplicate_attendee'                 => array(
394
+				'func'       => '_duplicate_attendee',
395
+				'noheader'   => true,
396
+				'capability' => 'ee_edit_contacts',
397
+				'obj_id'     => $att_id,
398
+			),
399
+			'insert_attendee'                    => array(
400
+				'func'       => '_insert_or_update_attendee',
401
+				'args'       => array(
402
+					'new_attendee' => true,
403
+				),
404
+				'noheader'   => true,
405
+				'capability' => 'ee_edit_contacts',
406
+			),
407
+			'update_attendee'                    => array(
408
+				'func'       => '_insert_or_update_attendee',
409
+				'args'       => array(
410
+					'new_attendee' => false,
411
+				),
412
+				'noheader'   => true,
413
+				'capability' => 'ee_edit_contacts',
414
+				'obj_id'     => $att_id,
415
+			),
416
+			'trash_attendees' => array(
417
+				'func' => '_trash_or_restore_attendees',
418
+				'args' => array(
419
+					'trash' => 'true'
420
+				),
421
+				'noheader' => true,
422
+				'capability' => 'ee_delete_contacts'
423
+			),
424
+			'trash_attendee'                    => array(
425
+				'func'       => '_trash_or_restore_attendees',
426
+				'args'       => array(
427
+					'trash' => true,
428
+				),
429
+				'noheader'   => true,
430
+				'capability' => 'ee_delete_contacts',
431
+				'obj_id'     => $att_id,
432
+			),
433
+			'restore_attendees'                  => array(
434
+				'func'       => '_trash_or_restore_attendees',
435
+				'args'       => array(
436
+					'trash' => false,
437
+				),
438
+				'noheader'   => true,
439
+				'capability' => 'ee_delete_contacts',
440
+				'obj_id'     => $att_id,
441
+			),
442
+			'resend_registration'                => array(
443
+				'func'       => '_resend_registration',
444
+				'noheader'   => true,
445
+				'capability' => 'ee_send_message',
446
+			),
447
+			'registrations_report'               => array(
448
+				'func'       => '_registrations_report',
449
+				'noheader'   => true,
450
+				'capability' => 'ee_read_registrations',
451
+			),
452
+			'contact_list_export'                => array(
453
+				'func'       => '_contact_list_export',
454
+				'noheader'   => true,
455
+				'capability' => 'export',
456
+			),
457
+			'contact_list_report'                => array(
458
+				'func'       => '_contact_list_report',
459
+				'noheader'   => true,
460
+				'capability' => 'ee_read_contacts',
461
+			),
462
+		);
463
+	}
464
+
465
+
466
+	protected function _set_page_config()
467
+	{
468
+		$this->_page_config = array(
469
+			'default'           => array(
470
+				'nav'           => array(
471
+					'label' => esc_html__('Overview', 'event_espresso'),
472
+					'order' => 5,
473
+				),
474
+				'help_tabs'     => array(
475
+					'registrations_overview_help_tab'                       => array(
476
+						'title'    => esc_html__('Registrations Overview', 'event_espresso'),
477
+						'filename' => 'registrations_overview',
478
+					),
479
+					'registrations_overview_table_column_headings_help_tab' => array(
480
+						'title'    => esc_html__('Registrations Table Column Headings', 'event_espresso'),
481
+						'filename' => 'registrations_overview_table_column_headings',
482
+					),
483
+					'registrations_overview_filters_help_tab'               => array(
484
+						'title'    => esc_html__('Registration Filters', 'event_espresso'),
485
+						'filename' => 'registrations_overview_filters',
486
+					),
487
+					'registrations_overview_views_help_tab'                 => array(
488
+						'title'    => esc_html__('Registration Views', 'event_espresso'),
489
+						'filename' => 'registrations_overview_views',
490
+					),
491
+					'registrations_regoverview_other_help_tab'              => array(
492
+						'title'    => esc_html__('Registrations Other', 'event_espresso'),
493
+						'filename' => 'registrations_overview_other',
494
+					),
495
+				),
496
+				'help_tour'     => array('Registration_Overview_Help_Tour'),
497
+				'qtips'         => array('Registration_List_Table_Tips'),
498
+				'list_table'    => 'EE_Registrations_List_Table',
499
+				'require_nonce' => false,
500
+			),
501
+			'view_registration' => array(
502
+				'nav'           => array(
503
+					'label'      => esc_html__('REG Details', 'event_espresso'),
504
+					'order'      => 15,
505
+					'url'        => isset($this->_req_data['_REG_ID'])
506
+						? add_query_arg(array('_REG_ID' => $this->_req_data['_REG_ID']), $this->_current_page_view_url)
507
+						: $this->_admin_base_url,
508
+					'persistent' => false,
509
+				),
510
+				'help_tabs'     => array(
511
+					'registrations_details_help_tab'                    => array(
512
+						'title'    => esc_html__('Registration Details', 'event_espresso'),
513
+						'filename' => 'registrations_details',
514
+					),
515
+					'registrations_details_table_help_tab'              => array(
516
+						'title'    => esc_html__('Registration Details Table', 'event_espresso'),
517
+						'filename' => 'registrations_details_table',
518
+					),
519
+					'registrations_details_form_answers_help_tab'       => array(
520
+						'title'    => esc_html__('Registration Form Answers', 'event_espresso'),
521
+						'filename' => 'registrations_details_form_answers',
522
+					),
523
+					'registrations_details_registrant_details_help_tab' => array(
524
+						'title'    => esc_html__('Contact Details', 'event_espresso'),
525
+						'filename' => 'registrations_details_registrant_details',
526
+					),
527
+				),
528
+				'help_tour'     => array('Registration_Details_Help_Tour'),
529
+				'metaboxes'     => array_merge(
530
+					$this->_default_espresso_metaboxes,
531
+					array('_registration_details_metaboxes')
532
+				),
533
+				'require_nonce' => false,
534
+			),
535
+			'new_registration'  => array(
536
+				'nav'           => array(
537
+					'label'      => esc_html__('Add New Registration', 'event_espresso'),
538
+					'url'        => '#',
539
+					'order'      => 15,
540
+					'persistent' => false,
541
+				),
542
+				'metaboxes'     => $this->_default_espresso_metaboxes,
543
+				'labels'        => array(
544
+					'publishbox' => esc_html__('Save Registration', 'event_espresso'),
545
+				),
546
+				'require_nonce' => false,
547
+			),
548
+			'add_new_attendee'  => array(
549
+				'nav'           => array(
550
+					'label'      => esc_html__('Add Contact', 'event_espresso'),
551
+					'order'      => 15,
552
+					'persistent' => false,
553
+				),
554
+				'metaboxes'     => array_merge(
555
+					$this->_default_espresso_metaboxes,
556
+					array('_publish_post_box', 'attendee_editor_metaboxes')
557
+				),
558
+				'require_nonce' => false,
559
+			),
560
+			'edit_attendee'     => array(
561
+				'nav'           => array(
562
+					'label'      => esc_html__('Edit Contact', 'event_espresso'),
563
+					'order'      => 15,
564
+					'persistent' => false,
565
+					'url'        => isset($this->_req_data['ATT_ID'])
566
+						? add_query_arg(array('ATT_ID' => $this->_req_data['ATT_ID']), $this->_current_page_view_url)
567
+						: $this->_admin_base_url,
568
+				),
569
+				'metaboxes'     => array('attendee_editor_metaboxes'),
570
+				'require_nonce' => false,
571
+			),
572
+			'contact_list'      => array(
573
+				'nav'           => array(
574
+					'label' => esc_html__('Contact List', 'event_espresso'),
575
+					'order' => 20,
576
+				),
577
+				'list_table'    => 'EE_Attendee_Contact_List_Table',
578
+				'help_tabs'     => array(
579
+					'registrations_contact_list_help_tab'                       => array(
580
+						'title'    => esc_html__('Registrations Contact List', 'event_espresso'),
581
+						'filename' => 'registrations_contact_list',
582
+					),
583
+					'registrations_contact-list_table_column_headings_help_tab' => array(
584
+						'title'    => esc_html__('Contact List Table Column Headings', 'event_espresso'),
585
+						'filename' => 'registrations_contact_list_table_column_headings',
586
+					),
587
+					'registrations_contact_list_views_help_tab'                 => array(
588
+						'title'    => esc_html__('Contact List Views', 'event_espresso'),
589
+						'filename' => 'registrations_contact_list_views',
590
+					),
591
+					'registrations_contact_list_other_help_tab'                 => array(
592
+						'title'    => esc_html__('Contact List Other', 'event_espresso'),
593
+						'filename' => 'registrations_contact_list_other',
594
+					),
595
+				),
596
+				'help_tour'     => array('Contact_List_Help_Tour'),
597
+				'metaboxes'     => array(),
598
+				'require_nonce' => false,
599
+			),
600
+			//override default cpt routes
601
+			'create_new'        => '',
602
+			'edit'              => '',
603
+		);
604
+	}
605
+
606
+
607
+	/**
608
+	 * The below methods aren't used by this class currently
609
+	 */
610
+	protected function _add_screen_options()
611
+	{
612
+	}
613
+
614
+
615
+	protected function _add_feature_pointers()
616
+	{
617
+	}
618
+
619
+
620
+	public function admin_init()
621
+	{
622
+		EE_Registry::$i18n_js_strings['update_att_qstns'] = esc_html__(
623
+			'click "Update Registration Questions" to save your changes',
624
+			'event_espresso'
625
+		);
626
+	}
627
+
628
+
629
+	public function admin_notices()
630
+	{
631
+	}
632
+
633
+
634
+	public function admin_footer_scripts()
635
+	{
636
+	}
637
+
638
+
639
+	/**
640
+	 *        get list of registration statuses
641
+	 *
642
+	 * @access private
643
+	 * @return void
644
+	 * @throws EE_Error
645
+	 */
646
+	private function _get_registration_status_array()
647
+	{
648
+		self::$_reg_status = EEM_Registration::reg_status_array(array(), true);
649
+	}
650
+
651
+
652
+	protected function _add_screen_options_default()
653
+	{
654
+		$this->_per_page_screen_option();
655
+	}
656
+
657
+
658
+	protected function _add_screen_options_contact_list()
659
+	{
660
+		$page_title              = $this->_admin_page_title;
661
+		$this->_admin_page_title = esc_html__("Contacts", 'event_espresso');
662
+		$this->_per_page_screen_option();
663
+		$this->_admin_page_title = $page_title;
664
+	}
665
+
666
+
667
+	public function load_scripts_styles()
668
+	{
669
+		//style
670
+		wp_register_style(
671
+			'espresso_reg',
672
+			REG_ASSETS_URL . 'espresso_registrations_admin.css',
673
+			array('ee-admin-css'),
674
+			EVENT_ESPRESSO_VERSION
675
+		);
676
+		wp_enqueue_style('espresso_reg');
677
+		//script
678
+		wp_register_script(
679
+			'espresso_reg',
680
+			REG_ASSETS_URL . 'espresso_registrations_admin.js',
681
+			array('jquery-ui-datepicker', 'jquery-ui-draggable', 'ee_admin_js'),
682
+			EVENT_ESPRESSO_VERSION,
683
+			true
684
+		);
685
+		wp_enqueue_script('espresso_reg');
686
+	}
687
+
688
+
689
+	public function load_scripts_styles_edit_attendee()
690
+	{
691
+		//stuff to only show up on our attendee edit details page.
692
+		$attendee_details_translations = array(
693
+			'att_publish_text' => sprintf(
694
+				esc_html__('Created on: <b>%1$s</b>', 'event_espresso'),
695
+				$this->_cpt_model_obj->get_datetime('ATT_created')
696
+			),
697
+		);
698
+		wp_localize_script('espresso_reg', 'ATTENDEE_DETAILS', $attendee_details_translations);
699
+		wp_enqueue_script('jquery-validate');
700
+	}
701
+
702
+
703
+	public function load_scripts_styles_view_registration()
704
+	{
705
+		//styles
706
+		wp_enqueue_style('espresso-ui-theme');
707
+		//scripts
708
+		$this->_get_reg_custom_questions_form($this->_registration->ID());
709
+		$this->_reg_custom_questions_form->wp_enqueue_scripts(true);
710
+	}
711
+
712
+
713
+	public function load_scripts_styles_contact_list()
714
+	{
715
+		wp_dequeue_style('espresso_reg');
716
+		wp_register_style(
717
+			'espresso_att',
718
+			REG_ASSETS_URL . 'espresso_attendees_admin.css',
719
+			array('ee-admin-css'),
720
+			EVENT_ESPRESSO_VERSION
721
+		);
722
+		wp_enqueue_style('espresso_att');
723
+	}
724
+
725
+
726
+	public function load_scripts_styles_new_registration()
727
+	{
728
+		wp_register_script(
729
+			'ee-spco-for-admin',
730
+			REG_ASSETS_URL . 'spco_for_admin.js',
731
+			array('underscore', 'jquery'),
732
+			EVENT_ESPRESSO_VERSION,
733
+			true
734
+		);
735
+		wp_enqueue_script('ee-spco-for-admin');
736
+		add_filter('FHEE__EED_Ticket_Selector__load_tckt_slctr_assets', '__return_true');
737
+		EE_Form_Section_Proper::wp_enqueue_scripts();
738
+		EED_Ticket_Selector::load_tckt_slctr_assets();
739
+		EE_Datepicker_Input::enqueue_styles_and_scripts();
740
+	}
741
+
742
+
743
+	public function AHEE__EE_Admin_Page__route_admin_request_resend_registration()
744
+	{
745
+		add_filter('FHEE_load_EE_messages', '__return_true');
746
+	}
747
+
748
+
749
+	public function AHEE__EE_Admin_Page__route_admin_request_approve_registration()
750
+	{
751
+		add_filter('FHEE_load_EE_messages', '__return_true');
752
+	}
753
+
754
+
755
+	protected function _set_list_table_views_default()
756
+	{
757
+		//for notification related bulk actions we need to make sure only active messengers have an option.
758
+		EED_Messages::set_autoloaders();
759
+		/** @type EE_Message_Resource_Manager $message_resource_manager */
760
+		$message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
761
+		$active_mts               = $message_resource_manager->list_of_active_message_types();
762
+		//key= bulk_action_slug, value= message type.
763
+		$match_array = array(
764
+			'approve_registrations'    => 'registration',
765
+			'decline_registrations'    => 'declined_registration',
766
+			'pending_registrations'    => 'pending_approval',
767
+			'no_approve_registrations' => 'not_approved_registration',
768
+			'cancel_registrations'     => 'cancelled_registration',
769
+		);
770
+		$can_send = EE_Registry::instance()->CAP->current_user_can(
771
+			'ee_send_message',
772
+			'batch_send_messages'
773
+		);
774
+		/** setup reg status bulk actions **/
775
+		$def_reg_status_actions['approve_registrations'] = esc_html__('Approve Registrations', 'event_espresso');
776
+		if ($can_send && in_array($match_array['approve_registrations'], $active_mts, true)) {
777
+				$def_reg_status_actions['approve_and_notify_registrations'] = esc_html__(
778
+					'Approve and Notify Registrations',
779
+					'event_espresso'
780
+				);
781
+		}
782
+		$def_reg_status_actions['decline_registrations'] = esc_html__('Decline Registrations', 'event_espresso');
783
+		if ($can_send && in_array($match_array['decline_registrations'], $active_mts, true)) {
784
+				$def_reg_status_actions['decline_and_notify_registrations'] = esc_html__(
785
+					'Decline and Notify Registrations',
786
+					'event_espresso'
787
+				);
788
+		}
789
+		$def_reg_status_actions['pending_registrations'] = esc_html__(
790
+			'Set Registrations to Pending Payment',
791
+			'event_espresso'
792
+		);
793
+		if ($can_send && in_array($match_array['pending_registrations'], $active_mts, true)) {
794
+				$def_reg_status_actions['pending_and_notify_registrations'] = esc_html__(
795
+					'Set Registrations to Pending Payment and Notify',
796
+					'event_espresso'
797
+				);
798
+		}
799
+		$def_reg_status_actions['no_approve_registrations'] = esc_html__(
800
+			'Set Registrations to Not Approved',
801
+			'event_espresso'
802
+		);
803
+		if ($can_send && in_array($match_array['no_approve_registrations'], $active_mts, true)) {
804
+				$def_reg_status_actions['no_approve_and_notify_registrations'] = esc_html__(
805
+					'Set Registrations to Not Approved and Notify',
806
+					'event_espresso'
807
+				);
808
+		}
809
+		$def_reg_status_actions['cancel_registrations'] = esc_html__('Cancel Registrations', 'event_espresso');
810
+		if ($can_send && in_array($match_array['cancel_registrations'], $active_mts, true)) {
811
+				$def_reg_status_actions['cancel_and_notify_registrations'] = esc_html__(
812
+					'Cancel Registrations and Notify',
813
+					'event_espresso'
814
+				);
815
+		}
816
+		$def_reg_status_actions = apply_filters(
817
+			'FHEE__Registrations_Admin_Page___set_list_table_views_default__def_reg_status_actions_array',
818
+			$def_reg_status_actions,
819
+			$active_mts,
820
+			$can_send
821
+		);
822
+
823
+		$this->_views = array(
824
+			'all'   => array(
825
+				'slug'        => 'all',
826
+				'label'       => esc_html__('View All Registrations', 'event_espresso'),
827
+				'count'       => 0,
828
+				'bulk_action' => array_merge($def_reg_status_actions, array(
829
+					'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
830
+				)),
831
+			),
832
+			'month' => array(
833
+				'slug'        => 'month',
834
+				'label'       => esc_html__('This Month', 'event_espresso'),
835
+				'count'       => 0,
836
+				'bulk_action' => array_merge($def_reg_status_actions, array(
837
+					'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
838
+				)),
839
+			),
840
+			'today' => array(
841
+				'slug'        => 'today',
842
+				'label'       => sprintf(
843
+					esc_html__('Today - %s', 'event_espresso'),
844
+					date('M d, Y', current_time('timestamp'))
845
+				),
846
+				'count'       => 0,
847
+				'bulk_action' => array_merge($def_reg_status_actions, array(
848
+					'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
849
+				)),
850
+			),
851
+		);
852
+		if (EE_Registry::instance()->CAP->current_user_can(
853
+			'ee_delete_registrations',
854
+			'espresso_registrations_delete_registration'
855
+		)) {
856
+			$this->_views['incomplete'] = array(
857
+				'slug'        => 'incomplete',
858
+				'label'       => esc_html__('Incomplete', 'event_espresso'),
859
+				'count'       => 0,
860
+				'bulk_action' => array(
861
+					'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
862
+				),
863
+			);
864
+			$this->_views['trash']      = array(
865
+				'slug'        => 'trash',
866
+				'label'       => esc_html__('Trash', 'event_espresso'),
867
+				'count'       => 0,
868
+				'bulk_action' => array(
869
+					'restore_registrations' => esc_html__('Restore Registrations', 'event_espresso'),
870
+					'delete_registrations'  => esc_html__('Delete Registrations Permanently', 'event_espresso'),
871
+				),
872
+			);
873
+		}
874
+	}
875
+
876
+
877
+	protected function _set_list_table_views_contact_list()
878
+	{
879
+		$this->_views = array(
880
+			'in_use' => array(
881
+				'slug'        => 'in_use',
882
+				'label'       => esc_html__('In Use', 'event_espresso'),
883
+				'count'       => 0,
884
+				'bulk_action' => array(
885
+					'trash_attendees' => esc_html__('Move to Trash', 'event_espresso'),
886
+				),
887
+			),
888
+		);
889
+		if (EE_Registry::instance()->CAP->current_user_can('ee_delete_contacts',
890
+			'espresso_registrations_trash_attendees')
891
+		) {
892
+			$this->_views['trash'] = array(
893
+				'slug'        => 'trash',
894
+				'label'       => esc_html__('Trash', 'event_espresso'),
895
+				'count'       => 0,
896
+				'bulk_action' => array(
897
+					'restore_attendees' => esc_html__('Restore from Trash', 'event_espresso'),
898
+				),
899
+			);
900
+		}
901
+	}
902
+
903
+
904
+	protected function _registration_legend_items()
905
+	{
906
+		$fc_items = array(
907
+			'star-icon'        => array(
908
+				'class' => 'dashicons dashicons-star-filled lt-blue-icon ee-icon-size-8',
909
+				'desc'  => esc_html__('This is the Primary Registrant', 'event_espresso'),
910
+			),
911
+			'view_details'     => array(
912
+				'class' => 'dashicons dashicons-clipboard',
913
+				'desc'  => esc_html__('View Registration Details', 'event_espresso'),
914
+			),
915
+			'edit_attendee'    => array(
916
+				'class' => 'ee-icon ee-icon-user-edit ee-icon-size-16',
917
+				'desc'  => esc_html__('Edit Contact Details', 'event_espresso'),
918
+			),
919
+			'view_transaction' => array(
920
+				'class' => 'dashicons dashicons-cart',
921
+				'desc'  => esc_html__('View Transaction Details', 'event_espresso'),
922
+			),
923
+			'view_invoice'     => array(
924
+				'class' => 'dashicons dashicons-media-spreadsheet',
925
+				'desc'  => esc_html__('View Transaction Invoice', 'event_espresso'),
926
+			),
927
+		);
928
+		if (EE_Registry::instance()->CAP->current_user_can(
929
+			'ee_send_message',
930
+			'espresso_registrations_resend_registration'
931
+		)) {
932
+			$fc_items['resend_registration'] = array(
933
+				'class' => 'dashicons dashicons-email-alt',
934
+				'desc'  => esc_html__('Resend Registration Details', 'event_espresso'),
935
+			);
936
+		} else {
937
+			$fc_items['blank'] = array('class' => 'blank', 'desc' => '');
938
+		}
939
+		if (EE_Registry::instance()->CAP->current_user_can(
940
+			'ee_read_global_messages',
941
+			'view_filtered_messages'
942
+		)) {
943
+			$related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
944
+			if (isset($related_for_icon['css_class']) && isset($related_for_icon['label'])) {
945
+				$fc_items['view_related_messages'] = array(
946
+					'class' => $related_for_icon['css_class'],
947
+					'desc'  => $related_for_icon['label'],
948
+				);
949
+			}
950
+		}
951
+		$sc_items = array(
952
+			'approved_status'   => array(
953
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_approved,
954
+				'desc'  => EEH_Template::pretty_status(
955
+					EEM_Registration::status_id_approved,
956
+					false,
957
+					'sentence'
958
+				),
959
+			),
960
+			'pending_status'    => array(
961
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_pending_payment,
962
+				'desc'  => EEH_Template::pretty_status(
963
+					EEM_Registration::status_id_pending_payment,
964
+					false,
965
+					'sentence'
966
+				),
967
+			),
968
+			'wait_list'         => array(
969
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_wait_list,
970
+				'desc'  => EEH_Template::pretty_status(
971
+					EEM_Registration::status_id_wait_list,
972
+					false,
973
+					'sentence'
974
+				),
975
+			),
976
+			'incomplete_status' => array(
977
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_incomplete,
978
+				'desc'  => EEH_Template::pretty_status(
979
+					EEM_Registration::status_id_incomplete,
980
+					false,
981
+					'sentence'
982
+				),
983
+			),
984
+			'not_approved'      => array(
985
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_not_approved,
986
+				'desc'  => EEH_Template::pretty_status(
987
+					EEM_Registration::status_id_not_approved,
988
+					false,
989
+					'sentence'
990
+				),
991
+			),
992
+			'declined_status'   => array(
993
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_declined,
994
+				'desc'  => EEH_Template::pretty_status(
995
+					EEM_Registration::status_id_declined,
996
+					false,
997
+					'sentence'
998
+				),
999
+			),
1000
+			'cancelled_status'  => array(
1001
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_cancelled,
1002
+				'desc'  => EEH_Template::pretty_status(
1003
+					EEM_Registration::status_id_cancelled,
1004
+					false,
1005
+					'sentence'
1006
+				),
1007
+			),
1008
+		);
1009
+		return array_merge($fc_items, $sc_items);
1010
+	}
1011
+
1012
+
1013
+
1014
+	/***************************************        REGISTRATION OVERVIEW        **************************************/
1015
+	/**
1016
+	 * @throws \EE_Error
1017
+	 */
1018
+	protected function _registrations_overview_list_table()
1019
+	{
1020
+		$this->_template_args['admin_page_header'] = '';
1021
+		$EVT_ID                                    = ! empty($this->_req_data['event_id'])
1022
+			? absint($this->_req_data['event_id'])
1023
+			: 0;
1024
+		$ATT_ID = !empty($this->_req_data['ATT_ID'])
1025
+			? absint($this->_req_data['ATT_ID'])
1026
+			: 0;
1027
+		if ($ATT_ID) {
1028
+			$attendee = EEM_Attendee::instance()->get_one_by_ID($ATT_ID);
1029
+			if ($attendee instanceof EE_Attendee) {
1030
+				$this->_template_args['admin_page_header'] = sprintf(
1031
+					esc_html__(
1032
+						'%1$s Viewing registrations for %2$s%3$s',
1033
+						'event_espresso'
1034
+					),
1035
+					'<h3 style="line-height:1.5em;">',
1036
+					'<a href="' . EE_Admin_Page::add_query_args_and_nonce(
1037
+						array(
1038
+							'action' => 'edit_attendee',
1039
+							'post' => $ATT_ID
1040
+						),
1041
+						REG_ADMIN_URL
1042
+					) . '">' . $attendee->full_name() . '</a>',
1043
+					'</h3>'
1044
+				);
1045
+			}
1046
+		}
1047
+		if ($EVT_ID) {
1048
+			if (EE_Registry::instance()->CAP->current_user_can(
1049
+				'ee_edit_registrations',
1050
+				'espresso_registrations_new_registration',
1051
+				$EVT_ID
1052
+			)) {
1053
+				$this->_admin_page_title .= ' ' . $this->get_action_link_or_button(
1054
+					'new_registration',
1055
+					'add-registrant',
1056
+					array('event_id' => $EVT_ID),
1057
+					'add-new-h2'
1058
+				);
1059
+			}
1060
+			$event = EEM_Event::instance()->get_one_by_ID($EVT_ID);
1061
+			if ($event instanceof EE_Event) {
1062
+				$this->_template_args['admin_page_header'] = sprintf(
1063
+					esc_html__(
1064
+						'%s Viewing registrations for the event: %s%s',
1065
+						'event_espresso'
1066
+					),
1067
+					'<h3 style="line-height:1.5em;">',
1068
+					'<br /><a href="'
1069
+						. EE_Admin_Page::add_query_args_and_nonce(
1070
+							array(
1071
+								'action' => 'edit',
1072
+								'post'   => $event->ID(),
1073
+							),
1074
+							EVENTS_ADMIN_URL
1075
+						)
1076
+						. '">&nbsp;'
1077
+						. $event->get('EVT_name')
1078
+						. '&nbsp;</a>&nbsp;',
1079
+					'</h3>'
1080
+				);
1081
+			}
1082
+			$DTT_ID   = ! empty($this->_req_data['datetime_id']) ? absint($this->_req_data['datetime_id']) : 0;
1083
+			$datetime = EEM_Datetime::instance()->get_one_by_ID($DTT_ID);
1084
+			if ($datetime instanceof EE_Datetime && $this->_template_args['admin_page_header'] !== '') {
1085
+				$this->_template_args['admin_page_header'] = substr(
1086
+					$this->_template_args['admin_page_header'],
1087
+					0,
1088
+					-5
1089
+				);
1090
+				$this->_template_args['admin_page_header'] .= ' &nbsp;<span class="drk-grey-text">';
1091
+				$this->_template_args['admin_page_header'] .= '<span class="dashicons dashicons-calendar"></span>';
1092
+				$this->_template_args['admin_page_header'] .= $datetime->name();
1093
+				$this->_template_args['admin_page_header'] .= ' ( ' . $datetime->start_date() . ' )';
1094
+				$this->_template_args['admin_page_header'] .= '</span></h3>';
1095
+			}
1096
+		}
1097
+		$this->_template_args['after_list_table'] = $this->_display_legend($this->_registration_legend_items());
1098
+		$this->display_admin_list_table_page_with_no_sidebar();
1099
+	}
1100
+
1101
+
1102
+	/**
1103
+	 * This sets the _registration property for the registration details screen
1104
+	 *
1105
+	 * @access private
1106
+	 * @return bool
1107
+	 * @throws EE_Error
1108
+	 * @throws InvalidArgumentException
1109
+	 * @throws InvalidDataTypeException
1110
+	 * @throws InvalidInterfaceException
1111
+	 */
1112
+	private function _set_registration_object()
1113
+	{
1114
+		//get out if we've already set the object
1115
+		if ($this->_registration instanceof EE_Registration) {
1116
+			return true;
1117
+		}
1118
+		$REG    = EEM_Registration::instance();
1119
+		$REG_ID = ( ! empty($this->_req_data['_REG_ID'])) ? absint($this->_req_data['_REG_ID']) : false;
1120
+		if ($this->_registration = $REG->get_one_by_ID($REG_ID)) {
1121
+			return true;
1122
+		} else {
1123
+			$error_msg = sprintf(
1124
+				esc_html__(
1125
+					'An error occurred and the details for Registration ID #%s could not be retrieved.',
1126
+					'event_espresso'
1127
+				),
1128
+				$REG_ID
1129
+			);
1130
+			EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
1131
+			$this->_registration = null;
1132
+			return false;
1133
+		}
1134
+	}
1135
+
1136
+
1137
+	/**
1138
+	 * Used to retrieve registrations for the list table.
1139
+	 *
1140
+	 * @param int  $per_page
1141
+	 * @param bool $count
1142
+	 * @param bool $this_month
1143
+	 * @param bool $today
1144
+	 * @return EE_Registration[]|int
1145
+	 * @throws EE_Error
1146
+	 * @throws InvalidArgumentException
1147
+	 * @throws InvalidDataTypeException
1148
+	 * @throws InvalidInterfaceException
1149
+	 */
1150
+	public function get_registrations(
1151
+		$per_page = 10,
1152
+		$count = false,
1153
+		$this_month = false,
1154
+		$today = false
1155
+	) {
1156
+		if ($this_month) {
1157
+			$this->_req_data['status'] = 'month';
1158
+		}
1159
+		if ($today) {
1160
+			$this->_req_data['status'] = 'today';
1161
+		}
1162
+		$query_params = $this->_get_registration_query_parameters($this->_req_data, $per_page, $count);
1163
+		/**
1164
+		 * Override the default groupby added by EEM_Base so that sorts with multiple order bys work as expected
1165
+		 * @link https://events.codebasehq.com/projects/event-espresso/tickets/10093
1166
+		 * @see EEM_Base::get_all()
1167
+		 */
1168
+		$query_params['group_by'] = '';
1169
+
1170
+		return $count
1171
+			? EEM_Registration::instance()->count($query_params)
1172
+			/** @type EE_Registration[] */
1173
+			: EEM_Registration::instance()->get_all($query_params);
1174
+	}
1175
+
1176
+
1177
+	/**
1178
+	 * Retrieves the query parameters to be used by the Registration model for getting registrations.
1179
+	 * Note: this listens to values on the request for some of the query parameters.
1180
+	 *
1181
+	 * @param array $request
1182
+	 * @param int   $per_page
1183
+	 * @param bool  $count
1184
+	 * @return array
1185
+	 * @throws EE_Error
1186
+	 */
1187
+	protected function _get_registration_query_parameters(
1188
+		$request = array(),
1189
+		$per_page = 10,
1190
+		$count = false
1191
+	) {
1192
+
1193
+		$query_params = array(
1194
+			0                          => $this->_get_where_conditions_for_registrations_query(
1195
+				$request
1196
+			),
1197
+			'caps'                     => EEM_Registration::caps_read_admin,
1198
+			'default_where_conditions' => 'this_model_only',
1199
+		);
1200
+		if (! $count) {
1201
+			$query_params = array_merge(
1202
+				$query_params,
1203
+				$this->_get_orderby_for_registrations_query(),
1204
+				$this->_get_limit($per_page)
1205
+			);
1206
+		}
1207
+
1208
+		return $query_params;
1209
+	}
1210
+
1211
+
1212
+	/**
1213
+	 * This will add ATT_ID to the provided $where array for EE model query parameters.
1214
+	 *
1215
+	 * @param array $request usually the same as $this->_req_data but not necessarily
1216
+	 * @return array
1217
+	 */
1218
+	protected function addAttendeeIdToWhereConditions(array $request)
1219
+	{
1220
+		$where = array();
1221
+		if (! empty($request['ATT_ID'])) {
1222
+			$where['ATT_ID'] = absint($request['ATT_ID']);
1223
+		}
1224
+		return $where;
1225
+	}
1226
+
1227
+
1228
+	/**
1229
+	 * This will add EVT_ID to the provided $where array for EE model query parameters.
1230
+	 *
1231
+	 * @param array $request usually the same as $this->_req_data but not necessarily
1232
+	 * @return array
1233
+	 */
1234
+	protected function _add_event_id_to_where_conditions(array $request)
1235
+	{
1236
+		$where = array();
1237
+		if (! empty($request['event_id'])) {
1238
+			$where['EVT_ID'] = absint($request['event_id']);
1239
+		}
1240
+		return $where;
1241
+	}
1242
+
1243
+
1244
+	/**
1245
+	 * Adds category ID if it exists in the request to the where conditions for the registrations query.
1246
+	 *
1247
+	 * @param array $request usually the same as $this->_req_data but not necessarily
1248
+	 * @return array
1249
+	 */
1250
+	protected function _add_category_id_to_where_conditions(array $request)
1251
+	{
1252
+		$where = array();
1253
+		if (! empty($request['EVT_CAT']) && (int)$request['EVT_CAT'] !== -1) {
1254
+			$where['Event.Term_Taxonomy.term_id'] = absint($request['EVT_CAT']);
1255
+		}
1256
+		return $where;
1257
+	}
1258
+
1259
+
1260
+	/**
1261
+	 * Adds the datetime ID if it exists in the request to the where conditions for the registrations query.
1262
+	 *
1263
+	 * @param array $request usually the same as $this->_req_data but not necessarily
1264
+	 * @return array
1265
+	 */
1266
+	protected function _add_datetime_id_to_where_conditions(array $request)
1267
+	{
1268
+		$where = array();
1269
+		if (! empty($request['datetime_id'])) {
1270
+			$where['Ticket.Datetime.DTT_ID'] = absint($request['datetime_id']);
1271
+		}
1272
+		if (! empty($request['DTT_ID'])) {
1273
+			$where['Ticket.Datetime.DTT_ID'] = absint($request['DTT_ID']);
1274
+		}
1275
+		return $where;
1276
+	}
1277
+
1278
+
1279
+	/**
1280
+	 * Adds the correct registration status to the where conditions for the registrations query.
1281
+	 *
1282
+	 * @param array $request usually the same as $this->_req_data but not necessarily
1283
+	 * @return array
1284
+	 */
1285
+	protected function _add_registration_status_to_where_conditions(array $request)
1286
+	{
1287
+		$where = array();
1288
+		$view = EEH_Array::is_set($request, 'status', '');
1289
+		$registration_status = ! empty($request['_reg_status'])
1290
+			? sanitize_text_field($request['_reg_status'])
1291
+			: '';
1292
+
1293
+		/*
1294 1294
          * If filtering by registration status, then we show registrations matching that status.
1295 1295
          * If not filtering by specified status, then we show all registrations excluding incomplete registrations
1296 1296
          * UNLESS viewing trashed registrations.
1297 1297
          */
1298
-        if (! empty($registration_status)) {
1299
-            $where['STS_ID'] = $registration_status;
1300
-        } else {
1301
-            //make sure we exclude incomplete registrations, but only if not trashed.
1302
-            if ($view === 'trash') {
1303
-                $where['REG_deleted'] = true;
1304
-            } elseif ($view === 'incomplete') {
1305
-                $where['STS_ID'] = EEM_Registration::status_id_incomplete;
1306
-            } else {
1307
-                $where['STS_ID'] = array('!=', EEM_Registration::status_id_incomplete);
1308
-            }
1309
-        }
1310
-        return $where;
1311
-    }
1312
-
1313
-
1314
-    /**
1315
-     * Adds any provided date restraints to the where conditions for the registrations query.
1316
-     *
1317
-     * @param array $request usually the same as $this->_req_data but not necessarily
1318
-     * @return array
1319
-     * @throws EE_Error
1320
-     * @throws InvalidArgumentException
1321
-     * @throws InvalidDataTypeException
1322
-     * @throws InvalidInterfaceException
1323
-     */
1324
-    protected function _add_date_to_where_conditions(array $request)
1325
-    {
1326
-        $where = array();
1327
-        $view = EEH_Array::is_set($request, 'status', '');
1328
-        $month_range             = ! empty($request['month_range'])
1329
-            ? sanitize_text_field($request['month_range'])
1330
-            : '';
1331
-        $retrieve_for_today      = $view === 'today';
1332
-        $retrieve_for_this_month = $view === 'month';
1333
-
1334
-        if ($retrieve_for_today) {
1335
-            $now               = date('Y-m-d', current_time('timestamp'));
1336
-            $where['REG_date'] = array(
1337
-                'BETWEEN',
1338
-                array(
1339
-                    EEM_Registration::instance()->convert_datetime_for_query(
1340
-                        'REG_date',
1341
-                        $now . ' 00:00:00',
1342
-                        'Y-m-d H:i:s'
1343
-                    ),
1344
-                    EEM_Registration::instance()->convert_datetime_for_query(
1345
-                        'REG_date',
1346
-                        $now . ' 23:59:59',
1347
-                        'Y-m-d H:i:s'
1348
-                    ),
1349
-                ),
1350
-            );
1351
-        } elseif ($retrieve_for_this_month) {
1352
-            $current_year_and_month = date('Y-m', current_time('timestamp'));
1353
-            $days_this_month        = date('t', current_time('timestamp'));
1354
-            $where['REG_date']      = array(
1355
-                'BETWEEN',
1356
-                array(
1357
-                    EEM_Registration::instance()->convert_datetime_for_query(
1358
-                        'REG_date',
1359
-                        $current_year_and_month . '-01 00:00:00',
1360
-                        'Y-m-d H:i:s'
1361
-                    ),
1362
-                    EEM_Registration::instance()->convert_datetime_for_query(
1363
-                        'REG_date',
1364
-                        $current_year_and_month . '-' . $days_this_month . ' 23:59:59',
1365
-                        'Y-m-d H:i:s'
1366
-                    ),
1367
-                ),
1368
-            );
1369
-        } elseif ($month_range) {
1370
-            $pieces          = explode(' ', $month_range, 3);
1371
-            $month_requested = ! empty($pieces[0])
1372
-                ? date('m', \EEH_DTT_Helper::first_of_month_timestamp($pieces[0]))
1373
-                : '';
1374
-            $year_requested  = ! empty($pieces[1])
1375
-                ? $pieces[1]
1376
-                : '';
1377
-            //if there is not a month or year then we can't go further
1378
-            if ($month_requested && $year_requested) {
1379
-                $days_in_month     = date('t', strtotime($year_requested . '-' . $month_requested . '-' . '01'));
1380
-                $where['REG_date'] = array(
1381
-                    'BETWEEN',
1382
-                    array(
1383
-                        EEM_Registration::instance()->convert_datetime_for_query(
1384
-                            'REG_date',
1385
-                            $year_requested . '-' . $month_requested . '-01 00:00:00',
1386
-                            'Y-m-d H:i:s'
1387
-                        ),
1388
-                        EEM_Registration::instance()->convert_datetime_for_query(
1389
-                            'REG_date',
1390
-                            $year_requested . '-' . $month_requested . '-' . $days_in_month . ' 23:59:59',
1391
-                            'Y-m-d H:i:s'
1392
-                        ),
1393
-                    ),
1394
-                );
1395
-            }
1396
-        }
1397
-        return $where;
1398
-    }
1399
-
1400
-
1401
-    /**
1402
-     * Adds any provided search restraints to the where conditions for the registrations query
1403
-     *
1404
-     * @param array $request usually the same as $this->_req_data but not necessarily
1405
-     * @return array
1406
-     */
1407
-    protected function _add_search_to_where_conditions(array $request)
1408
-    {
1409
-        $where = array();
1410
-        if (! empty($request['s'])) {
1411
-            $search_string = '%' . sanitize_text_field($request['s']) . '%';
1412
-            $where['OR*search_conditions'] = array(
1413
-                'Event.EVT_name'                          => array('LIKE', $search_string),
1414
-                'Event.EVT_desc'                          => array('LIKE', $search_string),
1415
-                'Event.EVT_short_desc'                    => array('LIKE', $search_string),
1416
-                'Attendee.ATT_full_name'                  => array('LIKE', $search_string),
1417
-                'Attendee.ATT_fname'                      => array('LIKE', $search_string),
1418
-                'Attendee.ATT_lname'                      => array('LIKE', $search_string),
1419
-                'Attendee.ATT_short_bio'                  => array('LIKE', $search_string),
1420
-                'Attendee.ATT_email'                      => array('LIKE', $search_string),
1421
-                'Attendee.ATT_address'                    => array('LIKE', $search_string),
1422
-                'Attendee.ATT_address2'                   => array('LIKE', $search_string),
1423
-                'Attendee.ATT_city'                       => array('LIKE', $search_string),
1424
-                'REG_final_price'                         => array('LIKE', $search_string),
1425
-                'REG_code'                                => array('LIKE', $search_string),
1426
-                'REG_count'                               => array('LIKE', $search_string),
1427
-                'REG_group_size'                          => array('LIKE', $search_string),
1428
-                'Ticket.TKT_name'                         => array('LIKE', $search_string),
1429
-                'Ticket.TKT_description'                  => array('LIKE', $search_string),
1430
-                'Transaction.Payment.PAY_txn_id_chq_nmbr' => array('LIKE', $search_string),
1431
-            );
1432
-        }
1433
-        return $where;
1434
-    }
1435
-
1436
-
1437
-    /**
1438
-     * Sets up the where conditions for the registrations query.
1439
-     *
1440
-     * @param array $request
1441
-     * @return array
1442
-     * @throws EE_Error
1443
-     */
1444
-    protected function _get_where_conditions_for_registrations_query($request)
1445
-    {
1446
-        return apply_filters(
1447
-            'FHEE__Registrations_Admin_Page___get_where_conditions_for_registrations_query',
1448
-            array_merge(
1449
-                $this->addAttendeeIdToWhereConditions($request),
1450
-                $this->_add_event_id_to_where_conditions($request),
1451
-                $this->_add_category_id_to_where_conditions($request),
1452
-                $this->_add_datetime_id_to_where_conditions($request),
1453
-                $this->_add_registration_status_to_where_conditions($request),
1454
-                $this->_add_date_to_where_conditions($request),
1455
-                $this->_add_search_to_where_conditions($request)
1456
-            ),
1457
-            $request
1458
-        );
1459
-    }
1460
-
1461
-
1462
-    /**
1463
-     * Sets up the orderby for the registrations query.
1464
-     *
1465
-     * @return array
1466
-     */
1467
-    protected function _get_orderby_for_registrations_query()
1468
-    {
1469
-        $orderby_field = ! empty($this->_req_data['orderby'])
1470
-            ? sanitize_text_field($this->_req_data['orderby'])
1471
-            : '';
1472
-        switch ($orderby_field) {
1473
-            case '_REG_ID':
1474
-                $orderby = array('REG_ID');
1475
-                break;
1476
-            case '_Reg_status':
1477
-                $orderby = array('STS_ID');
1478
-                break;
1479
-            case 'ATT_fname':
1480
-                $orderby = array('Attendee.ATT_fname', 'Attendee.ATT_lname');
1481
-                break;
1482
-            case 'ATT_lname':
1483
-                $orderby = array('Attendee.ATT_lname', 'Attendee.ATT_fname');
1484
-                break;
1485
-            case 'event_name':
1486
-                $orderby = array('Event.EVT_name');
1487
-                break;
1488
-            case 'DTT_EVT_start':
1489
-                $orderby = array('Event.Datetime.DTT_EVT_start');
1490
-                break;
1491
-            default: //'REG_date'
1492
-                $orderby = array('REG_date');
1493
-        }
1494
-
1495
-        //order
1496
-        $order = ! empty($this->_req_data['order'])
1497
-            ? sanitize_text_field($this->_req_data['order'])
1498
-            : 'DESC';
1499
-        $orderby = array_combine(
1500
-            $orderby,
1501
-            array_fill(0, count($orderby), $order)
1502
-        );
1503
-        //because there are many registrations with the same date, define
1504
-        //a secondary way to order them, otherwise MySQL seems to be a bit random
1505
-        if (empty($orderby['REG_ID'])) {
1506
-            $orderby['REG_ID'] = $order;
1507
-        }
1508
-        return array('order_by' => $orderby);
1509
-    }
1510
-
1511
-
1512
-    /**
1513
-     * Sets up the limit for the registrations query.
1514
-     *
1515
-     * @param $per_page
1516
-     * @return array
1517
-     */
1518
-    protected function _get_limit($per_page)
1519
-    {
1520
-        $current_page = ! empty($this->_req_data['paged'])
1521
-            ? absint($this->_req_data['paged'])
1522
-            : 1;
1523
-        $per_page     = ! empty($this->_req_data['perpage'])
1524
-            ? $this->_req_data['perpage']
1525
-            : $per_page;
1526
-
1527
-        //-1 means return all results so get out if that's set.
1528
-        if ((int)$per_page === -1) {
1529
-            return array();
1530
-        }
1531
-        $per_page = absint($per_page);
1532
-        $offset   = ($current_page - 1) * $per_page;
1533
-        return array('limit' => array($offset, $per_page));
1534
-    }
1535
-
1536
-
1537
-    public function get_registration_status_array()
1538
-    {
1539
-        return self::$_reg_status;
1540
-    }
1541
-
1542
-
1543
-
1544
-
1545
-    /***************************************        REGISTRATION DETAILS        ***************************************/
1546
-    /**
1547
-     *        generates HTML for the View Registration Details Admin page
1548
-     *
1549
-     * @access protected
1550
-     * @return void
1551
-     * @throws DomainException
1552
-     * @throws EE_Error
1553
-     * @throws InvalidArgumentException
1554
-     * @throws InvalidDataTypeException
1555
-     * @throws InvalidInterfaceException
1556
-     * @throws EntityNotFoundException
1557
-     */
1558
-    protected function _registration_details()
1559
-    {
1560
-        $this->_template_args = array();
1561
-        $this->_set_registration_object();
1562
-        if (is_object($this->_registration)) {
1563
-            $transaction                                   = $this->_registration->transaction()
1564
-                ? $this->_registration->transaction()
1565
-                : EE_Transaction::new_instance();
1566
-            $this->_session                                = $transaction->session_data();
1567
-            $event_id                                      = $this->_registration->event_ID();
1568
-            $this->_template_args['reg_nmbr']['value']     = $this->_registration->ID();
1569
-            $this->_template_args['reg_nmbr']['label']     = esc_html__('Registration Number', 'event_espresso');
1570
-            $this->_template_args['reg_datetime']['value'] = $this->_registration->get_i18n_datetime('REG_date');
1571
-            $this->_template_args['reg_datetime']['label'] = esc_html__('Date', 'event_espresso');
1572
-            $this->_template_args['grand_total']           = $transaction->total();
1573
-            $this->_template_args['currency_sign']         = EE_Registry::instance()->CFG->currency->sign;
1574
-            // link back to overview
1575
-            $this->_template_args['reg_overview_url']            = REG_ADMIN_URL;
1576
-            $this->_template_args['registration']                = $this->_registration;
1577
-            $this->_template_args['filtered_registrations_link'] = EE_Admin_Page::add_query_args_and_nonce(
1578
-                array(
1579
-                    'action'   => 'default',
1580
-                    'event_id' => $event_id,
1581
-                ),
1582
-                REG_ADMIN_URL
1583
-            );
1584
-            $this->_template_args['filtered_transactions_link']  = EE_Admin_Page::add_query_args_and_nonce(
1585
-                array(
1586
-                    'action' => 'default',
1587
-                    'EVT_ID' => $event_id,
1588
-                    'page'   => 'espresso_transactions',
1589
-                ),
1590
-                admin_url('admin.php')
1591
-            );
1592
-            $this->_template_args['event_link']                  = EE_Admin_Page::add_query_args_and_nonce(
1593
-                array(
1594
-                    'page'   => 'espresso_events',
1595
-                    'action' => 'edit',
1596
-                    'post'   => $event_id,
1597
-                ),
1598
-                admin_url('admin.php')
1599
-            );
1600
-            //next and previous links
1601
-            $next_reg                                      = $this->_registration->next(
1602
-                null,
1603
-                array(),
1604
-                'REG_ID'
1605
-            );
1606
-            $this->_template_args['next_registration']     = $next_reg
1607
-                ? $this->_next_link(
1608
-                    EE_Admin_Page::add_query_args_and_nonce(
1609
-                        array(
1610
-                            'action'  => 'view_registration',
1611
-                            '_REG_ID' => $next_reg['REG_ID'],
1612
-                        ),
1613
-                        REG_ADMIN_URL
1614
-                    ),
1615
-                    'dashicons dashicons-arrow-right ee-icon-size-22'
1616
-                )
1617
-                : '';
1618
-            $previous_reg                                  = $this->_registration->previous(
1619
-                null,
1620
-                array(),
1621
-                'REG_ID'
1622
-            );
1623
-            $this->_template_args['previous_registration'] = $previous_reg
1624
-                ? $this->_previous_link(
1625
-                    EE_Admin_Page::add_query_args_and_nonce(
1626
-                        array(
1627
-                            'action'  => 'view_registration',
1628
-                            '_REG_ID' => $previous_reg['REG_ID'],
1629
-                        ),
1630
-                        REG_ADMIN_URL
1631
-                    ),
1632
-                    'dashicons dashicons-arrow-left ee-icon-size-22'
1633
-                )
1634
-                : '';
1635
-            // grab header
1636
-            $template_path                             = REG_TEMPLATE_PATH . 'reg_admin_details_header.template.php';
1637
-            $this->_template_args['REG_ID']            = $this->_registration->ID();
1638
-            $this->_template_args['admin_page_header'] = EEH_Template::display_template(
1639
-                $template_path,
1640
-                $this->_template_args,
1641
-                true
1642
-            );
1643
-        } else {
1644
-            $this->_template_args['admin_page_header'] = $this->display_espresso_notices();
1645
-        }
1646
-        // the details template wrapper
1647
-        $this->display_admin_page_with_sidebar();
1648
-    }
1649
-
1650
-
1651
-    protected function _registration_details_metaboxes()
1652
-    {
1653
-        do_action('AHEE__Registrations_Admin_Page___registration_details_metabox__start', $this);
1654
-        $this->_set_registration_object();
1655
-        $attendee = $this->_registration instanceof EE_Registration ? $this->_registration->attendee() : null;
1656
-        add_meta_box('edit-reg-status-mbox', esc_html__('Registration Status', 'event_espresso'),
1657
-            array($this, 'set_reg_status_buttons_metabox'), $this->wp_page_slug, 'normal', 'high');
1658
-        add_meta_box('edit-reg-details-mbox', esc_html__('Registration Details', 'event_espresso'),
1659
-            array($this, '_reg_details_meta_box'), $this->wp_page_slug, 'normal', 'high');
1660
-        if ($attendee instanceof EE_Attendee
1661
-            && EE_Registry::instance()->CAP->current_user_can(
1662
-                'ee_edit_registration',
1663
-                'edit-reg-questions-mbox',
1664
-                $this->_registration->ID()
1665
-            )
1666
-        ) {
1667
-            add_meta_box(
1668
-                'edit-reg-questions-mbox',
1669
-                esc_html__('Registration Form Answers', 'event_espresso'),
1670
-                array($this, '_reg_questions_meta_box'),
1671
-                $this->wp_page_slug,
1672
-                'normal',
1673
-                'high'
1674
-            );
1675
-        }
1676
-        add_meta_box(
1677
-            'edit-reg-registrant-mbox',
1678
-            esc_html__('Contact Details', 'event_espresso'),
1679
-            array($this, '_reg_registrant_side_meta_box'),
1680
-            $this->wp_page_slug,
1681
-            'side',
1682
-            'high'
1683
-        );
1684
-        if ($this->_registration->group_size() > 1) {
1685
-            add_meta_box(
1686
-                'edit-reg-attendees-mbox',
1687
-                esc_html__('Other Registrations in this Transaction', 'event_espresso'),
1688
-                array($this, '_reg_attendees_meta_box'),
1689
-                $this->wp_page_slug,
1690
-                'normal',
1691
-                'high'
1692
-            );
1693
-        }
1694
-    }
1695
-
1696
-
1697
-    /**
1698
-     * set_reg_status_buttons_metabox
1699
-     *
1700
-     * @access protected
1701
-     * @return string
1702
-     * @throws \EE_Error
1703
-     */
1704
-    public function set_reg_status_buttons_metabox()
1705
-    {
1706
-        $this->_set_registration_object();
1707
-        $change_reg_status_form = $this->_generate_reg_status_change_form();
1708
-        echo $change_reg_status_form->form_open(
1709
-            self::add_query_args_and_nonce(
1710
-                array(
1711
-                    'action' => 'change_reg_status',
1712
-                ),
1713
-                REG_ADMIN_URL
1714
-            )
1715
-        );
1716
-        echo $change_reg_status_form->get_html();
1717
-        echo $change_reg_status_form->form_close();
1718
-    }
1719
-
1720
-
1721
-    /**
1722
-     * @return EE_Form_Section_Proper
1723
-     * @throws EE_Error
1724
-     * @throws InvalidArgumentException
1725
-     * @throws InvalidDataTypeException
1726
-     * @throws InvalidInterfaceException
1727
-     * @throws \EventEspresso\core\exceptions\EntityNotFoundException
1728
-     */
1729
-    protected function _generate_reg_status_change_form()
1730
-    {
1731
-        return new EE_Form_Section_Proper(array(
1732
-            'name'            => 'reg_status_change_form',
1733
-            'html_id'         => 'reg-status-change-form',
1734
-            'layout_strategy' => new EE_Admin_Two_Column_Layout(),
1735
-            'subsections'     => array(
1736
-                'return'             => new EE_Hidden_Input(array(
1737
-                    'name'    => 'return',
1738
-                    'default' => 'view_registration',
1739
-                )),
1740
-                'REG_ID'             => new EE_Hidden_Input(array(
1741
-                    'name'    => 'REG_ID',
1742
-                    'default' => $this->_registration->ID(),
1743
-                )),
1744
-                'current_status'     => new EE_Form_Section_HTML(
1745
-                    EEH_HTML::tr(
1746
-                        EEH_HTML::th(
1747
-                            EEH_HTML::label(
1748
-                                EEH_HTML::strong(esc_html__('Current Registration Status', 'event_espresso')
1749
-                                )
1750
-                            )
1751
-                        )
1752
-                        . EEH_HTML::td(
1753
-                            EEH_HTML::strong(
1754
-                                $this->_registration->pretty_status(),
1755
-                                '',
1756
-                                'status-' . $this->_registration->status_ID(),
1757
-                                'line-height: 1em; font-size: 1.5em; font-weight: bold;'
1758
-                            )
1759
-                        )
1760
-                    )
1761
-                ),
1762
-                'reg_status'         => new EE_Select_Input(
1763
-                    $this->_get_reg_statuses(),
1764
-                    array(
1765
-                        'html_label_text' => esc_html__('Change Registration Status to', 'event_espresso'),
1766
-                        'default'         => $this->_registration->status_ID(),
1767
-                    )
1768
-                ),
1769
-                'send_notifications' => new EE_Yes_No_Input(
1770
-                    array(
1771
-                        'html_label_text' => esc_html__('Send Related Messages', 'event_espresso'),
1772
-                        'default'         => false,
1773
-                        'html_help_text'  => esc_html__(
1774
-                            'If set to "Yes", then the related messages will be sent to the registrant.',
1775
-                            'event_espresso'
1776
-                        ),
1777
-                    )
1778
-                ),
1779
-                'submit'             => new EE_Submit_Input(
1780
-                    array(
1781
-                        'html_class'      => 'button-primary',
1782
-                        'html_label_text' => '&nbsp;',
1783
-                        'default'         => esc_html__('Update Registration Status', 'event_espresso'),
1784
-                    )
1785
-                ),
1786
-            ),
1787
-        ));
1788
-    }
1789
-
1790
-
1791
-    /**
1792
-     * Returns an array of all the buttons for the various statuses and switch status actions
1793
-     *
1794
-     * @return array
1795
-     * @throws EE_Error
1796
-     * @throws InvalidArgumentException
1797
-     * @throws InvalidDataTypeException
1798
-     * @throws InvalidInterfaceException
1799
-     * @throws EntityNotFoundException
1800
-     */
1801
-    protected function _get_reg_statuses()
1802
-    {
1803
-        $reg_status_array = EEM_Registration::instance()->reg_status_array();
1804
-        unset ($reg_status_array[EEM_Registration::status_id_incomplete]);
1805
-        // get current reg status
1806
-        $current_status = $this->_registration->status_ID();
1807
-        // is registration for free event? This will determine whether to display the pending payment option
1808
-        if (
1809
-            $current_status !== EEM_Registration::status_id_pending_payment
1810
-            && EEH_Money::compare_floats($this->_registration->ticket()->price(), 0.00)
1811
-        ) {
1812
-            unset($reg_status_array[EEM_Registration::status_id_pending_payment]);
1813
-        }
1814
-        return EEM_Status::instance()->localized_status($reg_status_array, false, 'sentence');
1815
-    }
1816
-
1817
-
1818
-    /**
1819
-     * This method is used when using _REG_ID from request which may or may not be an array of reg_ids.
1820
-     *
1821
-     * @param bool $status REG status given for changing registrations to.
1822
-     * @param bool $notify Whether to send messages notifications or not.
1823
-     * @return array (array with reg_id(s) updated and whether update was successful.
1824
-     * @throws EE_Error
1825
-     * @throws InvalidArgumentException
1826
-     * @throws InvalidDataTypeException
1827
-     * @throws InvalidInterfaceException
1828
-     * @throws ReflectionException
1829
-     * @throws RuntimeException
1830
-     * @throws EntityNotFoundException
1831
-     */
1832
-    protected function _set_registration_status_from_request($status = false, $notify = false)
1833
-    {
1834
-        if (isset($this->_req_data['reg_status_change_form'])) {
1835
-            $REG_IDs = isset($this->_req_data['reg_status_change_form']['REG_ID'])
1836
-                ? (array)$this->_req_data['reg_status_change_form']['REG_ID']
1837
-                : array();
1838
-        } else {
1839
-            $REG_IDs = isset($this->_req_data['_REG_ID'])
1840
-                ? (array)$this->_req_data['_REG_ID']
1841
-                : array();
1842
-        }
1843
-        // sanitize $REG_IDs
1844
-        $REG_IDs = array_map('absint', $REG_IDs);
1845
-        // and remove empty entries
1846
-        $REG_IDs = array_filter($REG_IDs);
1847
-
1848
-        $result = $this->_set_registration_status($REG_IDs, $status, $notify);
1849
-
1850
-        /**
1851
-         * Set and filter $_req_data['_REG_ID'] for any potential future messages notifications.
1852
-         * Currently this value is used downstream by the _process_resend_registration method.
1853
-         *
1854
-         * @param int|array                $registration_ids The registration ids that have had their status changed successfully.
1855
-         * @param bool                     $status           The status registrations were changed to.
1856
-         * @param bool                     $success          If the status was changed successfully for all registrations.
1857
-         * @param Registrations_Admin_Page $admin_page_object
1858
-         */
1859
-        $this->_req_data['_REG_ID'] = apply_filters(
1860
-            'FHEE__Registrations_Admin_Page___set_registration_status_from_request__REG_IDs',
1861
-            $result['REG_ID'],
1862
-            $status,
1863
-            $result['success'],
1864
-            $this
1865
-        );
1866
-
1867
-        //notify?
1868
-        if ($notify
1869
-            && $result['success']
1870
-            && ! empty($this->_req_data['_REG_ID'])
1871
-            && EE_Registry::instance()->CAP->current_user_can(
1872
-                'ee_send_message',
1873
-                'espresso_registrations_resend_registration'
1874
-            )
1875
-        ) {
1876
-            $this->_process_resend_registration();
1877
-        }
1878
-        return $result;
1879
-    }
1880
-
1881
-
1882
-    /**
1883
-     * Set the registration status for the given reg_id (which may or may not be an array, it gets typecast to an
1884
-     * array). Note, this method does NOT take care of possible notifications.  That is required by calling code.
1885
-     *
1886
-     * @param array  $REG_IDs
1887
-     * @param string $status
1888
-     * @param bool   $notify  Used to indicate whether notification was requested or not.  This determines the context
1889
-     *                        slug sent with setting the registration status.
1890
-     * @return array (an array with 'success' key representing whether status change was successful, and 'REG_ID' as
1891
-     * @throws EE_Error
1892
-     * @throws InvalidArgumentException
1893
-     * @throws InvalidDataTypeException
1894
-     * @throws InvalidInterfaceException
1895
-     * @throws ReflectionException
1896
-     * @throws RuntimeException
1897
-     * @throws EntityNotFoundException
1898
-     */
1899
-    protected function _set_registration_status($REG_IDs = array(), $status = '', $notify = false)
1900
-    {
1901
-        $success = false;
1902
-        // typecast $REG_IDs
1903
-        $REG_IDs = (array)$REG_IDs;
1904
-        if ( ! empty($REG_IDs)) {
1905
-            $success = true;
1906
-            // set default status if none is passed
1907
-            $status = $status ? $status : EEM_Registration::status_id_pending_payment;
1908
-            $status_context = $notify
1909
-                ? Domain::CONTEXT_REGISTRATION_STATUS_CHANGE_REGISTRATION_ADMIN_NOTIFY
1910
-                : Domain::CONTEXT_REGISTRATION_STATUS_CHANGE_REGISTRATION_ADMIN;
1911
-            //loop through REG_ID's and change status
1912
-            foreach ($REG_IDs as $REG_ID) {
1913
-                $registration = EEM_Registration::instance()->get_one_by_ID($REG_ID);
1914
-                if ($registration instanceof EE_Registration) {
1915
-                    $registration->set_status(
1916
-                        $status,
1917
-                        false,
1918
-                        new Context(
1919
-                            $status_context,
1920
-                            esc_html__(
1921
-                                'Manually triggered status change on a Registration Admin Page route.',
1922
-                                'event_espresso'
1923
-                            )
1924
-                        )
1925
-                    );
1926
-                    $result = $registration->save();
1927
-                    // verifying explicit fails because update *may* just return 0 for 0 rows affected
1928
-                    $success = $result !== false ? $success : false;
1929
-                }
1930
-            }
1931
-        }
1932
-
1933
-        //return $success and processed registrations
1934
-        return array('REG_ID' => $REG_IDs, 'success' => $success);
1935
-    }
1936
-
1937
-
1938
-    /**
1939
-     * Common logic for setting up success message and redirecting to appropriate route
1940
-     *
1941
-     * @param  string $STS_ID status id for the registration changed to
1942
-     * @param   bool  $notify indicates whether the _set_registration_status_from_request does notifications or not.
1943
-     * @return void
1944
-     * @throws EE_Error
1945
-     */
1946
-    protected function _reg_status_change_return($STS_ID, $notify = false)
1947
-    {
1948
-        $result  = ! empty($STS_ID) ? $this->_set_registration_status_from_request($STS_ID, $notify)
1949
-            : array('success' => false);
1950
-        $success = isset($result['success']) && $result['success'];
1951
-        //setup success message
1952
-        if ($success) {
1953
-            if (is_array($result['REG_ID']) && count($result['REG_ID']) === 1) {
1954
-                $msg = sprintf(esc_html__('Registration status has been set to %s', 'event_espresso'),
1955
-                    EEH_Template::pretty_status($STS_ID, false, 'lower'));
1956
-            } else {
1957
-                $msg = sprintf(esc_html__('Registrations have been set to %s.', 'event_espresso'),
1958
-                    EEH_Template::pretty_status($STS_ID, false, 'lower'));
1959
-            }
1960
-            EE_Error::add_success($msg);
1961
-        } else {
1962
-            EE_Error::add_error(
1963
-                esc_html__(
1964
-                    'Something went wrong, and the status was not changed',
1965
-                    'event_espresso'
1966
-                ), __FILE__, __LINE__, __FUNCTION__
1967
-            );
1968
-        }
1969
-        if (isset($this->_req_data['return']) && $this->_req_data['return'] == 'view_registration') {
1970
-            $route = array('action' => 'view_registration', '_REG_ID' => reset($result['REG_ID']));
1971
-        } else {
1972
-            $route = array('action' => 'default');
1973
-        }
1974
-        //unset nonces
1975
-        foreach ($this->_req_data as $ref => $value) {
1976
-            if (strpos($ref, 'nonce') !== false) {
1977
-                unset($this->_req_data[$ref]);
1978
-                continue;
1979
-            }
1980
-            $value                 = is_array($value) ? array_map('urlencode', $value) : urlencode($value);
1981
-            $this->_req_data[$ref] = $value;
1982
-        }
1983
-        //merge request vars so that the reloaded list table contains any existing filter query params
1984
-        $route = array_merge($this->_req_data, $route);
1985
-        $this->_redirect_after_action($success, '', '', $route, true);
1986
-    }
1987
-
1988
-
1989
-    /**
1990
-     * incoming reg status change from reg details page.
1991
-     *
1992
-     * @return void
1993
-     */
1994
-    protected function _change_reg_status()
1995
-    {
1996
-        $this->_req_data['return'] = 'view_registration';
1997
-        //set notify based on whether the send notifications toggle is set or not
1998
-        $notify = ! empty($this->_req_data['reg_status_change_form']['send_notifications']);
1999
-        //$notify = ! empty( $this->_req_data['txn_reg_status_change']['send_notifications'] );
2000
-        $this->_req_data['reg_status_change_form']['reg_status'] = isset($this->_req_data['reg_status_change_form']['reg_status'])
2001
-            ? $this->_req_data['reg_status_change_form']['reg_status'] : '';
2002
-        switch ($this->_req_data['reg_status_change_form']['reg_status']) {
2003
-            case EEM_Registration::status_id_approved :
2004
-            case EEH_Template::pretty_status(EEM_Registration::status_id_approved, false, 'sentence') :
2005
-                $this->approve_registration($notify);
2006
-                break;
2007
-            case EEM_Registration::status_id_pending_payment :
2008
-            case EEH_Template::pretty_status(EEM_Registration::status_id_pending_payment, false, 'sentence') :
2009
-                $this->pending_registration($notify);
2010
-                break;
2011
-            case EEM_Registration::status_id_not_approved :
2012
-            case EEH_Template::pretty_status(EEM_Registration::status_id_not_approved, false, 'sentence') :
2013
-                $this->not_approve_registration($notify);
2014
-                break;
2015
-            case EEM_Registration::status_id_declined :
2016
-            case EEH_Template::pretty_status(EEM_Registration::status_id_declined, false, 'sentence') :
2017
-                $this->decline_registration($notify);
2018
-                break;
2019
-            case EEM_Registration::status_id_cancelled :
2020
-            case EEH_Template::pretty_status(EEM_Registration::status_id_cancelled, false, 'sentence') :
2021
-                $this->cancel_registration($notify);
2022
-                break;
2023
-            case EEM_Registration::status_id_wait_list :
2024
-            case EEH_Template::pretty_status(EEM_Registration::status_id_wait_list, false, 'sentence') :
2025
-                $this->wait_list_registration($notify);
2026
-                break;
2027
-            case EEM_Registration::status_id_incomplete :
2028
-            default :
2029
-                $result['success'] = false;
2030
-                unset($this->_req_data['return']);
2031
-                $this->_reg_status_change_return('', false);
2032
-                break;
2033
-        }
2034
-    }
2035
-
2036
-
2037
-    /**
2038
-     * Callback for bulk action routes.
2039
-     * Note: although we could just register the singular route callbacks for each bulk action route as well, this
2040
-     * method was chosen so there is one central place all the registration status bulk actions are going through.
2041
-     * Potentially, this provides an easier place to locate logic that is specific to these bulk actions (as opposed to
2042
-     * when an action is happening on just a single registration).
2043
-     * @param      $action
2044
-     * @param bool $notify
2045
-     */
2046
-    protected function bulk_action_on_registrations($action, $notify = false) {
2047
-        do_action(
2048
-            'AHEE__Registrations_Admin_Page__bulk_action_on_registrations__before_execution',
2049
-            $this,
2050
-            $action,
2051
-            $notify
2052
-        );
2053
-        $method = $action . '_registration';
2054
-        if (method_exists($this, $method)) {
2055
-            $this->$method($notify);
2056
-        }
2057
-    }
2058
-
2059
-
2060
-    /**
2061
-     * approve_registration
2062
-     *
2063
-     * @access protected
2064
-     * @param bool $notify whether or not to notify the registrant about their approval.
2065
-     * @return void
2066
-     */
2067
-    protected function approve_registration($notify = false)
2068
-    {
2069
-        $this->_reg_status_change_return(EEM_Registration::status_id_approved, $notify);
2070
-    }
2071
-
2072
-
2073
-    /**
2074
-     *        decline_registration
2075
-     *
2076
-     * @access protected
2077
-     * @param bool $notify whether or not to notify the registrant about their status change.
2078
-     * @return void
2079
-     */
2080
-    protected function decline_registration($notify = false)
2081
-    {
2082
-        $this->_reg_status_change_return(EEM_Registration::status_id_declined, $notify);
2083
-    }
2084
-
2085
-
2086
-    /**
2087
-     *        cancel_registration
2088
-     *
2089
-     * @access protected
2090
-     * @param bool $notify whether or not to notify the registrant about their status change.
2091
-     * @return void
2092
-     */
2093
-    protected function cancel_registration($notify = false)
2094
-    {
2095
-        $this->_reg_status_change_return(EEM_Registration::status_id_cancelled, $notify);
2096
-    }
2097
-
2098
-
2099
-    /**
2100
-     *        not_approve_registration
2101
-     *
2102
-     * @access protected
2103
-     * @param bool $notify whether or not to notify the registrant about their status change.
2104
-     * @return void
2105
-     */
2106
-    protected function not_approve_registration($notify = false)
2107
-    {
2108
-        $this->_reg_status_change_return(EEM_Registration::status_id_not_approved, $notify);
2109
-    }
2110
-
2111
-
2112
-    /**
2113
-     *        decline_registration
2114
-     *
2115
-     * @access protected
2116
-     * @param bool $notify whether or not to notify the registrant about their status change.
2117
-     * @return void
2118
-     */
2119
-    protected function pending_registration($notify = false)
2120
-    {
2121
-        $this->_reg_status_change_return(EEM_Registration::status_id_pending_payment, $notify);
2122
-    }
2123
-
2124
-
2125
-    /**
2126
-     * waitlist_registration
2127
-     *
2128
-     * @access protected
2129
-     * @param bool $notify whether or not to notify the registrant about their status change.
2130
-     * @return void
2131
-     */
2132
-    protected function wait_list_registration($notify = false)
2133
-    {
2134
-        $this->_reg_status_change_return(EEM_Registration::status_id_wait_list, $notify);
2135
-    }
2136
-
2137
-
2138
-    /**
2139
-     *        generates HTML for the Registration main meta box
2140
-     *
2141
-     * @access public
2142
-     * @return void
2143
-     * @throws DomainException
2144
-     * @throws EE_Error
2145
-     * @throws InvalidArgumentException
2146
-     * @throws InvalidDataTypeException
2147
-     * @throws InvalidInterfaceException
2148
-     * @throws ReflectionException
2149
-     * @throws EntityNotFoundException
2150
-     */
2151
-    public function _reg_details_meta_box()
2152
-    {
2153
-        EEH_Autoloader::register_line_item_display_autoloaders();
2154
-        EEH_Autoloader::register_line_item_filter_autoloaders();
2155
-        EE_Registry::instance()->load_helper('Line_Item');
2156
-        $transaction    = $this->_registration->transaction() ? $this->_registration->transaction()
2157
-            : EE_Transaction::new_instance();
2158
-        $this->_session = $transaction->session_data();
2159
-        $filters        = new EE_Line_Item_Filter_Collection();
2160
-        //$filters->add( new EE_Non_Zero_Line_Item_Filter() );
2161
-        $filters->add(new EE_Single_Registration_Line_Item_Filter($this->_registration));
2162
-        $line_item_filter_processor              = new EE_Line_Item_Filter_Processor($filters,
2163
-            $transaction->total_line_item());
2164
-        $filtered_line_item_tree                 = $line_item_filter_processor->process();
2165
-        $line_item_display                       = new EE_Line_Item_Display('reg_admin_table',
2166
-            'EE_Admin_Table_Registration_Line_Item_Display_Strategy');
2167
-        $this->_template_args['line_item_table'] = $line_item_display->display_line_item(
2168
-            $filtered_line_item_tree,
2169
-            array('EE_Registration' => $this->_registration)
2170
-        );
2171
-        $attendee                                = $this->_registration->attendee();
2172
-        if (EE_Registry::instance()->CAP->current_user_can(
2173
-            'ee_read_transaction',
2174
-            'espresso_transactions_view_transaction'
2175
-        )) {
2176
-            $this->_template_args['view_transaction_button'] = EEH_Template::get_button_or_link(
2177
-                EE_Admin_Page::add_query_args_and_nonce(
2178
-                    array(
2179
-                        'action' => 'view_transaction',
2180
-                        'TXN_ID' => $transaction->ID(),
2181
-                    ),
2182
-                    TXN_ADMIN_URL
2183
-                ),
2184
-                esc_html__(' View Transaction', 'event_espresso'),
2185
-                'button secondary-button right',
2186
-                'dashicons dashicons-cart'
2187
-            );
2188
-        } else {
2189
-            $this->_template_args['view_transaction_button'] = '';
2190
-        }
2191
-        if ($attendee instanceof EE_Attendee
2192
-            && EE_Registry::instance()->CAP->current_user_can(
2193
-                'ee_send_message',
2194
-                'espresso_registrations_resend_registration'
2195
-            )
2196
-        ) {
2197
-            $this->_template_args['resend_registration_button'] = EEH_Template::get_button_or_link(
2198
-                EE_Admin_Page::add_query_args_and_nonce(
2199
-                    array(
2200
-                        'action'      => 'resend_registration',
2201
-                        '_REG_ID'     => $this->_registration->ID(),
2202
-                        'redirect_to' => 'view_registration',
2203
-                    ),
2204
-                    REG_ADMIN_URL
2205
-                ),
2206
-                esc_html__(' Resend Registration', 'event_espresso'),
2207
-                'button secondary-button right',
2208
-                'dashicons dashicons-email-alt'
2209
-            );
2210
-        } else {
2211
-            $this->_template_args['resend_registration_button'] = '';
2212
-        }
2213
-        $this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
2214
-        $payment                               = $transaction->get_first_related('Payment');
2215
-        $payment                               = ! $payment instanceof EE_Payment
2216
-            ? EE_Payment::new_instance()
2217
-            : $payment;
2218
-        $payment_method                        = $payment->get_first_related('Payment_Method');
2219
-        $payment_method                        = ! $payment_method instanceof EE_Payment_Method
2220
-            ? EE_Payment_Method::new_instance()
2221
-            : $payment_method;
2222
-        $reg_details                           = array(
2223
-            'payment_method'       => $payment_method->name(),
2224
-            'response_msg'         => $payment->gateway_response(),
2225
-            'registration_id'      => $this->_registration->get('REG_code'),
2226
-            'registration_session' => $this->_registration->session_ID(),
2227
-            'ip_address'           => isset($this->_session['ip_address']) ? $this->_session['ip_address'] : '',
2228
-            'user_agent'           => isset($this->_session['user_agent']) ? $this->_session['user_agent'] : '',
2229
-        );
2230
-        if (isset($reg_details['registration_id'])) {
2231
-            $this->_template_args['reg_details']['registration_id']['value'] = $reg_details['registration_id'];
2232
-            $this->_template_args['reg_details']['registration_id']['label'] = esc_html__(
2233
-                'Registration ID',
2234
-                'event_espresso'
2235
-            );
2236
-            $this->_template_args['reg_details']['registration_id']['class'] = 'regular-text';
2237
-        }
2238
-        if (isset($reg_details['payment_method'])) {
2239
-            $this->_template_args['reg_details']['payment_method']['value'] = $reg_details['payment_method'];
2240
-            $this->_template_args['reg_details']['payment_method']['label'] = esc_html__(
2241
-                'Most Recent Payment Method',
2242
-                'event_espresso'
2243
-            );
2244
-            $this->_template_args['reg_details']['payment_method']['class'] = 'regular-text';
2245
-            $this->_template_args['reg_details']['response_msg']['value']   = $reg_details['response_msg'];
2246
-            $this->_template_args['reg_details']['response_msg']['label']   = esc_html__(
2247
-                'Payment method response',
2248
-                'event_espresso'
2249
-            );
2250
-            $this->_template_args['reg_details']['response_msg']['class']   = 'regular-text';
2251
-        }
2252
-        $this->_template_args['reg_details']['registration_session']['value'] = $reg_details['registration_session'];
2253
-        $this->_template_args['reg_details']['registration_session']['label'] = esc_html__(
2254
-            'Registration Session',
2255
-            'event_espresso'
2256
-        );
2257
-        $this->_template_args['reg_details']['registration_session']['class'] = 'regular-text';
2258
-        $this->_template_args['reg_details']['ip_address']['value']           = $reg_details['ip_address'];
2259
-        $this->_template_args['reg_details']['ip_address']['label']           = esc_html__(
2260
-            'Registration placed from IP',
2261
-            'event_espresso'
2262
-        );
2263
-        $this->_template_args['reg_details']['ip_address']['class']           = 'regular-text';
2264
-        $this->_template_args['reg_details']['user_agent']['value']           = $reg_details['user_agent'];
2265
-        $this->_template_args['reg_details']['user_agent']['label']           = esc_html__('Registrant User Agent',
2266
-            'event_espresso');
2267
-        $this->_template_args['reg_details']['user_agent']['class']           = 'large-text';
2268
-        $this->_template_args['event_link']                                   = EE_Admin_Page::add_query_args_and_nonce(
2269
-            array(
2270
-                'action'   => 'default',
2271
-                'event_id' => $this->_registration->event_ID(),
2272
-            ),
2273
-            REG_ADMIN_URL
2274
-        );
2275
-        $this->_template_args['REG_ID']                                       = $this->_registration->ID();
2276
-        $this->_template_args['event_id']                                     = $this->_registration->event_ID();
2277
-        $template_path                                                        =
2278
-            REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_reg_details.template.php';
2279
-        echo EEH_Template::display_template($template_path, $this->_template_args, true);
2280
-    }
2281
-
2282
-
2283
-    /**
2284
-     * generates HTML for the Registration Questions meta box.
2285
-     * If pre-4.8.32.rc.000 hooks are used, uses old methods (with its filters),
2286
-     * otherwise uses new forms system
2287
-     *
2288
-     * @access public
2289
-     * @return void
2290
-     * @throws DomainException
2291
-     * @throws EE_Error
2292
-     */
2293
-    public function _reg_questions_meta_box()
2294
-    {
2295
-        //allow someone to override this method entirely
2296
-        if (apply_filters('FHEE__Registrations_Admin_Page___reg_questions_meta_box__do_default', true, $this,
2297
-            $this->_registration)) {
2298
-            $form                                              = $this->_get_reg_custom_questions_form(
2299
-                $this->_registration->ID()
2300
-            );
2301
-            $this->_template_args['att_questions']             = count($form->subforms()) > 0
2302
-                ? $form->get_html_and_js()
2303
-                : '';
2304
-            $this->_template_args['reg_questions_form_action'] = 'edit_registration';
2305
-            $this->_template_args['REG_ID']                    = $this->_registration->ID();
2306
-            $template_path                                     =
2307
-                REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_reg_questions.template.php';
2308
-            echo EEH_Template::display_template($template_path, $this->_template_args, true);
2309
-        }
2310
-    }
2311
-
2312
-
2313
-    /**
2314
-     * form_before_question_group
2315
-     *
2316
-     * @deprecated    as of 4.8.32.rc.000
2317
-     * @access        public
2318
-     * @param        string $output
2319
-     * @return        string
2320
-     */
2321
-    public function form_before_question_group($output)
2322
-    {
2323
-        EE_Error::doing_it_wrong(
2324
-            __CLASS__ . '::' . __FUNCTION__,
2325
-            esc_html__(
2326
-                'This method would have been protected but was used on a filter callback so needed to be public. Please discontinue usage as it will be removed soon.',
2327
-                'event_espresso'
2328
-            ),
2329
-            '4.8.32.rc.000'
2330
-        );
2331
-        return '
1298
+		if (! empty($registration_status)) {
1299
+			$where['STS_ID'] = $registration_status;
1300
+		} else {
1301
+			//make sure we exclude incomplete registrations, but only if not trashed.
1302
+			if ($view === 'trash') {
1303
+				$where['REG_deleted'] = true;
1304
+			} elseif ($view === 'incomplete') {
1305
+				$where['STS_ID'] = EEM_Registration::status_id_incomplete;
1306
+			} else {
1307
+				$where['STS_ID'] = array('!=', EEM_Registration::status_id_incomplete);
1308
+			}
1309
+		}
1310
+		return $where;
1311
+	}
1312
+
1313
+
1314
+	/**
1315
+	 * Adds any provided date restraints to the where conditions for the registrations query.
1316
+	 *
1317
+	 * @param array $request usually the same as $this->_req_data but not necessarily
1318
+	 * @return array
1319
+	 * @throws EE_Error
1320
+	 * @throws InvalidArgumentException
1321
+	 * @throws InvalidDataTypeException
1322
+	 * @throws InvalidInterfaceException
1323
+	 */
1324
+	protected function _add_date_to_where_conditions(array $request)
1325
+	{
1326
+		$where = array();
1327
+		$view = EEH_Array::is_set($request, 'status', '');
1328
+		$month_range             = ! empty($request['month_range'])
1329
+			? sanitize_text_field($request['month_range'])
1330
+			: '';
1331
+		$retrieve_for_today      = $view === 'today';
1332
+		$retrieve_for_this_month = $view === 'month';
1333
+
1334
+		if ($retrieve_for_today) {
1335
+			$now               = date('Y-m-d', current_time('timestamp'));
1336
+			$where['REG_date'] = array(
1337
+				'BETWEEN',
1338
+				array(
1339
+					EEM_Registration::instance()->convert_datetime_for_query(
1340
+						'REG_date',
1341
+						$now . ' 00:00:00',
1342
+						'Y-m-d H:i:s'
1343
+					),
1344
+					EEM_Registration::instance()->convert_datetime_for_query(
1345
+						'REG_date',
1346
+						$now . ' 23:59:59',
1347
+						'Y-m-d H:i:s'
1348
+					),
1349
+				),
1350
+			);
1351
+		} elseif ($retrieve_for_this_month) {
1352
+			$current_year_and_month = date('Y-m', current_time('timestamp'));
1353
+			$days_this_month        = date('t', current_time('timestamp'));
1354
+			$where['REG_date']      = array(
1355
+				'BETWEEN',
1356
+				array(
1357
+					EEM_Registration::instance()->convert_datetime_for_query(
1358
+						'REG_date',
1359
+						$current_year_and_month . '-01 00:00:00',
1360
+						'Y-m-d H:i:s'
1361
+					),
1362
+					EEM_Registration::instance()->convert_datetime_for_query(
1363
+						'REG_date',
1364
+						$current_year_and_month . '-' . $days_this_month . ' 23:59:59',
1365
+						'Y-m-d H:i:s'
1366
+					),
1367
+				),
1368
+			);
1369
+		} elseif ($month_range) {
1370
+			$pieces          = explode(' ', $month_range, 3);
1371
+			$month_requested = ! empty($pieces[0])
1372
+				? date('m', \EEH_DTT_Helper::first_of_month_timestamp($pieces[0]))
1373
+				: '';
1374
+			$year_requested  = ! empty($pieces[1])
1375
+				? $pieces[1]
1376
+				: '';
1377
+			//if there is not a month or year then we can't go further
1378
+			if ($month_requested && $year_requested) {
1379
+				$days_in_month     = date('t', strtotime($year_requested . '-' . $month_requested . '-' . '01'));
1380
+				$where['REG_date'] = array(
1381
+					'BETWEEN',
1382
+					array(
1383
+						EEM_Registration::instance()->convert_datetime_for_query(
1384
+							'REG_date',
1385
+							$year_requested . '-' . $month_requested . '-01 00:00:00',
1386
+							'Y-m-d H:i:s'
1387
+						),
1388
+						EEM_Registration::instance()->convert_datetime_for_query(
1389
+							'REG_date',
1390
+							$year_requested . '-' . $month_requested . '-' . $days_in_month . ' 23:59:59',
1391
+							'Y-m-d H:i:s'
1392
+						),
1393
+					),
1394
+				);
1395
+			}
1396
+		}
1397
+		return $where;
1398
+	}
1399
+
1400
+
1401
+	/**
1402
+	 * Adds any provided search restraints to the where conditions for the registrations query
1403
+	 *
1404
+	 * @param array $request usually the same as $this->_req_data but not necessarily
1405
+	 * @return array
1406
+	 */
1407
+	protected function _add_search_to_where_conditions(array $request)
1408
+	{
1409
+		$where = array();
1410
+		if (! empty($request['s'])) {
1411
+			$search_string = '%' . sanitize_text_field($request['s']) . '%';
1412
+			$where['OR*search_conditions'] = array(
1413
+				'Event.EVT_name'                          => array('LIKE', $search_string),
1414
+				'Event.EVT_desc'                          => array('LIKE', $search_string),
1415
+				'Event.EVT_short_desc'                    => array('LIKE', $search_string),
1416
+				'Attendee.ATT_full_name'                  => array('LIKE', $search_string),
1417
+				'Attendee.ATT_fname'                      => array('LIKE', $search_string),
1418
+				'Attendee.ATT_lname'                      => array('LIKE', $search_string),
1419
+				'Attendee.ATT_short_bio'                  => array('LIKE', $search_string),
1420
+				'Attendee.ATT_email'                      => array('LIKE', $search_string),
1421
+				'Attendee.ATT_address'                    => array('LIKE', $search_string),
1422
+				'Attendee.ATT_address2'                   => array('LIKE', $search_string),
1423
+				'Attendee.ATT_city'                       => array('LIKE', $search_string),
1424
+				'REG_final_price'                         => array('LIKE', $search_string),
1425
+				'REG_code'                                => array('LIKE', $search_string),
1426
+				'REG_count'                               => array('LIKE', $search_string),
1427
+				'REG_group_size'                          => array('LIKE', $search_string),
1428
+				'Ticket.TKT_name'                         => array('LIKE', $search_string),
1429
+				'Ticket.TKT_description'                  => array('LIKE', $search_string),
1430
+				'Transaction.Payment.PAY_txn_id_chq_nmbr' => array('LIKE', $search_string),
1431
+			);
1432
+		}
1433
+		return $where;
1434
+	}
1435
+
1436
+
1437
+	/**
1438
+	 * Sets up the where conditions for the registrations query.
1439
+	 *
1440
+	 * @param array $request
1441
+	 * @return array
1442
+	 * @throws EE_Error
1443
+	 */
1444
+	protected function _get_where_conditions_for_registrations_query($request)
1445
+	{
1446
+		return apply_filters(
1447
+			'FHEE__Registrations_Admin_Page___get_where_conditions_for_registrations_query',
1448
+			array_merge(
1449
+				$this->addAttendeeIdToWhereConditions($request),
1450
+				$this->_add_event_id_to_where_conditions($request),
1451
+				$this->_add_category_id_to_where_conditions($request),
1452
+				$this->_add_datetime_id_to_where_conditions($request),
1453
+				$this->_add_registration_status_to_where_conditions($request),
1454
+				$this->_add_date_to_where_conditions($request),
1455
+				$this->_add_search_to_where_conditions($request)
1456
+			),
1457
+			$request
1458
+		);
1459
+	}
1460
+
1461
+
1462
+	/**
1463
+	 * Sets up the orderby for the registrations query.
1464
+	 *
1465
+	 * @return array
1466
+	 */
1467
+	protected function _get_orderby_for_registrations_query()
1468
+	{
1469
+		$orderby_field = ! empty($this->_req_data['orderby'])
1470
+			? sanitize_text_field($this->_req_data['orderby'])
1471
+			: '';
1472
+		switch ($orderby_field) {
1473
+			case '_REG_ID':
1474
+				$orderby = array('REG_ID');
1475
+				break;
1476
+			case '_Reg_status':
1477
+				$orderby = array('STS_ID');
1478
+				break;
1479
+			case 'ATT_fname':
1480
+				$orderby = array('Attendee.ATT_fname', 'Attendee.ATT_lname');
1481
+				break;
1482
+			case 'ATT_lname':
1483
+				$orderby = array('Attendee.ATT_lname', 'Attendee.ATT_fname');
1484
+				break;
1485
+			case 'event_name':
1486
+				$orderby = array('Event.EVT_name');
1487
+				break;
1488
+			case 'DTT_EVT_start':
1489
+				$orderby = array('Event.Datetime.DTT_EVT_start');
1490
+				break;
1491
+			default: //'REG_date'
1492
+				$orderby = array('REG_date');
1493
+		}
1494
+
1495
+		//order
1496
+		$order = ! empty($this->_req_data['order'])
1497
+			? sanitize_text_field($this->_req_data['order'])
1498
+			: 'DESC';
1499
+		$orderby = array_combine(
1500
+			$orderby,
1501
+			array_fill(0, count($orderby), $order)
1502
+		);
1503
+		//because there are many registrations with the same date, define
1504
+		//a secondary way to order them, otherwise MySQL seems to be a bit random
1505
+		if (empty($orderby['REG_ID'])) {
1506
+			$orderby['REG_ID'] = $order;
1507
+		}
1508
+		return array('order_by' => $orderby);
1509
+	}
1510
+
1511
+
1512
+	/**
1513
+	 * Sets up the limit for the registrations query.
1514
+	 *
1515
+	 * @param $per_page
1516
+	 * @return array
1517
+	 */
1518
+	protected function _get_limit($per_page)
1519
+	{
1520
+		$current_page = ! empty($this->_req_data['paged'])
1521
+			? absint($this->_req_data['paged'])
1522
+			: 1;
1523
+		$per_page     = ! empty($this->_req_data['perpage'])
1524
+			? $this->_req_data['perpage']
1525
+			: $per_page;
1526
+
1527
+		//-1 means return all results so get out if that's set.
1528
+		if ((int)$per_page === -1) {
1529
+			return array();
1530
+		}
1531
+		$per_page = absint($per_page);
1532
+		$offset   = ($current_page - 1) * $per_page;
1533
+		return array('limit' => array($offset, $per_page));
1534
+	}
1535
+
1536
+
1537
+	public function get_registration_status_array()
1538
+	{
1539
+		return self::$_reg_status;
1540
+	}
1541
+
1542
+
1543
+
1544
+
1545
+	/***************************************        REGISTRATION DETAILS        ***************************************/
1546
+	/**
1547
+	 *        generates HTML for the View Registration Details Admin page
1548
+	 *
1549
+	 * @access protected
1550
+	 * @return void
1551
+	 * @throws DomainException
1552
+	 * @throws EE_Error
1553
+	 * @throws InvalidArgumentException
1554
+	 * @throws InvalidDataTypeException
1555
+	 * @throws InvalidInterfaceException
1556
+	 * @throws EntityNotFoundException
1557
+	 */
1558
+	protected function _registration_details()
1559
+	{
1560
+		$this->_template_args = array();
1561
+		$this->_set_registration_object();
1562
+		if (is_object($this->_registration)) {
1563
+			$transaction                                   = $this->_registration->transaction()
1564
+				? $this->_registration->transaction()
1565
+				: EE_Transaction::new_instance();
1566
+			$this->_session                                = $transaction->session_data();
1567
+			$event_id                                      = $this->_registration->event_ID();
1568
+			$this->_template_args['reg_nmbr']['value']     = $this->_registration->ID();
1569
+			$this->_template_args['reg_nmbr']['label']     = esc_html__('Registration Number', 'event_espresso');
1570
+			$this->_template_args['reg_datetime']['value'] = $this->_registration->get_i18n_datetime('REG_date');
1571
+			$this->_template_args['reg_datetime']['label'] = esc_html__('Date', 'event_espresso');
1572
+			$this->_template_args['grand_total']           = $transaction->total();
1573
+			$this->_template_args['currency_sign']         = EE_Registry::instance()->CFG->currency->sign;
1574
+			// link back to overview
1575
+			$this->_template_args['reg_overview_url']            = REG_ADMIN_URL;
1576
+			$this->_template_args['registration']                = $this->_registration;
1577
+			$this->_template_args['filtered_registrations_link'] = EE_Admin_Page::add_query_args_and_nonce(
1578
+				array(
1579
+					'action'   => 'default',
1580
+					'event_id' => $event_id,
1581
+				),
1582
+				REG_ADMIN_URL
1583
+			);
1584
+			$this->_template_args['filtered_transactions_link']  = EE_Admin_Page::add_query_args_and_nonce(
1585
+				array(
1586
+					'action' => 'default',
1587
+					'EVT_ID' => $event_id,
1588
+					'page'   => 'espresso_transactions',
1589
+				),
1590
+				admin_url('admin.php')
1591
+			);
1592
+			$this->_template_args['event_link']                  = EE_Admin_Page::add_query_args_and_nonce(
1593
+				array(
1594
+					'page'   => 'espresso_events',
1595
+					'action' => 'edit',
1596
+					'post'   => $event_id,
1597
+				),
1598
+				admin_url('admin.php')
1599
+			);
1600
+			//next and previous links
1601
+			$next_reg                                      = $this->_registration->next(
1602
+				null,
1603
+				array(),
1604
+				'REG_ID'
1605
+			);
1606
+			$this->_template_args['next_registration']     = $next_reg
1607
+				? $this->_next_link(
1608
+					EE_Admin_Page::add_query_args_and_nonce(
1609
+						array(
1610
+							'action'  => 'view_registration',
1611
+							'_REG_ID' => $next_reg['REG_ID'],
1612
+						),
1613
+						REG_ADMIN_URL
1614
+					),
1615
+					'dashicons dashicons-arrow-right ee-icon-size-22'
1616
+				)
1617
+				: '';
1618
+			$previous_reg                                  = $this->_registration->previous(
1619
+				null,
1620
+				array(),
1621
+				'REG_ID'
1622
+			);
1623
+			$this->_template_args['previous_registration'] = $previous_reg
1624
+				? $this->_previous_link(
1625
+					EE_Admin_Page::add_query_args_and_nonce(
1626
+						array(
1627
+							'action'  => 'view_registration',
1628
+							'_REG_ID' => $previous_reg['REG_ID'],
1629
+						),
1630
+						REG_ADMIN_URL
1631
+					),
1632
+					'dashicons dashicons-arrow-left ee-icon-size-22'
1633
+				)
1634
+				: '';
1635
+			// grab header
1636
+			$template_path                             = REG_TEMPLATE_PATH . 'reg_admin_details_header.template.php';
1637
+			$this->_template_args['REG_ID']            = $this->_registration->ID();
1638
+			$this->_template_args['admin_page_header'] = EEH_Template::display_template(
1639
+				$template_path,
1640
+				$this->_template_args,
1641
+				true
1642
+			);
1643
+		} else {
1644
+			$this->_template_args['admin_page_header'] = $this->display_espresso_notices();
1645
+		}
1646
+		// the details template wrapper
1647
+		$this->display_admin_page_with_sidebar();
1648
+	}
1649
+
1650
+
1651
+	protected function _registration_details_metaboxes()
1652
+	{
1653
+		do_action('AHEE__Registrations_Admin_Page___registration_details_metabox__start', $this);
1654
+		$this->_set_registration_object();
1655
+		$attendee = $this->_registration instanceof EE_Registration ? $this->_registration->attendee() : null;
1656
+		add_meta_box('edit-reg-status-mbox', esc_html__('Registration Status', 'event_espresso'),
1657
+			array($this, 'set_reg_status_buttons_metabox'), $this->wp_page_slug, 'normal', 'high');
1658
+		add_meta_box('edit-reg-details-mbox', esc_html__('Registration Details', 'event_espresso'),
1659
+			array($this, '_reg_details_meta_box'), $this->wp_page_slug, 'normal', 'high');
1660
+		if ($attendee instanceof EE_Attendee
1661
+			&& EE_Registry::instance()->CAP->current_user_can(
1662
+				'ee_edit_registration',
1663
+				'edit-reg-questions-mbox',
1664
+				$this->_registration->ID()
1665
+			)
1666
+		) {
1667
+			add_meta_box(
1668
+				'edit-reg-questions-mbox',
1669
+				esc_html__('Registration Form Answers', 'event_espresso'),
1670
+				array($this, '_reg_questions_meta_box'),
1671
+				$this->wp_page_slug,
1672
+				'normal',
1673
+				'high'
1674
+			);
1675
+		}
1676
+		add_meta_box(
1677
+			'edit-reg-registrant-mbox',
1678
+			esc_html__('Contact Details', 'event_espresso'),
1679
+			array($this, '_reg_registrant_side_meta_box'),
1680
+			$this->wp_page_slug,
1681
+			'side',
1682
+			'high'
1683
+		);
1684
+		if ($this->_registration->group_size() > 1) {
1685
+			add_meta_box(
1686
+				'edit-reg-attendees-mbox',
1687
+				esc_html__('Other Registrations in this Transaction', 'event_espresso'),
1688
+				array($this, '_reg_attendees_meta_box'),
1689
+				$this->wp_page_slug,
1690
+				'normal',
1691
+				'high'
1692
+			);
1693
+		}
1694
+	}
1695
+
1696
+
1697
+	/**
1698
+	 * set_reg_status_buttons_metabox
1699
+	 *
1700
+	 * @access protected
1701
+	 * @return string
1702
+	 * @throws \EE_Error
1703
+	 */
1704
+	public function set_reg_status_buttons_metabox()
1705
+	{
1706
+		$this->_set_registration_object();
1707
+		$change_reg_status_form = $this->_generate_reg_status_change_form();
1708
+		echo $change_reg_status_form->form_open(
1709
+			self::add_query_args_and_nonce(
1710
+				array(
1711
+					'action' => 'change_reg_status',
1712
+				),
1713
+				REG_ADMIN_URL
1714
+			)
1715
+		);
1716
+		echo $change_reg_status_form->get_html();
1717
+		echo $change_reg_status_form->form_close();
1718
+	}
1719
+
1720
+
1721
+	/**
1722
+	 * @return EE_Form_Section_Proper
1723
+	 * @throws EE_Error
1724
+	 * @throws InvalidArgumentException
1725
+	 * @throws InvalidDataTypeException
1726
+	 * @throws InvalidInterfaceException
1727
+	 * @throws \EventEspresso\core\exceptions\EntityNotFoundException
1728
+	 */
1729
+	protected function _generate_reg_status_change_form()
1730
+	{
1731
+		return new EE_Form_Section_Proper(array(
1732
+			'name'            => 'reg_status_change_form',
1733
+			'html_id'         => 'reg-status-change-form',
1734
+			'layout_strategy' => new EE_Admin_Two_Column_Layout(),
1735
+			'subsections'     => array(
1736
+				'return'             => new EE_Hidden_Input(array(
1737
+					'name'    => 'return',
1738
+					'default' => 'view_registration',
1739
+				)),
1740
+				'REG_ID'             => new EE_Hidden_Input(array(
1741
+					'name'    => 'REG_ID',
1742
+					'default' => $this->_registration->ID(),
1743
+				)),
1744
+				'current_status'     => new EE_Form_Section_HTML(
1745
+					EEH_HTML::tr(
1746
+						EEH_HTML::th(
1747
+							EEH_HTML::label(
1748
+								EEH_HTML::strong(esc_html__('Current Registration Status', 'event_espresso')
1749
+								)
1750
+							)
1751
+						)
1752
+						. EEH_HTML::td(
1753
+							EEH_HTML::strong(
1754
+								$this->_registration->pretty_status(),
1755
+								'',
1756
+								'status-' . $this->_registration->status_ID(),
1757
+								'line-height: 1em; font-size: 1.5em; font-weight: bold;'
1758
+							)
1759
+						)
1760
+					)
1761
+				),
1762
+				'reg_status'         => new EE_Select_Input(
1763
+					$this->_get_reg_statuses(),
1764
+					array(
1765
+						'html_label_text' => esc_html__('Change Registration Status to', 'event_espresso'),
1766
+						'default'         => $this->_registration->status_ID(),
1767
+					)
1768
+				),
1769
+				'send_notifications' => new EE_Yes_No_Input(
1770
+					array(
1771
+						'html_label_text' => esc_html__('Send Related Messages', 'event_espresso'),
1772
+						'default'         => false,
1773
+						'html_help_text'  => esc_html__(
1774
+							'If set to "Yes", then the related messages will be sent to the registrant.',
1775
+							'event_espresso'
1776
+						),
1777
+					)
1778
+				),
1779
+				'submit'             => new EE_Submit_Input(
1780
+					array(
1781
+						'html_class'      => 'button-primary',
1782
+						'html_label_text' => '&nbsp;',
1783
+						'default'         => esc_html__('Update Registration Status', 'event_espresso'),
1784
+					)
1785
+				),
1786
+			),
1787
+		));
1788
+	}
1789
+
1790
+
1791
+	/**
1792
+	 * Returns an array of all the buttons for the various statuses and switch status actions
1793
+	 *
1794
+	 * @return array
1795
+	 * @throws EE_Error
1796
+	 * @throws InvalidArgumentException
1797
+	 * @throws InvalidDataTypeException
1798
+	 * @throws InvalidInterfaceException
1799
+	 * @throws EntityNotFoundException
1800
+	 */
1801
+	protected function _get_reg_statuses()
1802
+	{
1803
+		$reg_status_array = EEM_Registration::instance()->reg_status_array();
1804
+		unset ($reg_status_array[EEM_Registration::status_id_incomplete]);
1805
+		// get current reg status
1806
+		$current_status = $this->_registration->status_ID();
1807
+		// is registration for free event? This will determine whether to display the pending payment option
1808
+		if (
1809
+			$current_status !== EEM_Registration::status_id_pending_payment
1810
+			&& EEH_Money::compare_floats($this->_registration->ticket()->price(), 0.00)
1811
+		) {
1812
+			unset($reg_status_array[EEM_Registration::status_id_pending_payment]);
1813
+		}
1814
+		return EEM_Status::instance()->localized_status($reg_status_array, false, 'sentence');
1815
+	}
1816
+
1817
+
1818
+	/**
1819
+	 * This method is used when using _REG_ID from request which may or may not be an array of reg_ids.
1820
+	 *
1821
+	 * @param bool $status REG status given for changing registrations to.
1822
+	 * @param bool $notify Whether to send messages notifications or not.
1823
+	 * @return array (array with reg_id(s) updated and whether update was successful.
1824
+	 * @throws EE_Error
1825
+	 * @throws InvalidArgumentException
1826
+	 * @throws InvalidDataTypeException
1827
+	 * @throws InvalidInterfaceException
1828
+	 * @throws ReflectionException
1829
+	 * @throws RuntimeException
1830
+	 * @throws EntityNotFoundException
1831
+	 */
1832
+	protected function _set_registration_status_from_request($status = false, $notify = false)
1833
+	{
1834
+		if (isset($this->_req_data['reg_status_change_form'])) {
1835
+			$REG_IDs = isset($this->_req_data['reg_status_change_form']['REG_ID'])
1836
+				? (array)$this->_req_data['reg_status_change_form']['REG_ID']
1837
+				: array();
1838
+		} else {
1839
+			$REG_IDs = isset($this->_req_data['_REG_ID'])
1840
+				? (array)$this->_req_data['_REG_ID']
1841
+				: array();
1842
+		}
1843
+		// sanitize $REG_IDs
1844
+		$REG_IDs = array_map('absint', $REG_IDs);
1845
+		// and remove empty entries
1846
+		$REG_IDs = array_filter($REG_IDs);
1847
+
1848
+		$result = $this->_set_registration_status($REG_IDs, $status, $notify);
1849
+
1850
+		/**
1851
+		 * Set and filter $_req_data['_REG_ID'] for any potential future messages notifications.
1852
+		 * Currently this value is used downstream by the _process_resend_registration method.
1853
+		 *
1854
+		 * @param int|array                $registration_ids The registration ids that have had their status changed successfully.
1855
+		 * @param bool                     $status           The status registrations were changed to.
1856
+		 * @param bool                     $success          If the status was changed successfully for all registrations.
1857
+		 * @param Registrations_Admin_Page $admin_page_object
1858
+		 */
1859
+		$this->_req_data['_REG_ID'] = apply_filters(
1860
+			'FHEE__Registrations_Admin_Page___set_registration_status_from_request__REG_IDs',
1861
+			$result['REG_ID'],
1862
+			$status,
1863
+			$result['success'],
1864
+			$this
1865
+		);
1866
+
1867
+		//notify?
1868
+		if ($notify
1869
+			&& $result['success']
1870
+			&& ! empty($this->_req_data['_REG_ID'])
1871
+			&& EE_Registry::instance()->CAP->current_user_can(
1872
+				'ee_send_message',
1873
+				'espresso_registrations_resend_registration'
1874
+			)
1875
+		) {
1876
+			$this->_process_resend_registration();
1877
+		}
1878
+		return $result;
1879
+	}
1880
+
1881
+
1882
+	/**
1883
+	 * Set the registration status for the given reg_id (which may or may not be an array, it gets typecast to an
1884
+	 * array). Note, this method does NOT take care of possible notifications.  That is required by calling code.
1885
+	 *
1886
+	 * @param array  $REG_IDs
1887
+	 * @param string $status
1888
+	 * @param bool   $notify  Used to indicate whether notification was requested or not.  This determines the context
1889
+	 *                        slug sent with setting the registration status.
1890
+	 * @return array (an array with 'success' key representing whether status change was successful, and 'REG_ID' as
1891
+	 * @throws EE_Error
1892
+	 * @throws InvalidArgumentException
1893
+	 * @throws InvalidDataTypeException
1894
+	 * @throws InvalidInterfaceException
1895
+	 * @throws ReflectionException
1896
+	 * @throws RuntimeException
1897
+	 * @throws EntityNotFoundException
1898
+	 */
1899
+	protected function _set_registration_status($REG_IDs = array(), $status = '', $notify = false)
1900
+	{
1901
+		$success = false;
1902
+		// typecast $REG_IDs
1903
+		$REG_IDs = (array)$REG_IDs;
1904
+		if ( ! empty($REG_IDs)) {
1905
+			$success = true;
1906
+			// set default status if none is passed
1907
+			$status = $status ? $status : EEM_Registration::status_id_pending_payment;
1908
+			$status_context = $notify
1909
+				? Domain::CONTEXT_REGISTRATION_STATUS_CHANGE_REGISTRATION_ADMIN_NOTIFY
1910
+				: Domain::CONTEXT_REGISTRATION_STATUS_CHANGE_REGISTRATION_ADMIN;
1911
+			//loop through REG_ID's and change status
1912
+			foreach ($REG_IDs as $REG_ID) {
1913
+				$registration = EEM_Registration::instance()->get_one_by_ID($REG_ID);
1914
+				if ($registration instanceof EE_Registration) {
1915
+					$registration->set_status(
1916
+						$status,
1917
+						false,
1918
+						new Context(
1919
+							$status_context,
1920
+							esc_html__(
1921
+								'Manually triggered status change on a Registration Admin Page route.',
1922
+								'event_espresso'
1923
+							)
1924
+						)
1925
+					);
1926
+					$result = $registration->save();
1927
+					// verifying explicit fails because update *may* just return 0 for 0 rows affected
1928
+					$success = $result !== false ? $success : false;
1929
+				}
1930
+			}
1931
+		}
1932
+
1933
+		//return $success and processed registrations
1934
+		return array('REG_ID' => $REG_IDs, 'success' => $success);
1935
+	}
1936
+
1937
+
1938
+	/**
1939
+	 * Common logic for setting up success message and redirecting to appropriate route
1940
+	 *
1941
+	 * @param  string $STS_ID status id for the registration changed to
1942
+	 * @param   bool  $notify indicates whether the _set_registration_status_from_request does notifications or not.
1943
+	 * @return void
1944
+	 * @throws EE_Error
1945
+	 */
1946
+	protected function _reg_status_change_return($STS_ID, $notify = false)
1947
+	{
1948
+		$result  = ! empty($STS_ID) ? $this->_set_registration_status_from_request($STS_ID, $notify)
1949
+			: array('success' => false);
1950
+		$success = isset($result['success']) && $result['success'];
1951
+		//setup success message
1952
+		if ($success) {
1953
+			if (is_array($result['REG_ID']) && count($result['REG_ID']) === 1) {
1954
+				$msg = sprintf(esc_html__('Registration status has been set to %s', 'event_espresso'),
1955
+					EEH_Template::pretty_status($STS_ID, false, 'lower'));
1956
+			} else {
1957
+				$msg = sprintf(esc_html__('Registrations have been set to %s.', 'event_espresso'),
1958
+					EEH_Template::pretty_status($STS_ID, false, 'lower'));
1959
+			}
1960
+			EE_Error::add_success($msg);
1961
+		} else {
1962
+			EE_Error::add_error(
1963
+				esc_html__(
1964
+					'Something went wrong, and the status was not changed',
1965
+					'event_espresso'
1966
+				), __FILE__, __LINE__, __FUNCTION__
1967
+			);
1968
+		}
1969
+		if (isset($this->_req_data['return']) && $this->_req_data['return'] == 'view_registration') {
1970
+			$route = array('action' => 'view_registration', '_REG_ID' => reset($result['REG_ID']));
1971
+		} else {
1972
+			$route = array('action' => 'default');
1973
+		}
1974
+		//unset nonces
1975
+		foreach ($this->_req_data as $ref => $value) {
1976
+			if (strpos($ref, 'nonce') !== false) {
1977
+				unset($this->_req_data[$ref]);
1978
+				continue;
1979
+			}
1980
+			$value                 = is_array($value) ? array_map('urlencode', $value) : urlencode($value);
1981
+			$this->_req_data[$ref] = $value;
1982
+		}
1983
+		//merge request vars so that the reloaded list table contains any existing filter query params
1984
+		$route = array_merge($this->_req_data, $route);
1985
+		$this->_redirect_after_action($success, '', '', $route, true);
1986
+	}
1987
+
1988
+
1989
+	/**
1990
+	 * incoming reg status change from reg details page.
1991
+	 *
1992
+	 * @return void
1993
+	 */
1994
+	protected function _change_reg_status()
1995
+	{
1996
+		$this->_req_data['return'] = 'view_registration';
1997
+		//set notify based on whether the send notifications toggle is set or not
1998
+		$notify = ! empty($this->_req_data['reg_status_change_form']['send_notifications']);
1999
+		//$notify = ! empty( $this->_req_data['txn_reg_status_change']['send_notifications'] );
2000
+		$this->_req_data['reg_status_change_form']['reg_status'] = isset($this->_req_data['reg_status_change_form']['reg_status'])
2001
+			? $this->_req_data['reg_status_change_form']['reg_status'] : '';
2002
+		switch ($this->_req_data['reg_status_change_form']['reg_status']) {
2003
+			case EEM_Registration::status_id_approved :
2004
+			case EEH_Template::pretty_status(EEM_Registration::status_id_approved, false, 'sentence') :
2005
+				$this->approve_registration($notify);
2006
+				break;
2007
+			case EEM_Registration::status_id_pending_payment :
2008
+			case EEH_Template::pretty_status(EEM_Registration::status_id_pending_payment, false, 'sentence') :
2009
+				$this->pending_registration($notify);
2010
+				break;
2011
+			case EEM_Registration::status_id_not_approved :
2012
+			case EEH_Template::pretty_status(EEM_Registration::status_id_not_approved, false, 'sentence') :
2013
+				$this->not_approve_registration($notify);
2014
+				break;
2015
+			case EEM_Registration::status_id_declined :
2016
+			case EEH_Template::pretty_status(EEM_Registration::status_id_declined, false, 'sentence') :
2017
+				$this->decline_registration($notify);
2018
+				break;
2019
+			case EEM_Registration::status_id_cancelled :
2020
+			case EEH_Template::pretty_status(EEM_Registration::status_id_cancelled, false, 'sentence') :
2021
+				$this->cancel_registration($notify);
2022
+				break;
2023
+			case EEM_Registration::status_id_wait_list :
2024
+			case EEH_Template::pretty_status(EEM_Registration::status_id_wait_list, false, 'sentence') :
2025
+				$this->wait_list_registration($notify);
2026
+				break;
2027
+			case EEM_Registration::status_id_incomplete :
2028
+			default :
2029
+				$result['success'] = false;
2030
+				unset($this->_req_data['return']);
2031
+				$this->_reg_status_change_return('', false);
2032
+				break;
2033
+		}
2034
+	}
2035
+
2036
+
2037
+	/**
2038
+	 * Callback for bulk action routes.
2039
+	 * Note: although we could just register the singular route callbacks for each bulk action route as well, this
2040
+	 * method was chosen so there is one central place all the registration status bulk actions are going through.
2041
+	 * Potentially, this provides an easier place to locate logic that is specific to these bulk actions (as opposed to
2042
+	 * when an action is happening on just a single registration).
2043
+	 * @param      $action
2044
+	 * @param bool $notify
2045
+	 */
2046
+	protected function bulk_action_on_registrations($action, $notify = false) {
2047
+		do_action(
2048
+			'AHEE__Registrations_Admin_Page__bulk_action_on_registrations__before_execution',
2049
+			$this,
2050
+			$action,
2051
+			$notify
2052
+		);
2053
+		$method = $action . '_registration';
2054
+		if (method_exists($this, $method)) {
2055
+			$this->$method($notify);
2056
+		}
2057
+	}
2058
+
2059
+
2060
+	/**
2061
+	 * approve_registration
2062
+	 *
2063
+	 * @access protected
2064
+	 * @param bool $notify whether or not to notify the registrant about their approval.
2065
+	 * @return void
2066
+	 */
2067
+	protected function approve_registration($notify = false)
2068
+	{
2069
+		$this->_reg_status_change_return(EEM_Registration::status_id_approved, $notify);
2070
+	}
2071
+
2072
+
2073
+	/**
2074
+	 *        decline_registration
2075
+	 *
2076
+	 * @access protected
2077
+	 * @param bool $notify whether or not to notify the registrant about their status change.
2078
+	 * @return void
2079
+	 */
2080
+	protected function decline_registration($notify = false)
2081
+	{
2082
+		$this->_reg_status_change_return(EEM_Registration::status_id_declined, $notify);
2083
+	}
2084
+
2085
+
2086
+	/**
2087
+	 *        cancel_registration
2088
+	 *
2089
+	 * @access protected
2090
+	 * @param bool $notify whether or not to notify the registrant about their status change.
2091
+	 * @return void
2092
+	 */
2093
+	protected function cancel_registration($notify = false)
2094
+	{
2095
+		$this->_reg_status_change_return(EEM_Registration::status_id_cancelled, $notify);
2096
+	}
2097
+
2098
+
2099
+	/**
2100
+	 *        not_approve_registration
2101
+	 *
2102
+	 * @access protected
2103
+	 * @param bool $notify whether or not to notify the registrant about their status change.
2104
+	 * @return void
2105
+	 */
2106
+	protected function not_approve_registration($notify = false)
2107
+	{
2108
+		$this->_reg_status_change_return(EEM_Registration::status_id_not_approved, $notify);
2109
+	}
2110
+
2111
+
2112
+	/**
2113
+	 *        decline_registration
2114
+	 *
2115
+	 * @access protected
2116
+	 * @param bool $notify whether or not to notify the registrant about their status change.
2117
+	 * @return void
2118
+	 */
2119
+	protected function pending_registration($notify = false)
2120
+	{
2121
+		$this->_reg_status_change_return(EEM_Registration::status_id_pending_payment, $notify);
2122
+	}
2123
+
2124
+
2125
+	/**
2126
+	 * waitlist_registration
2127
+	 *
2128
+	 * @access protected
2129
+	 * @param bool $notify whether or not to notify the registrant about their status change.
2130
+	 * @return void
2131
+	 */
2132
+	protected function wait_list_registration($notify = false)
2133
+	{
2134
+		$this->_reg_status_change_return(EEM_Registration::status_id_wait_list, $notify);
2135
+	}
2136
+
2137
+
2138
+	/**
2139
+	 *        generates HTML for the Registration main meta box
2140
+	 *
2141
+	 * @access public
2142
+	 * @return void
2143
+	 * @throws DomainException
2144
+	 * @throws EE_Error
2145
+	 * @throws InvalidArgumentException
2146
+	 * @throws InvalidDataTypeException
2147
+	 * @throws InvalidInterfaceException
2148
+	 * @throws ReflectionException
2149
+	 * @throws EntityNotFoundException
2150
+	 */
2151
+	public function _reg_details_meta_box()
2152
+	{
2153
+		EEH_Autoloader::register_line_item_display_autoloaders();
2154
+		EEH_Autoloader::register_line_item_filter_autoloaders();
2155
+		EE_Registry::instance()->load_helper('Line_Item');
2156
+		$transaction    = $this->_registration->transaction() ? $this->_registration->transaction()
2157
+			: EE_Transaction::new_instance();
2158
+		$this->_session = $transaction->session_data();
2159
+		$filters        = new EE_Line_Item_Filter_Collection();
2160
+		//$filters->add( new EE_Non_Zero_Line_Item_Filter() );
2161
+		$filters->add(new EE_Single_Registration_Line_Item_Filter($this->_registration));
2162
+		$line_item_filter_processor              = new EE_Line_Item_Filter_Processor($filters,
2163
+			$transaction->total_line_item());
2164
+		$filtered_line_item_tree                 = $line_item_filter_processor->process();
2165
+		$line_item_display                       = new EE_Line_Item_Display('reg_admin_table',
2166
+			'EE_Admin_Table_Registration_Line_Item_Display_Strategy');
2167
+		$this->_template_args['line_item_table'] = $line_item_display->display_line_item(
2168
+			$filtered_line_item_tree,
2169
+			array('EE_Registration' => $this->_registration)
2170
+		);
2171
+		$attendee                                = $this->_registration->attendee();
2172
+		if (EE_Registry::instance()->CAP->current_user_can(
2173
+			'ee_read_transaction',
2174
+			'espresso_transactions_view_transaction'
2175
+		)) {
2176
+			$this->_template_args['view_transaction_button'] = EEH_Template::get_button_or_link(
2177
+				EE_Admin_Page::add_query_args_and_nonce(
2178
+					array(
2179
+						'action' => 'view_transaction',
2180
+						'TXN_ID' => $transaction->ID(),
2181
+					),
2182
+					TXN_ADMIN_URL
2183
+				),
2184
+				esc_html__(' View Transaction', 'event_espresso'),
2185
+				'button secondary-button right',
2186
+				'dashicons dashicons-cart'
2187
+			);
2188
+		} else {
2189
+			$this->_template_args['view_transaction_button'] = '';
2190
+		}
2191
+		if ($attendee instanceof EE_Attendee
2192
+			&& EE_Registry::instance()->CAP->current_user_can(
2193
+				'ee_send_message',
2194
+				'espresso_registrations_resend_registration'
2195
+			)
2196
+		) {
2197
+			$this->_template_args['resend_registration_button'] = EEH_Template::get_button_or_link(
2198
+				EE_Admin_Page::add_query_args_and_nonce(
2199
+					array(
2200
+						'action'      => 'resend_registration',
2201
+						'_REG_ID'     => $this->_registration->ID(),
2202
+						'redirect_to' => 'view_registration',
2203
+					),
2204
+					REG_ADMIN_URL
2205
+				),
2206
+				esc_html__(' Resend Registration', 'event_espresso'),
2207
+				'button secondary-button right',
2208
+				'dashicons dashicons-email-alt'
2209
+			);
2210
+		} else {
2211
+			$this->_template_args['resend_registration_button'] = '';
2212
+		}
2213
+		$this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
2214
+		$payment                               = $transaction->get_first_related('Payment');
2215
+		$payment                               = ! $payment instanceof EE_Payment
2216
+			? EE_Payment::new_instance()
2217
+			: $payment;
2218
+		$payment_method                        = $payment->get_first_related('Payment_Method');
2219
+		$payment_method                        = ! $payment_method instanceof EE_Payment_Method
2220
+			? EE_Payment_Method::new_instance()
2221
+			: $payment_method;
2222
+		$reg_details                           = array(
2223
+			'payment_method'       => $payment_method->name(),
2224
+			'response_msg'         => $payment->gateway_response(),
2225
+			'registration_id'      => $this->_registration->get('REG_code'),
2226
+			'registration_session' => $this->_registration->session_ID(),
2227
+			'ip_address'           => isset($this->_session['ip_address']) ? $this->_session['ip_address'] : '',
2228
+			'user_agent'           => isset($this->_session['user_agent']) ? $this->_session['user_agent'] : '',
2229
+		);
2230
+		if (isset($reg_details['registration_id'])) {
2231
+			$this->_template_args['reg_details']['registration_id']['value'] = $reg_details['registration_id'];
2232
+			$this->_template_args['reg_details']['registration_id']['label'] = esc_html__(
2233
+				'Registration ID',
2234
+				'event_espresso'
2235
+			);
2236
+			$this->_template_args['reg_details']['registration_id']['class'] = 'regular-text';
2237
+		}
2238
+		if (isset($reg_details['payment_method'])) {
2239
+			$this->_template_args['reg_details']['payment_method']['value'] = $reg_details['payment_method'];
2240
+			$this->_template_args['reg_details']['payment_method']['label'] = esc_html__(
2241
+				'Most Recent Payment Method',
2242
+				'event_espresso'
2243
+			);
2244
+			$this->_template_args['reg_details']['payment_method']['class'] = 'regular-text';
2245
+			$this->_template_args['reg_details']['response_msg']['value']   = $reg_details['response_msg'];
2246
+			$this->_template_args['reg_details']['response_msg']['label']   = esc_html__(
2247
+				'Payment method response',
2248
+				'event_espresso'
2249
+			);
2250
+			$this->_template_args['reg_details']['response_msg']['class']   = 'regular-text';
2251
+		}
2252
+		$this->_template_args['reg_details']['registration_session']['value'] = $reg_details['registration_session'];
2253
+		$this->_template_args['reg_details']['registration_session']['label'] = esc_html__(
2254
+			'Registration Session',
2255
+			'event_espresso'
2256
+		);
2257
+		$this->_template_args['reg_details']['registration_session']['class'] = 'regular-text';
2258
+		$this->_template_args['reg_details']['ip_address']['value']           = $reg_details['ip_address'];
2259
+		$this->_template_args['reg_details']['ip_address']['label']           = esc_html__(
2260
+			'Registration placed from IP',
2261
+			'event_espresso'
2262
+		);
2263
+		$this->_template_args['reg_details']['ip_address']['class']           = 'regular-text';
2264
+		$this->_template_args['reg_details']['user_agent']['value']           = $reg_details['user_agent'];
2265
+		$this->_template_args['reg_details']['user_agent']['label']           = esc_html__('Registrant User Agent',
2266
+			'event_espresso');
2267
+		$this->_template_args['reg_details']['user_agent']['class']           = 'large-text';
2268
+		$this->_template_args['event_link']                                   = EE_Admin_Page::add_query_args_and_nonce(
2269
+			array(
2270
+				'action'   => 'default',
2271
+				'event_id' => $this->_registration->event_ID(),
2272
+			),
2273
+			REG_ADMIN_URL
2274
+		);
2275
+		$this->_template_args['REG_ID']                                       = $this->_registration->ID();
2276
+		$this->_template_args['event_id']                                     = $this->_registration->event_ID();
2277
+		$template_path                                                        =
2278
+			REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_reg_details.template.php';
2279
+		echo EEH_Template::display_template($template_path, $this->_template_args, true);
2280
+	}
2281
+
2282
+
2283
+	/**
2284
+	 * generates HTML for the Registration Questions meta box.
2285
+	 * If pre-4.8.32.rc.000 hooks are used, uses old methods (with its filters),
2286
+	 * otherwise uses new forms system
2287
+	 *
2288
+	 * @access public
2289
+	 * @return void
2290
+	 * @throws DomainException
2291
+	 * @throws EE_Error
2292
+	 */
2293
+	public function _reg_questions_meta_box()
2294
+	{
2295
+		//allow someone to override this method entirely
2296
+		if (apply_filters('FHEE__Registrations_Admin_Page___reg_questions_meta_box__do_default', true, $this,
2297
+			$this->_registration)) {
2298
+			$form                                              = $this->_get_reg_custom_questions_form(
2299
+				$this->_registration->ID()
2300
+			);
2301
+			$this->_template_args['att_questions']             = count($form->subforms()) > 0
2302
+				? $form->get_html_and_js()
2303
+				: '';
2304
+			$this->_template_args['reg_questions_form_action'] = 'edit_registration';
2305
+			$this->_template_args['REG_ID']                    = $this->_registration->ID();
2306
+			$template_path                                     =
2307
+				REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_reg_questions.template.php';
2308
+			echo EEH_Template::display_template($template_path, $this->_template_args, true);
2309
+		}
2310
+	}
2311
+
2312
+
2313
+	/**
2314
+	 * form_before_question_group
2315
+	 *
2316
+	 * @deprecated    as of 4.8.32.rc.000
2317
+	 * @access        public
2318
+	 * @param        string $output
2319
+	 * @return        string
2320
+	 */
2321
+	public function form_before_question_group($output)
2322
+	{
2323
+		EE_Error::doing_it_wrong(
2324
+			__CLASS__ . '::' . __FUNCTION__,
2325
+			esc_html__(
2326
+				'This method would have been protected but was used on a filter callback so needed to be public. Please discontinue usage as it will be removed soon.',
2327
+				'event_espresso'
2328
+			),
2329
+			'4.8.32.rc.000'
2330
+		);
2331
+		return '
2332 2332
 	<table class="form-table ee-width-100">
2333 2333
 		<tbody>
2334 2334
 			';
2335
-    }
2336
-
2337
-
2338
-    /**
2339
-     * form_after_question_group
2340
-     *
2341
-     * @deprecated    as of 4.8.32.rc.000
2342
-     * @access        public
2343
-     * @param        string $output
2344
-     * @return        string
2345
-     */
2346
-    public function form_after_question_group($output)
2347
-    {
2348
-        EE_Error::doing_it_wrong(
2349
-            __CLASS__ . '::' . __FUNCTION__,
2350
-            esc_html__(
2351
-                'This method would have been protected but was used on a filter callback so needed to be public. Please discontinue usage as it will be removed soon.',
2352
-                'event_espresso'
2353
-            ),
2354
-            '4.8.32.rc.000'
2355
-        );
2356
-        return '
2335
+	}
2336
+
2337
+
2338
+	/**
2339
+	 * form_after_question_group
2340
+	 *
2341
+	 * @deprecated    as of 4.8.32.rc.000
2342
+	 * @access        public
2343
+	 * @param        string $output
2344
+	 * @return        string
2345
+	 */
2346
+	public function form_after_question_group($output)
2347
+	{
2348
+		EE_Error::doing_it_wrong(
2349
+			__CLASS__ . '::' . __FUNCTION__,
2350
+			esc_html__(
2351
+				'This method would have been protected but was used on a filter callback so needed to be public. Please discontinue usage as it will be removed soon.',
2352
+				'event_espresso'
2353
+			),
2354
+			'4.8.32.rc.000'
2355
+		);
2356
+		return '
2357 2357
 			<tr class="hide-if-no-js">
2358 2358
 				<th> </th>
2359 2359
 				<td class="reg-admin-edit-attendee-question-td">
2360 2360
 					<a class="reg-admin-edit-attendee-question-lnk" href="#" title="'
2361
-               . esc_attr__('click to edit question', 'event_espresso')
2362
-               . '">
2361
+			   . esc_attr__('click to edit question', 'event_espresso')
2362
+			   . '">
2363 2363
 						<span class="reg-admin-edit-question-group-spn lt-grey-txt">'
2364
-               . esc_html__('edit the above question group', 'event_espresso')
2365
-               . '</span>
2364
+			   . esc_html__('edit the above question group', 'event_espresso')
2365
+			   . '</span>
2366 2366
 						<div class="dashicons dashicons-edit"></div>
2367 2367
 					</a>
2368 2368
 				</td>
@@ -2370,579 +2370,579 @@  discard block
 block discarded – undo
2370 2370
 		</tbody>
2371 2371
 	</table>
2372 2372
 ';
2373
-    }
2374
-
2375
-
2376
-    /**
2377
-     * form_form_field_label_wrap
2378
-     *
2379
-     * @deprecated    as of 4.8.32.rc.000
2380
-     * @access        public
2381
-     * @param        string $label
2382
-     * @return        string
2383
-     */
2384
-    public function form_form_field_label_wrap($label)
2385
-    {
2386
-        EE_Error::doing_it_wrong(
2387
-            __CLASS__ . '::' . __FUNCTION__,
2388
-            esc_html__(
2389
-                'This method would have been protected but was used on a filter callback so needed to be public. Please discontinue usage as it will be removed soon.',
2390
-                'event_espresso'
2391
-            ),
2392
-            '4.8.32.rc.000'
2393
-        );
2394
-        return '
2373
+	}
2374
+
2375
+
2376
+	/**
2377
+	 * form_form_field_label_wrap
2378
+	 *
2379
+	 * @deprecated    as of 4.8.32.rc.000
2380
+	 * @access        public
2381
+	 * @param        string $label
2382
+	 * @return        string
2383
+	 */
2384
+	public function form_form_field_label_wrap($label)
2385
+	{
2386
+		EE_Error::doing_it_wrong(
2387
+			__CLASS__ . '::' . __FUNCTION__,
2388
+			esc_html__(
2389
+				'This method would have been protected but was used on a filter callback so needed to be public. Please discontinue usage as it will be removed soon.',
2390
+				'event_espresso'
2391
+			),
2392
+			'4.8.32.rc.000'
2393
+		);
2394
+		return '
2395 2395
 			<tr>
2396 2396
 				<th>
2397 2397
 					' . $label . '
2398 2398
 				</th>';
2399
-    }
2400
-
2401
-
2402
-    /**
2403
-     * form_form_field_input__wrap
2404
-     *
2405
-     * @deprecated    as of 4.8.32.rc.000
2406
-     * @access        public
2407
-     * @param        string $input
2408
-     * @return        string
2409
-     */
2410
-    public function form_form_field_input__wrap($input)
2411
-    {
2412
-        EE_Error::doing_it_wrong(
2413
-            __CLASS__ . '::' . __FUNCTION__,
2414
-            esc_html__(
2415
-                'This method would have been protected but was used on a filter callback so needed to be public. Please discontinue usage as it will be removed soon.',
2416
-                'event_espresso'
2417
-            ),
2418
-            '4.8.32.rc.000'
2419
-        );
2420
-        return '
2399
+	}
2400
+
2401
+
2402
+	/**
2403
+	 * form_form_field_input__wrap
2404
+	 *
2405
+	 * @deprecated    as of 4.8.32.rc.000
2406
+	 * @access        public
2407
+	 * @param        string $input
2408
+	 * @return        string
2409
+	 */
2410
+	public function form_form_field_input__wrap($input)
2411
+	{
2412
+		EE_Error::doing_it_wrong(
2413
+			__CLASS__ . '::' . __FUNCTION__,
2414
+			esc_html__(
2415
+				'This method would have been protected but was used on a filter callback so needed to be public. Please discontinue usage as it will be removed soon.',
2416
+				'event_espresso'
2417
+			),
2418
+			'4.8.32.rc.000'
2419
+		);
2420
+		return '
2421 2421
 				<td class="reg-admin-attendee-questions-input-td disabled-input">
2422 2422
 					' . $input . '
2423 2423
 				</td>
2424 2424
 			</tr>';
2425
-    }
2426
-
2427
-
2428
-    /**
2429
-     * Updates the registration's custom questions according to the form info, if the form is submitted.
2430
-     * If it's not a post, the "view_registrations" route will be called next on the SAME request
2431
-     * to display the page
2432
-     *
2433
-     * @access protected
2434
-     * @return void
2435
-     * @throws EE_Error
2436
-     */
2437
-    protected function _update_attendee_registration_form()
2438
-    {
2439
-        do_action('AHEE__Registrations_Admin_Page___update_attendee_registration_form__start', $this);
2440
-        if ($_SERVER['REQUEST_METHOD'] == 'POST') {
2441
-            $REG_ID  = isset($this->_req_data['_REG_ID']) ? absint($this->_req_data['_REG_ID']) : false;
2442
-            $success = $this->_save_reg_custom_questions_form($REG_ID);
2443
-            if ($success) {
2444
-                $what  = esc_html__('Registration Form', 'event_espresso');
2445
-                $route = $REG_ID ? array('action' => 'view_registration', '_REG_ID' => $REG_ID)
2446
-                    : array('action' => 'default');
2447
-                $this->_redirect_after_action($success, $what, esc_html__('updated', 'event_espresso'), $route);
2448
-            }
2449
-        }
2450
-    }
2451
-
2452
-
2453
-    /**
2454
-     * Gets the form for saving registrations custom questions (if done
2455
-     * previously retrieves the cached form object, which may have validation errors in it)
2456
-     *
2457
-     * @param int $REG_ID
2458
-     * @return EE_Registration_Custom_Questions_Form
2459
-     * @throws EE_Error
2460
-     * @throws InvalidArgumentException
2461
-     * @throws InvalidDataTypeException
2462
-     * @throws InvalidInterfaceException
2463
-     */
2464
-    protected function _get_reg_custom_questions_form($REG_ID)
2465
-    {
2466
-        if ( ! $this->_reg_custom_questions_form) {
2467
-            require_once(REG_ADMIN . 'form_sections' . DS . 'EE_Registration_Custom_Questions_Form.form.php');
2468
-            $this->_reg_custom_questions_form = new EE_Registration_Custom_Questions_Form(
2469
-                EEM_Registration::instance()->get_one_by_ID($REG_ID)
2470
-            );
2471
-            $this->_reg_custom_questions_form->_construct_finalize(null, null);
2472
-        }
2473
-        return $this->_reg_custom_questions_form;
2474
-    }
2475
-
2476
-
2477
-    /**
2478
-     * Saves
2479
-     *
2480
-     * @access private
2481
-     * @param bool $REG_ID
2482
-     * @return bool
2483
-     * @throws EE_Error
2484
-     * @throws InvalidArgumentException
2485
-     * @throws InvalidDataTypeException
2486
-     * @throws InvalidInterfaceException
2487
-     */
2488
-    private function _save_reg_custom_questions_form($REG_ID = false)
2489
-    {
2490
-        if ( ! $REG_ID) {
2491
-            EE_Error::add_error(
2492
-                esc_html__(
2493
-                    'An error occurred. No registration ID was received.', 'event_espresso'),
2494
-                __FILE__, __FUNCTION__, __LINE__
2495
-            );
2496
-        }
2497
-        $form = $this->_get_reg_custom_questions_form($REG_ID);
2498
-        $form->receive_form_submission($this->_req_data);
2499
-        $success = false;
2500
-        if ($form->is_valid()) {
2501
-            foreach ($form->subforms() as $question_group_id => $question_group_form) {
2502
-                foreach ($question_group_form->inputs() as $question_id => $input) {
2503
-                    $where_conditions    = array(
2504
-                        'QST_ID' => $question_id,
2505
-                        'REG_ID' => $REG_ID,
2506
-                    );
2507
-                    $possibly_new_values = array(
2508
-                        'ANS_value' => $input->normalized_value(),
2509
-                    );
2510
-                    $answer              = EEM_Answer::instance()->get_one(array($where_conditions));
2511
-                    if ($answer instanceof EE_Answer) {
2512
-                        $success = $answer->save($possibly_new_values);
2513
-                    } else {
2514
-                        //insert it then
2515
-                        $cols_n_vals = array_merge($where_conditions, $possibly_new_values);
2516
-                        $answer      = EE_Answer::new_instance($cols_n_vals);
2517
-                        $success     = $answer->save();
2518
-                    }
2519
-                }
2520
-            }
2521
-        } else {
2522
-            EE_Error::add_error($form->get_validation_error_string(), __FILE__, __FUNCTION__, __LINE__);
2523
-        }
2524
-        return $success;
2525
-    }
2526
-
2527
-
2528
-    /**
2529
-     *        generates HTML for the Registration main meta box
2530
-     *
2531
-     * @access public
2532
-     * @return void
2533
-     * @throws DomainException
2534
-     * @throws EE_Error
2535
-     * @throws InvalidArgumentException
2536
-     * @throws InvalidDataTypeException
2537
-     * @throws InvalidInterfaceException
2538
-     */
2539
-    public function _reg_attendees_meta_box()
2540
-    {
2541
-        $REG = EEM_Registration::instance();
2542
-        //get all other registrations on this transaction, and cache
2543
-        //the attendees for them so we don't have to run another query using force_join
2544
-        $registrations                           = $REG->get_all(array(
2545
-            array(
2546
-                'TXN_ID' => $this->_registration->transaction_ID(),
2547
-                'REG_ID' => array('!=', $this->_registration->ID()),
2548
-            ),
2549
-            'force_join' => array('Attendee'),
2550
-        ));
2551
-        $this->_template_args['attendees']       = array();
2552
-        $this->_template_args['attendee_notice'] = '';
2553
-        if (empty($registrations)
2554
-            || (is_array($registrations)
2555
-                && ! EEH_Array::get_one_item_from_array($registrations))
2556
-        ) {
2557
-            EE_Error::add_error(
2558
-                esc_html__(
2559
-                    'There are no records attached to this registration. Something may have gone wrong with the registration',
2560
-                    'event_espresso'
2561
-                ), __FILE__, __FUNCTION__, __LINE__
2562
-            );
2563
-            $this->_template_args['attendee_notice'] = EE_Error::get_notices();
2564
-        } else {
2565
-            $att_nmbr = 1;
2566
-            foreach ($registrations as $registration) {
2567
-                /* @var $registration EE_Registration */
2568
-                $attendee                                                    = $registration->attendee()
2569
-                    ? $registration->attendee()
2570
-                    : EEM_Attendee::instance()
2571
-                                  ->create_default_object();
2572
-                $this->_template_args['attendees'][$att_nmbr]['STS_ID']      = $registration->status_ID();
2573
-                $this->_template_args['attendees'][$att_nmbr]['fname']       = $attendee->fname();
2574
-                $this->_template_args['attendees'][$att_nmbr]['lname']       = $attendee->lname();
2575
-                $this->_template_args['attendees'][$att_nmbr]['email']       = $attendee->email();
2576
-                $this->_template_args['attendees'][$att_nmbr]['final_price'] = $registration->final_price();
2577
-                $this->_template_args['attendees'][$att_nmbr]['address']     = implode(
2578
-                    ', ',
2579
-                    $attendee->full_address_as_array()
2580
-                );
2581
-                $this->_template_args['attendees'][$att_nmbr]['att_link']    = self::add_query_args_and_nonce(
2582
-                    array(
2583
-                        'action' => 'edit_attendee',
2584
-                        'post'   => $attendee->ID(),
2585
-                    ),
2586
-                    REG_ADMIN_URL
2587
-                );
2588
-                $this->_template_args['attendees'][$att_nmbr]['event_name']  = $registration->event_obj()->name();
2589
-                $att_nmbr++;
2590
-            }
2591
-            $this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
2592
-        }
2593
-        $template_path = REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_attendees.template.php';
2594
-        echo EEH_Template::display_template($template_path, $this->_template_args, true);
2595
-    }
2596
-
2597
-
2598
-    /**
2599
-     *        generates HTML for the Edit Registration side meta box
2600
-     *
2601
-     * @access public
2602
-     * @return void
2603
-     * @throws DomainException
2604
-     * @throws EE_Error
2605
-     * @throws InvalidArgumentException
2606
-     * @throws InvalidDataTypeException
2607
-     * @throws InvalidInterfaceException
2608
-     */
2609
-    public function _reg_registrant_side_meta_box()
2610
-    {
2611
-        /*@var $attendee EE_Attendee */
2612
-        $att_check = $this->_registration->attendee();
2613
-        $attendee  = $att_check instanceof EE_Attendee ? $att_check : EEM_Attendee::instance()->create_default_object();
2614
-        //now let's determine if this is not the primary registration.  If it isn't then we set the
2615
-        //primary_registration object for reference BUT ONLY if the Attendee object loaded is not the same as the
2616
-        //primary registration object (that way we know if we need to show create button or not)
2617
-        if ( ! $this->_registration->is_primary_registrant()) {
2618
-            $primary_registration = $this->_registration->get_primary_registration();
2619
-            $primary_attendee     = $primary_registration instanceof EE_Registration ? $primary_registration->attendee()
2620
-                : null;
2621
-            if ( ! $primary_attendee instanceof EE_Attendee || $attendee->ID() !== $primary_attendee->ID()) {
2622
-                //in here?  This means the displayed registration is not the primary registrant but ALREADY HAS its own
2623
-                //custom attendee object so let's not worry about the primary reg.
2624
-                $primary_registration = null;
2625
-            }
2626
-        } else {
2627
-            $primary_registration = null;
2628
-        }
2629
-        $this->_template_args['ATT_ID']            = $attendee->ID();
2630
-        $this->_template_args['fname']             = $attendee->fname();
2631
-        $this->_template_args['lname']             = $attendee->lname();
2632
-        $this->_template_args['email']             = $attendee->email();
2633
-        $this->_template_args['phone']             = $attendee->phone();
2634
-        $this->_template_args['formatted_address'] = EEH_Address::format($attendee);
2635
-        //edit link
2636
-        $this->_template_args['att_edit_link']  = EE_Admin_Page::add_query_args_and_nonce(array(
2637
-            'action' => 'edit_attendee',
2638
-            'post'   => $attendee->ID(),
2639
-        ), REG_ADMIN_URL);
2640
-        $this->_template_args['att_edit_label'] = esc_html__('View/Edit Contact', 'event_espresso');
2641
-        //create link
2642
-        $this->_template_args['create_link']  = $primary_registration instanceof EE_Registration
2643
-            ? EE_Admin_Page::add_query_args_and_nonce(array(
2644
-                'action'  => 'duplicate_attendee',
2645
-                '_REG_ID' => $this->_registration->ID(),
2646
-            ), REG_ADMIN_URL) : '';
2647
-        $this->_template_args['create_label'] = esc_html__('Create Contact', 'event_espresso');
2648
-        $this->_template_args['att_check']    = $att_check;
2649
-        $template_path                        = REG_TEMPLATE_PATH . 'reg_admin_details_side_meta_box_registrant.template.php';
2650
-        echo EEH_Template::display_template($template_path, $this->_template_args, true);
2651
-    }
2652
-
2653
-
2654
-    /**
2655
-     * trash or restore registrations
2656
-     *
2657
-     * @param  boolean $trash whether to archive or restore
2658
-     * @return void
2659
-     * @throws EE_Error
2660
-     * @throws InvalidArgumentException
2661
-     * @throws InvalidDataTypeException
2662
-     * @throws InvalidInterfaceException
2663
-     * @throws RuntimeException
2664
-     * @access protected
2665
-     */
2666
-    protected function _trash_or_restore_registrations($trash = true)
2667
-    {
2668
-        //if empty _REG_ID then get out because there's nothing to do
2669
-        if (empty($this->_req_data['_REG_ID'])) {
2670
-            EE_Error::add_error(
2671
-                sprintf(
2672
-                    esc_html__(
2673
-                        'In order to %1$s registrations you must select which ones you wish to %1$s by clicking the checkboxes.',
2674
-                        'event_espresso'
2675
-                    ),
2676
-                    $trash ? 'trash' : 'restore'
2677
-                ),
2678
-                __FILE__, __LINE__, __FUNCTION__
2679
-            );
2680
-            $this->_redirect_after_action(false, '', '', array(), true);
2681
-        }
2682
-        $success = 0;
2683
-        $overwrite_msgs = false;
2684
-        //Checkboxes
2685
-        if ( ! is_array($this->_req_data['_REG_ID'])) {
2686
-            $this->_req_data['_REG_ID'] = array($this->_req_data['_REG_ID']);
2687
-        }
2688
-        $reg_count = count($this->_req_data['_REG_ID']);
2689
-        // cycle thru checkboxes
2690
-        foreach ($this->_req_data['_REG_ID'] as $REG_ID) {
2691
-            /** @var EE_Registration $REG */
2692
-            $REG = EEM_Registration::instance()->get_one_by_ID($REG_ID);
2693
-            $payments = $REG->registration_payments();
2694
-            if (! empty($payments)) {
2695
-                $name = $REG->attendee() instanceof EE_Attendee
2696
-                    ? $REG->attendee()->full_name()
2697
-                    : esc_html__('Unknown Attendee', 'event_espresso');
2698
-                $overwrite_msgs = true;
2699
-                EE_Error::add_error(
2700
-                    sprintf(
2701
-                        esc_html__(
2702
-                            'The registration for %s could not be trashed because it has payments attached to the related transaction.  If you wish to trash this registration you must first delete the payments on the related transaction.',
2703
-                            'event_espresso'
2704
-                        ),
2705
-                        $name
2706
-                    ),
2707
-                    __FILE__, __FUNCTION__, __LINE__
2708
-                );
2709
-                //can't trash this registration because it has payments.
2710
-                continue;
2711
-            }
2712
-            $updated = $trash ? $REG->delete() : $REG->restore();
2713
-            if ($updated) {
2714
-                $success++;
2715
-            }
2716
-        }
2717
-        $this->_redirect_after_action(
2718
-            $success === $reg_count, // were ALL registrations affected?
2719
-            $success > 1
2720
-                ? esc_html__('Registrations', 'event_espresso')
2721
-                : esc_html__('Registration', 'event_espresso'),
2722
-            $trash
2723
-                ? esc_html__('moved to the trash', 'event_espresso')
2724
-                : esc_html__('restored', 'event_espresso'),
2725
-            array('action' => 'default'),
2726
-            $overwrite_msgs
2727
-        );
2728
-    }
2729
-
2730
-
2731
-    /**
2732
-     * This is used to permanently delete registrations.  Note, this will handle not only deleting permanently the
2733
-     * registration but also.
2734
-     * 1. Removing relations to EE_Attendee
2735
-     * 2. Deleting permanently the related transaction, but ONLY if all related registrations to the transaction are
2736
-     * ALSO trashed.
2737
-     * 3. Deleting permanently any related Line items but only if the above conditions are met.
2738
-     * 4. Removing relationships between all tickets and the related registrations
2739
-     * 5. Deleting permanently any related Answers (and the answers for other related registrations that were deleted.)
2740
-     * 6. Deleting permanently any related Checkins.
2741
-     *
2742
-     * @return void
2743
-     * @throws EE_Error
2744
-     * @throws InvalidArgumentException
2745
-     * @throws InvalidDataTypeException
2746
-     * @throws InvalidInterfaceException
2747
-     */
2748
-    protected function _delete_registrations()
2749
-    {
2750
-        $REG_MDL = EEM_Registration::instance();
2751
-        $success = 1;
2752
-        //Checkboxes
2753
-        if ( ! empty($this->_req_data['_REG_ID']) && is_array($this->_req_data['_REG_ID'])) {
2754
-            // if array has more than one element than success message should be plural
2755
-            $success = count($this->_req_data['_REG_ID']) > 1 ? 2 : 1;
2756
-            // cycle thru checkboxes
2757
-            while (list($ind, $REG_ID) = each($this->_req_data['_REG_ID'])) {
2758
-                $REG = $REG_MDL->get_one_by_ID($REG_ID);
2759
-                if ( ! $REG instanceof EE_Registration) {
2760
-                    continue;
2761
-                }
2762
-                $deleted = $this->_delete_registration($REG);
2763
-                if ( ! $deleted) {
2764
-                    $success = 0;
2765
-                }
2766
-            }
2767
-        } else {
2768
-            // grab single id and delete
2769
-            $REG_ID  = $this->_req_data['_REG_ID'];
2770
-            $REG     = $REG_MDL->get_one_by_ID($REG_ID);
2771
-            $deleted = $this->_delete_registration($REG);
2772
-            if ( ! $deleted) {
2773
-                $success = 0;
2774
-            }
2775
-        }
2776
-        $what        = $success > 1
2777
-            ? esc_html__('Registrations', 'event_espresso')
2778
-            : esc_html__('Registration', 'event_espresso');
2779
-        $action_desc = esc_html__('permanently deleted.', 'event_espresso');
2780
-        $this->_redirect_after_action(
2781
-            $success,
2782
-            $what,
2783
-            $action_desc,
2784
-            array('action' => 'default'),
2785
-            true
2786
-        );
2787
-    }
2788
-
2789
-
2790
-    /**
2791
-     * handles the permanent deletion of a registration.  See comments with _delete_registrations() for details on what
2792
-     * models get affected.
2793
-     *
2794
-     * @param  EE_Registration $REG registration to be deleted permenantly
2795
-     * @return bool true = successful deletion, false = fail.
2796
-     * @throws EE_Error
2797
-     */
2798
-    protected function _delete_registration(EE_Registration $REG)
2799
-    {
2800
-        //first we start with the transaction... ultimately, we WILL not delete permanently if there are any related
2801
-        //registrations on the transaction that are NOT trashed.
2802
-        $TXN         = $REG->get_first_related('Transaction');
2803
-        $REGS        = $TXN->get_many_related('Registration');
2804
-        $all_trashed = true;
2805
-        foreach ($REGS as $registration) {
2806
-            if ( ! $registration->get('REG_deleted')) {
2807
-                $all_trashed = false;
2808
-            }
2809
-        }
2810
-        if ( ! $all_trashed) {
2811
-            EE_Error::add_error(
2812
-                esc_html__(
2813
-                    'Unable to permanently delete this registration. Before this registration can be permanently deleted, all registrations made in the same transaction must be trashed as well.  These registrations will be permanently deleted in the same action.',
2814
-                    'event_espresso'
2815
-                ),
2816
-                __FILE__, __FUNCTION__, __LINE__
2817
-            );
2818
-            return false;
2819
-        }
2820
-        //k made it here so that means we can delete all the related transactions and their answers (but let's do them
2821
-        //separately from THIS one).
2822
-        foreach ($REGS as $registration) {
2823
-            //delete related answers
2824
-            $registration->delete_related_permanently('Answer');
2825
-            //remove relationship to EE_Attendee (but we ALWAYS leave the contact record intact)
2826
-            $attendee = $registration->get_first_related('Attendee');
2827
-            if ($attendee instanceof EE_Attendee) {
2828
-                $registration->_remove_relation_to($attendee, 'Attendee');
2829
-            }
2830
-            //now remove relationships to tickets on this registration.
2831
-            $registration->_remove_relations('Ticket');
2832
-            //now delete permanently the checkins related to this registration.
2833
-            $registration->delete_related_permanently('Checkin');
2834
-            if ($registration->ID() === $REG->ID()) {
2835
-                continue;
2836
-            } //we don't want to delete permanently the existing registration just yet.
2837
-            //remove relation to transaction for these registrations if NOT the existing registrations
2838
-            $registration->_remove_relations('Transaction');
2839
-            //delete permanently any related messages.
2840
-            $registration->delete_related_permanently('Message');
2841
-            //now delete this registration permanently
2842
-            $registration->delete_permanently();
2843
-        }
2844
-        //now all related registrations on the transaction are handled.  So let's just handle this registration itself
2845
-        // (the transaction and line items should be all that's left).
2846
-        // delete the line items related to the transaction for this registration.
2847
-        $TXN->delete_related_permanently('Line_Item');
2848
-        //we need to remove all the relationships on the transaction
2849
-        $TXN->delete_related_permanently('Payment');
2850
-        $TXN->delete_related_permanently('Extra_Meta');
2851
-        $TXN->delete_related_permanently('Message');
2852
-        //now we can delete this REG permanently (and the transaction of course)
2853
-        $REG->delete_related_permanently('Transaction');
2854
-        return $REG->delete_permanently();
2855
-    }
2856
-
2857
-
2858
-    /**
2859
-     *    generates HTML for the Register New Attendee Admin page
2860
-     *
2861
-     * @access private
2862
-     * @throws DomainException
2863
-     * @throws EE_Error
2864
-     */
2865
-    public function new_registration()
2866
-    {
2867
-        if ( ! $this->_set_reg_event()) {
2868
-            throw new EE_Error(
2869
-                esc_html__(
2870
-                    'Unable to continue with registering because there is no Event ID in the request',
2871
-                    'event_espresso'
2872
-                )
2873
-            );
2874
-        }
2875
-        EE_Registry::instance()->REQ->set_espresso_page(true);
2876
-        // gotta start with a clean slate if we're not coming here via ajax
2877
-        if ( ! defined('DOING_AJAX')
2878
-             && ( ! isset($this->_req_data['processing_registration']) || isset($this->_req_data['step_error']))
2879
-        ) {
2880
-            EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
2881
-        }
2882
-        $this->_template_args['event_name'] = '';
2883
-        // event name
2884
-        if ($this->_reg_event) {
2885
-            $this->_template_args['event_name'] = $this->_reg_event->name();
2886
-            $edit_event_url                     = self::add_query_args_and_nonce(array(
2887
-                'action' => 'edit',
2888
-                'post'   => $this->_reg_event->ID(),
2889
-            ), EVENTS_ADMIN_URL);
2890
-            $edit_event_lnk                     = '<a href="'
2891
-                                                  . $edit_event_url
2892
-                                                  . '" title="'
2893
-                                                  . esc_attr__('Edit ', 'event_espresso')
2894
-                                                  . $this->_reg_event->name()
2895
-                                                  . '">'
2896
-                                                  . esc_html__('Edit Event', 'event_espresso')
2897
-                                                  . '</a>';
2898
-            $this->_template_args['event_name'] .= ' <span class="admin-page-header-edit-lnk not-bold">'
2899
-                                                   . $edit_event_lnk
2900
-                                                   . '</span>';
2901
-        }
2902
-        $this->_template_args['step_content'] = $this->_get_registration_step_content();
2903
-        if (defined('DOING_AJAX')) {
2904
-            $this->_return_json();
2905
-        }
2906
-        // grab header
2907
-        $template_path                              =
2908
-            REG_TEMPLATE_PATH . 'reg_admin_register_new_attendee.template.php';
2909
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template($template_path,
2910
-            $this->_template_args, true);
2911
-        //$this->_set_publish_post_box_vars( NULL, FALSE, FALSE, NULL, FALSE );
2912
-        // the details template wrapper
2913
-        $this->display_admin_page_with_sidebar();
2914
-    }
2915
-
2916
-
2917
-    /**
2918
-     * This returns the content for a registration step
2919
-     *
2920
-     * @access protected
2921
-     * @return string html
2922
-     * @throws DomainException
2923
-     * @throws EE_Error
2924
-     * @throws InvalidArgumentException
2925
-     * @throws InvalidDataTypeException
2926
-     * @throws InvalidInterfaceException
2927
-     */
2928
-    protected function _get_registration_step_content()
2929
-    {
2930
-        if (isset($_COOKIE['ee_registration_added']) && $_COOKIE['ee_registration_added']) {
2931
-            $warning_msg = sprintf(
2932
-                esc_html__(
2933
-                    '%2$sWARNING!!!%3$s%1$sPlease do not use the back button to return to this page for the purpose of adding another registration.%1$sThis can result in lost and/or corrupted data.%1$sIf you wish to add another registration, then please click the%1$s%7$s"Add Another New Registration to Event"%8$s button%1$son the Transaction details page, after you are redirected.%1$s%1$s%4$s redirecting in %5$s seconds %6$s',
2934
-                    'event_espresso'
2935
-                ),
2936
-                '<br />',
2937
-                '<h3 class="important-notice">',
2938
-                '</h3>',
2939
-                '<div class="float-right">',
2940
-                '<span id="redirect_timer" class="important-notice">30</span>',
2941
-                '</div>',
2942
-                '<b>',
2943
-                '</b>'
2944
-            );
2945
-            return '
2425
+	}
2426
+
2427
+
2428
+	/**
2429
+	 * Updates the registration's custom questions according to the form info, if the form is submitted.
2430
+	 * If it's not a post, the "view_registrations" route will be called next on the SAME request
2431
+	 * to display the page
2432
+	 *
2433
+	 * @access protected
2434
+	 * @return void
2435
+	 * @throws EE_Error
2436
+	 */
2437
+	protected function _update_attendee_registration_form()
2438
+	{
2439
+		do_action('AHEE__Registrations_Admin_Page___update_attendee_registration_form__start', $this);
2440
+		if ($_SERVER['REQUEST_METHOD'] == 'POST') {
2441
+			$REG_ID  = isset($this->_req_data['_REG_ID']) ? absint($this->_req_data['_REG_ID']) : false;
2442
+			$success = $this->_save_reg_custom_questions_form($REG_ID);
2443
+			if ($success) {
2444
+				$what  = esc_html__('Registration Form', 'event_espresso');
2445
+				$route = $REG_ID ? array('action' => 'view_registration', '_REG_ID' => $REG_ID)
2446
+					: array('action' => 'default');
2447
+				$this->_redirect_after_action($success, $what, esc_html__('updated', 'event_espresso'), $route);
2448
+			}
2449
+		}
2450
+	}
2451
+
2452
+
2453
+	/**
2454
+	 * Gets the form for saving registrations custom questions (if done
2455
+	 * previously retrieves the cached form object, which may have validation errors in it)
2456
+	 *
2457
+	 * @param int $REG_ID
2458
+	 * @return EE_Registration_Custom_Questions_Form
2459
+	 * @throws EE_Error
2460
+	 * @throws InvalidArgumentException
2461
+	 * @throws InvalidDataTypeException
2462
+	 * @throws InvalidInterfaceException
2463
+	 */
2464
+	protected function _get_reg_custom_questions_form($REG_ID)
2465
+	{
2466
+		if ( ! $this->_reg_custom_questions_form) {
2467
+			require_once(REG_ADMIN . 'form_sections' . DS . 'EE_Registration_Custom_Questions_Form.form.php');
2468
+			$this->_reg_custom_questions_form = new EE_Registration_Custom_Questions_Form(
2469
+				EEM_Registration::instance()->get_one_by_ID($REG_ID)
2470
+			);
2471
+			$this->_reg_custom_questions_form->_construct_finalize(null, null);
2472
+		}
2473
+		return $this->_reg_custom_questions_form;
2474
+	}
2475
+
2476
+
2477
+	/**
2478
+	 * Saves
2479
+	 *
2480
+	 * @access private
2481
+	 * @param bool $REG_ID
2482
+	 * @return bool
2483
+	 * @throws EE_Error
2484
+	 * @throws InvalidArgumentException
2485
+	 * @throws InvalidDataTypeException
2486
+	 * @throws InvalidInterfaceException
2487
+	 */
2488
+	private function _save_reg_custom_questions_form($REG_ID = false)
2489
+	{
2490
+		if ( ! $REG_ID) {
2491
+			EE_Error::add_error(
2492
+				esc_html__(
2493
+					'An error occurred. No registration ID was received.', 'event_espresso'),
2494
+				__FILE__, __FUNCTION__, __LINE__
2495
+			);
2496
+		}
2497
+		$form = $this->_get_reg_custom_questions_form($REG_ID);
2498
+		$form->receive_form_submission($this->_req_data);
2499
+		$success = false;
2500
+		if ($form->is_valid()) {
2501
+			foreach ($form->subforms() as $question_group_id => $question_group_form) {
2502
+				foreach ($question_group_form->inputs() as $question_id => $input) {
2503
+					$where_conditions    = array(
2504
+						'QST_ID' => $question_id,
2505
+						'REG_ID' => $REG_ID,
2506
+					);
2507
+					$possibly_new_values = array(
2508
+						'ANS_value' => $input->normalized_value(),
2509
+					);
2510
+					$answer              = EEM_Answer::instance()->get_one(array($where_conditions));
2511
+					if ($answer instanceof EE_Answer) {
2512
+						$success = $answer->save($possibly_new_values);
2513
+					} else {
2514
+						//insert it then
2515
+						$cols_n_vals = array_merge($where_conditions, $possibly_new_values);
2516
+						$answer      = EE_Answer::new_instance($cols_n_vals);
2517
+						$success     = $answer->save();
2518
+					}
2519
+				}
2520
+			}
2521
+		} else {
2522
+			EE_Error::add_error($form->get_validation_error_string(), __FILE__, __FUNCTION__, __LINE__);
2523
+		}
2524
+		return $success;
2525
+	}
2526
+
2527
+
2528
+	/**
2529
+	 *        generates HTML for the Registration main meta box
2530
+	 *
2531
+	 * @access public
2532
+	 * @return void
2533
+	 * @throws DomainException
2534
+	 * @throws EE_Error
2535
+	 * @throws InvalidArgumentException
2536
+	 * @throws InvalidDataTypeException
2537
+	 * @throws InvalidInterfaceException
2538
+	 */
2539
+	public function _reg_attendees_meta_box()
2540
+	{
2541
+		$REG = EEM_Registration::instance();
2542
+		//get all other registrations on this transaction, and cache
2543
+		//the attendees for them so we don't have to run another query using force_join
2544
+		$registrations                           = $REG->get_all(array(
2545
+			array(
2546
+				'TXN_ID' => $this->_registration->transaction_ID(),
2547
+				'REG_ID' => array('!=', $this->_registration->ID()),
2548
+			),
2549
+			'force_join' => array('Attendee'),
2550
+		));
2551
+		$this->_template_args['attendees']       = array();
2552
+		$this->_template_args['attendee_notice'] = '';
2553
+		if (empty($registrations)
2554
+			|| (is_array($registrations)
2555
+				&& ! EEH_Array::get_one_item_from_array($registrations))
2556
+		) {
2557
+			EE_Error::add_error(
2558
+				esc_html__(
2559
+					'There are no records attached to this registration. Something may have gone wrong with the registration',
2560
+					'event_espresso'
2561
+				), __FILE__, __FUNCTION__, __LINE__
2562
+			);
2563
+			$this->_template_args['attendee_notice'] = EE_Error::get_notices();
2564
+		} else {
2565
+			$att_nmbr = 1;
2566
+			foreach ($registrations as $registration) {
2567
+				/* @var $registration EE_Registration */
2568
+				$attendee                                                    = $registration->attendee()
2569
+					? $registration->attendee()
2570
+					: EEM_Attendee::instance()
2571
+								  ->create_default_object();
2572
+				$this->_template_args['attendees'][$att_nmbr]['STS_ID']      = $registration->status_ID();
2573
+				$this->_template_args['attendees'][$att_nmbr]['fname']       = $attendee->fname();
2574
+				$this->_template_args['attendees'][$att_nmbr]['lname']       = $attendee->lname();
2575
+				$this->_template_args['attendees'][$att_nmbr]['email']       = $attendee->email();
2576
+				$this->_template_args['attendees'][$att_nmbr]['final_price'] = $registration->final_price();
2577
+				$this->_template_args['attendees'][$att_nmbr]['address']     = implode(
2578
+					', ',
2579
+					$attendee->full_address_as_array()
2580
+				);
2581
+				$this->_template_args['attendees'][$att_nmbr]['att_link']    = self::add_query_args_and_nonce(
2582
+					array(
2583
+						'action' => 'edit_attendee',
2584
+						'post'   => $attendee->ID(),
2585
+					),
2586
+					REG_ADMIN_URL
2587
+				);
2588
+				$this->_template_args['attendees'][$att_nmbr]['event_name']  = $registration->event_obj()->name();
2589
+				$att_nmbr++;
2590
+			}
2591
+			$this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
2592
+		}
2593
+		$template_path = REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_attendees.template.php';
2594
+		echo EEH_Template::display_template($template_path, $this->_template_args, true);
2595
+	}
2596
+
2597
+
2598
+	/**
2599
+	 *        generates HTML for the Edit Registration side meta box
2600
+	 *
2601
+	 * @access public
2602
+	 * @return void
2603
+	 * @throws DomainException
2604
+	 * @throws EE_Error
2605
+	 * @throws InvalidArgumentException
2606
+	 * @throws InvalidDataTypeException
2607
+	 * @throws InvalidInterfaceException
2608
+	 */
2609
+	public function _reg_registrant_side_meta_box()
2610
+	{
2611
+		/*@var $attendee EE_Attendee */
2612
+		$att_check = $this->_registration->attendee();
2613
+		$attendee  = $att_check instanceof EE_Attendee ? $att_check : EEM_Attendee::instance()->create_default_object();
2614
+		//now let's determine if this is not the primary registration.  If it isn't then we set the
2615
+		//primary_registration object for reference BUT ONLY if the Attendee object loaded is not the same as the
2616
+		//primary registration object (that way we know if we need to show create button or not)
2617
+		if ( ! $this->_registration->is_primary_registrant()) {
2618
+			$primary_registration = $this->_registration->get_primary_registration();
2619
+			$primary_attendee     = $primary_registration instanceof EE_Registration ? $primary_registration->attendee()
2620
+				: null;
2621
+			if ( ! $primary_attendee instanceof EE_Attendee || $attendee->ID() !== $primary_attendee->ID()) {
2622
+				//in here?  This means the displayed registration is not the primary registrant but ALREADY HAS its own
2623
+				//custom attendee object so let's not worry about the primary reg.
2624
+				$primary_registration = null;
2625
+			}
2626
+		} else {
2627
+			$primary_registration = null;
2628
+		}
2629
+		$this->_template_args['ATT_ID']            = $attendee->ID();
2630
+		$this->_template_args['fname']             = $attendee->fname();
2631
+		$this->_template_args['lname']             = $attendee->lname();
2632
+		$this->_template_args['email']             = $attendee->email();
2633
+		$this->_template_args['phone']             = $attendee->phone();
2634
+		$this->_template_args['formatted_address'] = EEH_Address::format($attendee);
2635
+		//edit link
2636
+		$this->_template_args['att_edit_link']  = EE_Admin_Page::add_query_args_and_nonce(array(
2637
+			'action' => 'edit_attendee',
2638
+			'post'   => $attendee->ID(),
2639
+		), REG_ADMIN_URL);
2640
+		$this->_template_args['att_edit_label'] = esc_html__('View/Edit Contact', 'event_espresso');
2641
+		//create link
2642
+		$this->_template_args['create_link']  = $primary_registration instanceof EE_Registration
2643
+			? EE_Admin_Page::add_query_args_and_nonce(array(
2644
+				'action'  => 'duplicate_attendee',
2645
+				'_REG_ID' => $this->_registration->ID(),
2646
+			), REG_ADMIN_URL) : '';
2647
+		$this->_template_args['create_label'] = esc_html__('Create Contact', 'event_espresso');
2648
+		$this->_template_args['att_check']    = $att_check;
2649
+		$template_path                        = REG_TEMPLATE_PATH . 'reg_admin_details_side_meta_box_registrant.template.php';
2650
+		echo EEH_Template::display_template($template_path, $this->_template_args, true);
2651
+	}
2652
+
2653
+
2654
+	/**
2655
+	 * trash or restore registrations
2656
+	 *
2657
+	 * @param  boolean $trash whether to archive or restore
2658
+	 * @return void
2659
+	 * @throws EE_Error
2660
+	 * @throws InvalidArgumentException
2661
+	 * @throws InvalidDataTypeException
2662
+	 * @throws InvalidInterfaceException
2663
+	 * @throws RuntimeException
2664
+	 * @access protected
2665
+	 */
2666
+	protected function _trash_or_restore_registrations($trash = true)
2667
+	{
2668
+		//if empty _REG_ID then get out because there's nothing to do
2669
+		if (empty($this->_req_data['_REG_ID'])) {
2670
+			EE_Error::add_error(
2671
+				sprintf(
2672
+					esc_html__(
2673
+						'In order to %1$s registrations you must select which ones you wish to %1$s by clicking the checkboxes.',
2674
+						'event_espresso'
2675
+					),
2676
+					$trash ? 'trash' : 'restore'
2677
+				),
2678
+				__FILE__, __LINE__, __FUNCTION__
2679
+			);
2680
+			$this->_redirect_after_action(false, '', '', array(), true);
2681
+		}
2682
+		$success = 0;
2683
+		$overwrite_msgs = false;
2684
+		//Checkboxes
2685
+		if ( ! is_array($this->_req_data['_REG_ID'])) {
2686
+			$this->_req_data['_REG_ID'] = array($this->_req_data['_REG_ID']);
2687
+		}
2688
+		$reg_count = count($this->_req_data['_REG_ID']);
2689
+		// cycle thru checkboxes
2690
+		foreach ($this->_req_data['_REG_ID'] as $REG_ID) {
2691
+			/** @var EE_Registration $REG */
2692
+			$REG = EEM_Registration::instance()->get_one_by_ID($REG_ID);
2693
+			$payments = $REG->registration_payments();
2694
+			if (! empty($payments)) {
2695
+				$name = $REG->attendee() instanceof EE_Attendee
2696
+					? $REG->attendee()->full_name()
2697
+					: esc_html__('Unknown Attendee', 'event_espresso');
2698
+				$overwrite_msgs = true;
2699
+				EE_Error::add_error(
2700
+					sprintf(
2701
+						esc_html__(
2702
+							'The registration for %s could not be trashed because it has payments attached to the related transaction.  If you wish to trash this registration you must first delete the payments on the related transaction.',
2703
+							'event_espresso'
2704
+						),
2705
+						$name
2706
+					),
2707
+					__FILE__, __FUNCTION__, __LINE__
2708
+				);
2709
+				//can't trash this registration because it has payments.
2710
+				continue;
2711
+			}
2712
+			$updated = $trash ? $REG->delete() : $REG->restore();
2713
+			if ($updated) {
2714
+				$success++;
2715
+			}
2716
+		}
2717
+		$this->_redirect_after_action(
2718
+			$success === $reg_count, // were ALL registrations affected?
2719
+			$success > 1
2720
+				? esc_html__('Registrations', 'event_espresso')
2721
+				: esc_html__('Registration', 'event_espresso'),
2722
+			$trash
2723
+				? esc_html__('moved to the trash', 'event_espresso')
2724
+				: esc_html__('restored', 'event_espresso'),
2725
+			array('action' => 'default'),
2726
+			$overwrite_msgs
2727
+		);
2728
+	}
2729
+
2730
+
2731
+	/**
2732
+	 * This is used to permanently delete registrations.  Note, this will handle not only deleting permanently the
2733
+	 * registration but also.
2734
+	 * 1. Removing relations to EE_Attendee
2735
+	 * 2. Deleting permanently the related transaction, but ONLY if all related registrations to the transaction are
2736
+	 * ALSO trashed.
2737
+	 * 3. Deleting permanently any related Line items but only if the above conditions are met.
2738
+	 * 4. Removing relationships between all tickets and the related registrations
2739
+	 * 5. Deleting permanently any related Answers (and the answers for other related registrations that were deleted.)
2740
+	 * 6. Deleting permanently any related Checkins.
2741
+	 *
2742
+	 * @return void
2743
+	 * @throws EE_Error
2744
+	 * @throws InvalidArgumentException
2745
+	 * @throws InvalidDataTypeException
2746
+	 * @throws InvalidInterfaceException
2747
+	 */
2748
+	protected function _delete_registrations()
2749
+	{
2750
+		$REG_MDL = EEM_Registration::instance();
2751
+		$success = 1;
2752
+		//Checkboxes
2753
+		if ( ! empty($this->_req_data['_REG_ID']) && is_array($this->_req_data['_REG_ID'])) {
2754
+			// if array has more than one element than success message should be plural
2755
+			$success = count($this->_req_data['_REG_ID']) > 1 ? 2 : 1;
2756
+			// cycle thru checkboxes
2757
+			while (list($ind, $REG_ID) = each($this->_req_data['_REG_ID'])) {
2758
+				$REG = $REG_MDL->get_one_by_ID($REG_ID);
2759
+				if ( ! $REG instanceof EE_Registration) {
2760
+					continue;
2761
+				}
2762
+				$deleted = $this->_delete_registration($REG);
2763
+				if ( ! $deleted) {
2764
+					$success = 0;
2765
+				}
2766
+			}
2767
+		} else {
2768
+			// grab single id and delete
2769
+			$REG_ID  = $this->_req_data['_REG_ID'];
2770
+			$REG     = $REG_MDL->get_one_by_ID($REG_ID);
2771
+			$deleted = $this->_delete_registration($REG);
2772
+			if ( ! $deleted) {
2773
+				$success = 0;
2774
+			}
2775
+		}
2776
+		$what        = $success > 1
2777
+			? esc_html__('Registrations', 'event_espresso')
2778
+			: esc_html__('Registration', 'event_espresso');
2779
+		$action_desc = esc_html__('permanently deleted.', 'event_espresso');
2780
+		$this->_redirect_after_action(
2781
+			$success,
2782
+			$what,
2783
+			$action_desc,
2784
+			array('action' => 'default'),
2785
+			true
2786
+		);
2787
+	}
2788
+
2789
+
2790
+	/**
2791
+	 * handles the permanent deletion of a registration.  See comments with _delete_registrations() for details on what
2792
+	 * models get affected.
2793
+	 *
2794
+	 * @param  EE_Registration $REG registration to be deleted permenantly
2795
+	 * @return bool true = successful deletion, false = fail.
2796
+	 * @throws EE_Error
2797
+	 */
2798
+	protected function _delete_registration(EE_Registration $REG)
2799
+	{
2800
+		//first we start with the transaction... ultimately, we WILL not delete permanently if there are any related
2801
+		//registrations on the transaction that are NOT trashed.
2802
+		$TXN         = $REG->get_first_related('Transaction');
2803
+		$REGS        = $TXN->get_many_related('Registration');
2804
+		$all_trashed = true;
2805
+		foreach ($REGS as $registration) {
2806
+			if ( ! $registration->get('REG_deleted')) {
2807
+				$all_trashed = false;
2808
+			}
2809
+		}
2810
+		if ( ! $all_trashed) {
2811
+			EE_Error::add_error(
2812
+				esc_html__(
2813
+					'Unable to permanently delete this registration. Before this registration can be permanently deleted, all registrations made in the same transaction must be trashed as well.  These registrations will be permanently deleted in the same action.',
2814
+					'event_espresso'
2815
+				),
2816
+				__FILE__, __FUNCTION__, __LINE__
2817
+			);
2818
+			return false;
2819
+		}
2820
+		//k made it here so that means we can delete all the related transactions and their answers (but let's do them
2821
+		//separately from THIS one).
2822
+		foreach ($REGS as $registration) {
2823
+			//delete related answers
2824
+			$registration->delete_related_permanently('Answer');
2825
+			//remove relationship to EE_Attendee (but we ALWAYS leave the contact record intact)
2826
+			$attendee = $registration->get_first_related('Attendee');
2827
+			if ($attendee instanceof EE_Attendee) {
2828
+				$registration->_remove_relation_to($attendee, 'Attendee');
2829
+			}
2830
+			//now remove relationships to tickets on this registration.
2831
+			$registration->_remove_relations('Ticket');
2832
+			//now delete permanently the checkins related to this registration.
2833
+			$registration->delete_related_permanently('Checkin');
2834
+			if ($registration->ID() === $REG->ID()) {
2835
+				continue;
2836
+			} //we don't want to delete permanently the existing registration just yet.
2837
+			//remove relation to transaction for these registrations if NOT the existing registrations
2838
+			$registration->_remove_relations('Transaction');
2839
+			//delete permanently any related messages.
2840
+			$registration->delete_related_permanently('Message');
2841
+			//now delete this registration permanently
2842
+			$registration->delete_permanently();
2843
+		}
2844
+		//now all related registrations on the transaction are handled.  So let's just handle this registration itself
2845
+		// (the transaction and line items should be all that's left).
2846
+		// delete the line items related to the transaction for this registration.
2847
+		$TXN->delete_related_permanently('Line_Item');
2848
+		//we need to remove all the relationships on the transaction
2849
+		$TXN->delete_related_permanently('Payment');
2850
+		$TXN->delete_related_permanently('Extra_Meta');
2851
+		$TXN->delete_related_permanently('Message');
2852
+		//now we can delete this REG permanently (and the transaction of course)
2853
+		$REG->delete_related_permanently('Transaction');
2854
+		return $REG->delete_permanently();
2855
+	}
2856
+
2857
+
2858
+	/**
2859
+	 *    generates HTML for the Register New Attendee Admin page
2860
+	 *
2861
+	 * @access private
2862
+	 * @throws DomainException
2863
+	 * @throws EE_Error
2864
+	 */
2865
+	public function new_registration()
2866
+	{
2867
+		if ( ! $this->_set_reg_event()) {
2868
+			throw new EE_Error(
2869
+				esc_html__(
2870
+					'Unable to continue with registering because there is no Event ID in the request',
2871
+					'event_espresso'
2872
+				)
2873
+			);
2874
+		}
2875
+		EE_Registry::instance()->REQ->set_espresso_page(true);
2876
+		// gotta start with a clean slate if we're not coming here via ajax
2877
+		if ( ! defined('DOING_AJAX')
2878
+			 && ( ! isset($this->_req_data['processing_registration']) || isset($this->_req_data['step_error']))
2879
+		) {
2880
+			EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
2881
+		}
2882
+		$this->_template_args['event_name'] = '';
2883
+		// event name
2884
+		if ($this->_reg_event) {
2885
+			$this->_template_args['event_name'] = $this->_reg_event->name();
2886
+			$edit_event_url                     = self::add_query_args_and_nonce(array(
2887
+				'action' => 'edit',
2888
+				'post'   => $this->_reg_event->ID(),
2889
+			), EVENTS_ADMIN_URL);
2890
+			$edit_event_lnk                     = '<a href="'
2891
+												  . $edit_event_url
2892
+												  . '" title="'
2893
+												  . esc_attr__('Edit ', 'event_espresso')
2894
+												  . $this->_reg_event->name()
2895
+												  . '">'
2896
+												  . esc_html__('Edit Event', 'event_espresso')
2897
+												  . '</a>';
2898
+			$this->_template_args['event_name'] .= ' <span class="admin-page-header-edit-lnk not-bold">'
2899
+												   . $edit_event_lnk
2900
+												   . '</span>';
2901
+		}
2902
+		$this->_template_args['step_content'] = $this->_get_registration_step_content();
2903
+		if (defined('DOING_AJAX')) {
2904
+			$this->_return_json();
2905
+		}
2906
+		// grab header
2907
+		$template_path                              =
2908
+			REG_TEMPLATE_PATH . 'reg_admin_register_new_attendee.template.php';
2909
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template($template_path,
2910
+			$this->_template_args, true);
2911
+		//$this->_set_publish_post_box_vars( NULL, FALSE, FALSE, NULL, FALSE );
2912
+		// the details template wrapper
2913
+		$this->display_admin_page_with_sidebar();
2914
+	}
2915
+
2916
+
2917
+	/**
2918
+	 * This returns the content for a registration step
2919
+	 *
2920
+	 * @access protected
2921
+	 * @return string html
2922
+	 * @throws DomainException
2923
+	 * @throws EE_Error
2924
+	 * @throws InvalidArgumentException
2925
+	 * @throws InvalidDataTypeException
2926
+	 * @throws InvalidInterfaceException
2927
+	 */
2928
+	protected function _get_registration_step_content()
2929
+	{
2930
+		if (isset($_COOKIE['ee_registration_added']) && $_COOKIE['ee_registration_added']) {
2931
+			$warning_msg = sprintf(
2932
+				esc_html__(
2933
+					'%2$sWARNING!!!%3$s%1$sPlease do not use the back button to return to this page for the purpose of adding another registration.%1$sThis can result in lost and/or corrupted data.%1$sIf you wish to add another registration, then please click the%1$s%7$s"Add Another New Registration to Event"%8$s button%1$son the Transaction details page, after you are redirected.%1$s%1$s%4$s redirecting in %5$s seconds %6$s',
2934
+					'event_espresso'
2935
+				),
2936
+				'<br />',
2937
+				'<h3 class="important-notice">',
2938
+				'</h3>',
2939
+				'<div class="float-right">',
2940
+				'<span id="redirect_timer" class="important-notice">30</span>',
2941
+				'</div>',
2942
+				'<b>',
2943
+				'</b>'
2944
+			);
2945
+			return '
2946 2946
 	<div id="ee-add-reg-back-button-dv"><p>' . $warning_msg . '</p></div>
2947 2947
 	<script >
2948 2948
 		// WHOAH !!! it appears that someone is using the back button from the Transaction admin page
@@ -2955,841 +2955,841 @@  discard block
 block discarded – undo
2955 2955
 	        }
2956 2956
 	    }, 800 );
2957 2957
 	</script >';
2958
-        }
2959
-        $template_args = array(
2960
-            'title'                    => '',
2961
-            'content'                  => '',
2962
-            'step_button_text'         => '',
2963
-            'show_notification_toggle' => false,
2964
-        );
2965
-        //to indicate we're processing a new registration
2966
-        $hidden_fields = array(
2967
-            'processing_registration' => array(
2968
-                'type'  => 'hidden',
2969
-                'value' => 0,
2970
-            ),
2971
-            'event_id'                => array(
2972
-                'type'  => 'hidden',
2973
-                'value' => $this->_reg_event->ID(),
2974
-            ),
2975
-        );
2976
-        //if the cart is empty then we know we're at step one so we'll display ticket selector
2977
-        $cart = EE_Registry::instance()->SSN->cart();
2978
-        $step = ! $cart instanceof EE_Cart ? 'ticket' : 'questions';
2979
-        switch ($step) {
2980
-            case 'ticket' :
2981
-                $hidden_fields['processing_registration']['value'] = 1;
2982
-                $template_args['title']                            = esc_html__(
2983
-                    'Step One: Select the Ticket for this registration',
2984
-                    'event_espresso'
2985
-                );
2986
-                $template_args['content']                          =
2987
-                    EED_Ticket_Selector::instance()->display_ticket_selector($this->_reg_event);
2988
-                $template_args['step_button_text']                 = esc_html__(
2989
-                    'Add Tickets and Continue to Registrant Details',
2990
-                    'event_espresso'
2991
-                );
2992
-                $template_args['show_notification_toggle']         = false;
2993
-                break;
2994
-            case 'questions' :
2995
-                $hidden_fields['processing_registration']['value'] = 2;
2996
-                $template_args['title']                            = esc_html__(
2997
-                    'Step Two: Add Registrant Details for this Registration',
2998
-                    'event_espresso'
2999
-                );
3000
-                //in theory we should be able to run EED_SPCO at this point because the cart should have been setup
3001
-                // properly by the first process_reg_step run.
3002
-                $template_args['content']                  =
3003
-                    EED_Single_Page_Checkout::registration_checkout_for_admin();
3004
-                $template_args['step_button_text']         = esc_html__(
3005
-                    'Save Registration and Continue to Details',
3006
-                    'event_espresso'
3007
-                );
3008
-                $template_args['show_notification_toggle'] = true;
3009
-                break;
3010
-        }
3011
-        //we come back to the process_registration_step route.
3012
-        $this->_set_add_edit_form_tags('process_reg_step', $hidden_fields);
3013
-        return EEH_Template::display_template(
3014
-            REG_TEMPLATE_PATH . 'reg_admin_register_new_attendee_step_content.template.php',
3015
-            $template_args,
3016
-            true
3017
-        );
3018
-    }
3019
-
3020
-
3021
-    /**
3022
-     *        set_reg_event
3023
-     *
3024
-     * @access private
3025
-     * @return bool
3026
-     * @throws EE_Error
3027
-     * @throws InvalidArgumentException
3028
-     * @throws InvalidDataTypeException
3029
-     * @throws InvalidInterfaceException
3030
-     */
3031
-    private function _set_reg_event()
3032
-    {
3033
-        if (is_object($this->_reg_event)) {
3034
-            return true;
3035
-        }
3036
-        $EVT_ID = (! empty($this->_req_data['event_id'])) ? absint($this->_req_data['event_id']) : false;
3037
-        if ( ! $EVT_ID) {
3038
-            return false;
3039
-        }
3040
-        $this->_reg_event = EEM_Event::instance()->get_one_by_ID($EVT_ID);
3041
-        return true;
3042
-    }
3043
-
3044
-
3045
-    /**
3046
-     * process_reg_step
3047
-     *
3048
-     * @access        public
3049
-     * @return string
3050
-     * @throws DomainException
3051
-     * @throws EE_Error
3052
-     * @throws InvalidArgumentException
3053
-     * @throws InvalidDataTypeException
3054
-     * @throws InvalidInterfaceException
3055
-     * @throws ReflectionException
3056
-     * @throws RuntimeException
3057
-     */
3058
-    public function process_reg_step()
3059
-    {
3060
-        EE_System::do_not_cache();
3061
-        $this->_set_reg_event();
3062
-        EE_Registry::instance()->REQ->set_espresso_page(true);
3063
-        EE_Registry::instance()->REQ->set('uts', time());
3064
-        //what step are we on?
3065
-        $cart = EE_Registry::instance()->SSN->cart();
3066
-        $step = ! $cart instanceof EE_Cart ? 'ticket' : 'questions';
3067
-        //if doing ajax then we need to verify the nonce
3068
-        if (defined('DOING_AJAX')) {
3069
-            $nonce = isset($this->_req_data[$this->_req_nonce])
3070
-                ? sanitize_text_field($this->_req_data[$this->_req_nonce]) : '';
3071
-            $this->_verify_nonce($nonce, $this->_req_nonce);
3072
-        }
3073
-        switch ($step) {
3074
-            case 'ticket' :
3075
-                //process ticket selection
3076
-                $success = EED_Ticket_Selector::instance()->process_ticket_selections();
3077
-                if ($success) {
3078
-                    EE_Error::add_success(
3079
-                        esc_html__(
3080
-                            'Tickets Selected. Now complete the registration.',
3081
-                            'event_espresso'
3082
-                        )
3083
-                    );
3084
-                } else {
3085
-                    $query_args['step_error'] = $this->_req_data['step_error'] = true;
3086
-                }
3087
-                if (defined('DOING_AJAX')) {
3088
-                    $this->new_registration(); //display next step
3089
-                } else {
3090
-                    $query_args = array(
3091
-                        'action'                  => 'new_registration',
3092
-                        'processing_registration' => 1,
3093
-                        'event_id'                => $this->_reg_event->ID(),
3094
-                        'uts'                     => time(),
3095
-                    );
3096
-                    $this->_redirect_after_action(
3097
-                        false,
3098
-                        '',
3099
-                        '',
3100
-                        $query_args,
3101
-                        true
3102
-                    );
3103
-                }
3104
-                break;
3105
-            case 'questions' :
3106
-                if (! isset(
3107
-                    $this->_req_data['txn_reg_status_change'],
3108
-                    $this->_req_data['txn_reg_status_change']['send_notifications'])
3109
-                ) {
3110
-                    add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_false', 15);
3111
-                }
3112
-                //process registration
3113
-                $transaction = EED_Single_Page_Checkout::instance()->process_registration_from_admin();
3114
-                if ($cart instanceof EE_Cart) {
3115
-                    $grand_total = $cart->get_cart_grand_total();
3116
-                    if ($grand_total instanceof EE_Line_Item) {
3117
-                        $grand_total->save_this_and_descendants_to_txn();
3118
-                    }
3119
-                }
3120
-                if ( ! $transaction instanceof EE_Transaction) {
3121
-                    $query_args = array(
3122
-                        'action'                  => 'new_registration',
3123
-                        'processing_registration' => 2,
3124
-                        'event_id'                => $this->_reg_event->ID(),
3125
-                        'uts'                     => time(),
3126
-                    );
3127
-                    if (defined('DOING_AJAX')) {
3128
-                        //display registration form again because there are errors (maybe validation?)
3129
-                        $this->new_registration();
3130
-                        return;
3131
-                    } else {
3132
-                        $this->_redirect_after_action(
3133
-                            false,
3134
-                            '',
3135
-                            '',
3136
-                            $query_args,
3137
-                            true
3138
-                        );
3139
-                        return;
3140
-                    }
3141
-                }
3142
-                // maybe update status, and make sure to save transaction if not done already
3143
-                if ( ! $transaction->update_status_based_on_total_paid()) {
3144
-                    $transaction->save();
3145
-                }
3146
-                EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
3147
-                $this->_req_data = array();
3148
-                $query_args      = array(
3149
-                    'action'        => 'redirect_to_txn',
3150
-                    'TXN_ID'        => $transaction->ID(),
3151
-                    'EVT_ID'        => $this->_reg_event->ID(),
3152
-                    'event_name'    => urlencode($this->_reg_event->name()),
3153
-                    'redirect_from' => 'new_registration',
3154
-                );
3155
-                $this->_redirect_after_action(false, '', '', $query_args, true);
3156
-                break;
3157
-        }
3158
-        //what are you looking here for?  Should be nothing to do at this point.
3159
-    }
3160
-
3161
-
3162
-    /**
3163
-     * redirect_to_txn
3164
-     *
3165
-     * @access public
3166
-     * @return void
3167
-     * @throws EE_Error
3168
-     * @throws InvalidArgumentException
3169
-     * @throws InvalidDataTypeException
3170
-     * @throws InvalidInterfaceException
3171
-     */
3172
-    public function redirect_to_txn()
3173
-    {
3174
-        EE_System::do_not_cache();
3175
-        EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
3176
-        $query_args = array(
3177
-            'action' => 'view_transaction',
3178
-            'TXN_ID' => isset($this->_req_data['TXN_ID']) ? absint($this->_req_data['TXN_ID']) : 0,
3179
-            'page'   => 'espresso_transactions',
3180
-        );
3181
-        if (isset($this->_req_data['EVT_ID'], $this->_req_data['redirect_from'])) {
3182
-            $query_args['EVT_ID']        = $this->_req_data['EVT_ID'];
3183
-            $query_args['event_name']    = urlencode($this->_req_data['event_name']);
3184
-            $query_args['redirect_from'] = $this->_req_data['redirect_from'];
3185
-        }
3186
-        EE_Error::add_success(
3187
-            esc_html__(
3188
-                'Registration Created.  Please review the transaction and add any payments as necessary',
3189
-                'event_espresso'
3190
-            )
3191
-        );
3192
-        $this->_redirect_after_action(false, '', '', $query_args, true);
3193
-    }
3194
-
3195
-
3196
-    /**
3197
-     *        generates HTML for the Attendee Contact List
3198
-     *
3199
-     * @access protected
3200
-     * @return void
3201
-     */
3202
-    protected function _attendee_contact_list_table()
3203
-    {
3204
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3205
-        $this->_search_btn_label = esc_html__('Contacts', 'event_espresso');
3206
-        $this->display_admin_list_table_page_with_no_sidebar();
3207
-    }
3208
-
3209
-
3210
-    /**
3211
-     *        get_attendees
3212
-     *
3213
-     * @param      $per_page
3214
-     * @param bool $count whether to return count or data.
3215
-     * @param bool $trash
3216
-     * @return array
3217
-     * @throws EE_Error
3218
-     * @throws InvalidArgumentException
3219
-     * @throws InvalidDataTypeException
3220
-     * @throws InvalidInterfaceException
3221
-     * @access public
3222
-     */
3223
-    public function get_attendees($per_page, $count = false, $trash = false)
3224
-    {
3225
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3226
-        require_once(REG_ADMIN . 'EE_Attendee_Contact_List_Table.class.php');
3227
-        $ATT_MDL                    = EEM_Attendee::instance();
3228
-        $this->_req_data['orderby'] = ! empty($this->_req_data['orderby']) ? $this->_req_data['orderby'] : '';
3229
-        switch ($this->_req_data['orderby']) {
3230
-            case 'ATT_ID':
3231
-                $orderby = 'ATT_ID';
3232
-                break;
3233
-            case 'ATT_fname':
3234
-                $orderby = 'ATT_fname';
3235
-                break;
3236
-            case 'ATT_email':
3237
-                $orderby = 'ATT_email';
3238
-                break;
3239
-            case 'ATT_city':
3240
-                $orderby = 'ATT_city';
3241
-                break;
3242
-            case 'STA_ID':
3243
-                $orderby = 'STA_ID';
3244
-                break;
3245
-            case 'CNT_ID':
3246
-                $orderby = 'CNT_ID';
3247
-                break;
3248
-            case 'Registration_Count':
3249
-                $orderby = 'Registration_Count';
3250
-                break;
3251
-            default:
3252
-                $orderby = 'ATT_lname';
3253
-        }
3254
-        $sort         = (isset($this->_req_data['order']) && ! empty($this->_req_data['order']))
3255
-            ? $this->_req_data['order']
3256
-            : 'ASC';
3257
-        $current_page = isset($this->_req_data['paged']) && ! empty($this->_req_data['paged'])
3258
-            ? $this->_req_data['paged']
3259
-            : 1;
3260
-        $per_page     = isset($per_page) && ! empty($per_page) ? $per_page : 10;
3261
-        $per_page     = isset($this->_req_data['perpage']) && ! empty($this->_req_data['perpage'])
3262
-            ? $this->_req_data['perpage']
3263
-            : $per_page;
3264
-        $_where       = array();
3265
-        if ( ! empty($this->_req_data['s'])) {
3266
-            $sstr         = '%' . $this->_req_data['s'] . '%';
3267
-            $_where['OR'] = array(
3268
-                'Registration.Event.EVT_name'       => array('LIKE', $sstr),
3269
-                'Registration.Event.EVT_desc'       => array('LIKE', $sstr),
3270
-                'Registration.Event.EVT_short_desc' => array('LIKE', $sstr),
3271
-                'ATT_fname'                         => array('LIKE', $sstr),
3272
-                'ATT_lname'                         => array('LIKE', $sstr),
3273
-                'ATT_short_bio'                     => array('LIKE', $sstr),
3274
-                'ATT_email'                         => array('LIKE', $sstr),
3275
-                'ATT_address'                       => array('LIKE', $sstr),
3276
-                'ATT_address2'                      => array('LIKE', $sstr),
3277
-                'ATT_city'                          => array('LIKE', $sstr),
3278
-                'Country.CNT_name'                  => array('LIKE', $sstr),
3279
-                'State.STA_name'                    => array('LIKE', $sstr),
3280
-                'ATT_phone'                         => array('LIKE', $sstr),
3281
-                'Registration.REG_final_price'      => array('LIKE', $sstr),
3282
-                'Registration.REG_code'             => array('LIKE', $sstr),
3283
-                'Registration.REG_group_size'       => array('LIKE', $sstr),
3284
-            );
3285
-        }
3286
-        $offset = ($current_page - 1) * $per_page;
3287
-        $limit  = $count ? null : array($offset, $per_page);
3288
-        $query_args = array(
3289
-            $_where,
3290
-            'extra_selects' => array('Registration_Count' => array('Registration.REG_ID', 'count', '%d')),
3291
-            'limit' => $limit
3292
-        );
3293
-        if (! $count) {
3294
-            $query_args['order_by'] = array($orderby => $sort);
3295
-        }
3296
-        if ($trash) {
3297
-            $query_args[0]['status'] = array('!=', 'publish');
3298
-            $all_attendees    = $count
3299
-                ? $ATT_MDL->count($query_args, 'ATT_ID', true)
3300
-                : $ATT_MDL->get_all($query_args);
3301
-        } else {
3302
-            $query_args[0]['status'] = array('IN', array('publish'));
3303
-            $all_attendees    = $count
3304
-                ? $ATT_MDL->count($query_args, 'ATT_ID', true)
3305
-                : $ATT_MDL->get_all($query_args);
3306
-        }
3307
-        return $all_attendees;
3308
-    }
3309
-
3310
-
3311
-    /**
3312
-     * This is just taking care of resending the registration confirmation
3313
-     *
3314
-     * @access protected
3315
-     * @return void
3316
-     */
3317
-    protected function _resend_registration()
3318
-    {
3319
-        $this->_process_resend_registration();
3320
-        $query_args = isset($this->_req_data['redirect_to'])
3321
-            ? array('action' => $this->_req_data['redirect_to'], '_REG_ID' => $this->_req_data['_REG_ID'])
3322
-            : array('action' => 'default');
3323
-        $this->_redirect_after_action(false, '', '', $query_args, true);
3324
-    }
3325
-
3326
-    /**
3327
-     * Creates a registration report, but accepts the name of a method to use for preparing the query parameters
3328
-     * to use when selecting registrations
3329
-     * @param string $method_name_for_getting_query_params the name of the method (on this class) to use for preparing
3330
-     *                                                     the query parameters from the request
3331
-     * @return void ends the request with a redirect or download
3332
-     */
3333
-    public function _registrations_report_base( $method_name_for_getting_query_params )
3334
-    {
3335
-        if (! defined('EE_USE_OLD_CSV_REPORT_CLASS')) {
3336
-            wp_redirect(EE_Admin_Page::add_query_args_and_nonce(
3337
-                array(
3338
-                    'page'        => 'espresso_batch',
3339
-                    'batch'       => 'file',
3340
-                    'EVT_ID'      => isset($this->_req_data['EVT_ID']) ? $this->_req_data['EVT_ID'] : null,
3341
-                    'filters'     => urlencode(
3342
-                        serialize(
3343
-                            call_user_func(
3344
-                                array( $this, $method_name_for_getting_query_params ),
3345
-                                EEH_Array::is_set(
3346
-                                    $this->_req_data,
3347
-                                    'filters',
3348
-                                    array()
3349
-                                )
3350
-                            )
3351
-                        )
3352
-                ),
3353
-                'use_filters' => EEH_Array::is_set($this->_req_data, 'use_filters', false),
3354
-                'job_handler' => urlencode('EventEspressoBatchRequest\JobHandlers\RegistrationsReport'),
3355
-                'return_url'  => urlencode($this->_req_data['return_url']),
3356
-            )));
3357
-        } else {
3358
-            $new_request_args = array(
3359
-                'export' => 'report',
3360
-                'action' => 'registrations_report_for_event',
3361
-                'EVT_ID' => isset($this->_req_data['EVT_ID']) ? $this->_req_data['EVT_ID'] : null,
3362
-            );
3363
-            $this->_req_data = array_merge($this->_req_data, $new_request_args);
3364
-            if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3365
-                require_once(EE_CLASSES . 'EE_Export.class.php');
3366
-                $EE_Export = EE_Export::instance($this->_req_data);
3367
-                $EE_Export->export();
3368
-            }
3369
-        }
3370
-    }
3371
-
3372
-
3373
-
3374
-    /**
3375
-     * Creates a registration report using only query parameters in the request
3376
-     * @return void
3377
-     */
3378
-    public function _registrations_report()
3379
-    {
3380
-        $this->_registrations_report_base('_get_registration_query_parameters');
3381
-    }
3382
-
3383
-
3384
-    public function _contact_list_export()
3385
-    {
3386
-        if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3387
-            require_once(EE_CLASSES . 'EE_Export.class.php');
3388
-            $EE_Export = EE_Export::instance($this->_req_data);
3389
-            $EE_Export->export_attendees();
3390
-        }
3391
-    }
3392
-
3393
-
3394
-    public function _contact_list_report()
3395
-    {
3396
-        if ( ! defined('EE_USE_OLD_CSV_REPORT_CLASS')) {
3397
-            wp_redirect(EE_Admin_Page::add_query_args_and_nonce(array(
3398
-                'page'        => 'espresso_batch',
3399
-                'batch'       => 'file',
3400
-                'job_handler' => urlencode('EventEspressoBatchRequest\JobHandlers\AttendeesReport'),
3401
-                'return_url'  => urlencode($this->_req_data['return_url']),
3402
-            )));
3403
-        } else {
3404
-            if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3405
-                require_once(EE_CLASSES . 'EE_Export.class.php');
3406
-                $EE_Export = EE_Export::instance($this->_req_data);
3407
-                $EE_Export->report_attendees();
3408
-            }
3409
-        }
3410
-    }
3411
-
3412
-
3413
-
3414
-
3415
-
3416
-    /***************************************        ATTENDEE DETAILS        ***************************************/
3417
-    /**
3418
-     * This duplicates the attendee object for the given incoming registration id and attendee_id.
3419
-     *
3420
-     * @return void
3421
-     * @throws EE_Error
3422
-     * @throws InvalidArgumentException
3423
-     * @throws InvalidDataTypeException
3424
-     * @throws InvalidInterfaceException
3425
-     */
3426
-    protected function _duplicate_attendee()
3427
-    {
3428
-        $action = ! empty($this->_req_data['return']) ? $this->_req_data['return'] : 'default';
3429
-        //verify we have necessary info
3430
-        if (empty($this->_req_data['_REG_ID'])) {
3431
-            EE_Error::add_error(
3432
-                esc_html__(
3433
-                    'Unable to create the contact for the registration because the required parameters are not present (_REG_ID )',
3434
-                    'event_espresso'
3435
-                ), __FILE__, __LINE__, __FUNCTION__
3436
-            );
3437
-            $query_args = array('action' => $action);
3438
-            $this->_redirect_after_action('', '', '', $query_args, true);
3439
-        }
3440
-        //okay necessary deets present... let's dupe the incoming attendee and attach to incoming registration.
3441
-        $registration = EEM_Registration::instance()->get_one_by_ID($this->_req_data['_REG_ID']);
3442
-        $attendee     = $registration->attendee();
3443
-        //remove relation of existing attendee on registration
3444
-        $registration->_remove_relation_to($attendee, 'Attendee');
3445
-        //new attendee
3446
-        $new_attendee = clone $attendee;
3447
-        $new_attendee->set('ATT_ID', 0);
3448
-        $new_attendee->save();
3449
-        //add new attendee to reg
3450
-        $registration->_add_relation_to($new_attendee, 'Attendee');
3451
-        EE_Error::add_success(
3452
-            esc_html__(
3453
-                'New Contact record created.  Now make any edits you wish to make for this contact.',
3454
-                'event_espresso'
3455
-            )
3456
-        );
3457
-        //redirect to edit page for attendee
3458
-        $query_args = array('post' => $new_attendee->ID(), 'action' => 'edit_attendee');
3459
-        $this->_redirect_after_action('', '', '', $query_args, true);
3460
-    }
3461
-
3462
-
3463
-    /**
3464
-     * Callback invoked by parent EE_Admin_CPT class hooked in on `save_post` wp hook.
3465
-     * @param int      $post_id
3466
-     * @param WP_POST $post
3467
-     * @throws DomainException
3468
-     * @throws EE_Error
3469
-     * @throws InvalidArgumentException
3470
-     * @throws InvalidDataTypeException
3471
-     * @throws InvalidInterfaceException
3472
-     * @throws LogicException
3473
-     * @throws InvalidFormSubmissionException
3474
-     */
3475
-    protected function _insert_update_cpt_item($post_id, $post)
3476
-    {
3477
-        $success  = true;
3478
-        $attendee = $post instanceof WP_Post && $post->post_type === 'espresso_attendees'
3479
-            ? EEM_Attendee::instance()->get_one_by_ID($post_id)
3480
-            : null;
3481
-        //for attendee updates
3482
-        if ($attendee instanceof EE_Attendee) {
3483
-            //note we should only be UPDATING attendees at this point.
3484
-            $updated_fields = array(
3485
-                'ATT_fname'     => $this->_req_data['ATT_fname'],
3486
-                'ATT_lname'     => $this->_req_data['ATT_lname'],
3487
-                'ATT_full_name' => $this->_req_data['ATT_fname'] . ' ' . $this->_req_data['ATT_lname'],
3488
-                'ATT_address'   => isset($this->_req_data['ATT_address']) ? $this->_req_data['ATT_address'] : '',
3489
-                'ATT_address2'  => isset($this->_req_data['ATT_address2']) ? $this->_req_data['ATT_address2'] : '',
3490
-                'ATT_city'      => isset($this->_req_data['ATT_city']) ? $this->_req_data['ATT_city'] : '',
3491
-                'STA_ID'        => isset($this->_req_data['STA_ID']) ? $this->_req_data['STA_ID'] : '',
3492
-                'CNT_ISO'       => isset($this->_req_data['CNT_ISO']) ? $this->_req_data['CNT_ISO'] : '',
3493
-                'ATT_zip'       => isset($this->_req_data['ATT_zip']) ? $this->_req_data['ATT_zip'] : '',
3494
-            );
3495
-            foreach ($updated_fields as $field => $value) {
3496
-                $attendee->set($field, $value);
3497
-            }
3498
-
3499
-            //process contact details metabox form handler (which will also save the attendee)
3500
-            $contact_details_form = $this->getAttendeeContactDetailsMetaboxFormHandler($attendee);
3501
-            $success = $contact_details_form->process($this->_req_data);
3502
-
3503
-            $attendee_update_callbacks = apply_filters(
3504
-                'FHEE__Registrations_Admin_Page__insert_update_cpt_item__attendee_update',
3505
-                array()
3506
-            );
3507
-            foreach ($attendee_update_callbacks as $a_callback) {
3508
-                if (false === call_user_func_array($a_callback, array($attendee, $this->_req_data))) {
3509
-                    throw new EE_Error(
3510
-                        sprintf(
3511
-                            esc_html__(
3512
-                                'The %s callback given for the "FHEE__Registrations_Admin_Page__insert_update_cpt_item__attendee_update" filter is not a valid callback.  Please check the spelling.',
3513
-                                'event_espresso'
3514
-                            ),
3515
-                            $a_callback
3516
-                        )
3517
-                    );
3518
-                }
3519
-            }
3520
-        }
3521
-
3522
-        if ($success === false) {
3523
-            EE_Error::add_error(
3524
-                esc_html__(
3525
-                    'Something went wrong with updating the meta table data for the registration.',
3526
-                    'event_espresso'
3527
-                ),
3528
-                __FILE__, __FUNCTION__, __LINE__
3529
-            );
3530
-        }
3531
-    }
3532
-
3533
-
3534
-    public function trash_cpt_item($post_id)
3535
-    {
3536
-    }
3537
-
3538
-
3539
-    public function delete_cpt_item($post_id)
3540
-    {
3541
-    }
3542
-
3543
-
3544
-    public function restore_cpt_item($post_id)
3545
-    {
3546
-    }
3547
-
3548
-
3549
-    protected function _restore_cpt_item($post_id, $revision_id)
3550
-    {
3551
-    }
3552
-
3553
-
3554
-    public function attendee_editor_metaboxes()
3555
-    {
3556
-        $this->verify_cpt_object();
3557
-        remove_meta_box(
3558
-            'postexcerpt',
3559
-            esc_html__('Excerpt', 'event_espresso'),
3560
-            'post_excerpt_meta_box',
3561
-            $this->_cpt_routes[$this->_req_action],
3562
-            'normal',
3563
-            'core'
3564
-        );
3565
-        remove_meta_box('commentstatusdiv', $this->_cpt_routes[$this->_req_action], 'normal', 'core');
3566
-        if (post_type_supports('espresso_attendees', 'excerpt')) {
3567
-            add_meta_box(
3568
-                'postexcerpt',
3569
-                esc_html__('Short Biography', 'event_espresso'),
3570
-                'post_excerpt_meta_box',
3571
-                $this->_cpt_routes[$this->_req_action],
3572
-                'normal'
3573
-            );
3574
-        }
3575
-        if (post_type_supports('espresso_attendees', 'comments')) {
3576
-            add_meta_box(
3577
-                'commentsdiv',
3578
-                esc_html__('Notes on the Contact', 'event_espresso'),
3579
-                'post_comment_meta_box',
3580
-                $this->_cpt_routes[$this->_req_action],
3581
-                'normal',
3582
-                'core'
3583
-            );
3584
-        }
3585
-        add_meta_box(
3586
-            'attendee_contact_info',
3587
-            esc_html__('Contact Info', 'event_espresso'),
3588
-            array($this, 'attendee_contact_info'),
3589
-            $this->_cpt_routes[$this->_req_action],
3590
-            'side',
3591
-            'core'
3592
-        );
3593
-        add_meta_box(
3594
-            'attendee_details_address',
3595
-            esc_html__('Address Details', 'event_espresso'),
3596
-            array($this, 'attendee_address_details'),
3597
-            $this->_cpt_routes[$this->_req_action],
3598
-            'normal',
3599
-            'core'
3600
-        );
3601
-        add_meta_box(
3602
-            'attendee_registrations',
3603
-            esc_html__('Registrations for this Contact', 'event_espresso'),
3604
-            array($this, 'attendee_registrations_meta_box'),
3605
-            $this->_cpt_routes[$this->_req_action],
3606
-            'normal',
3607
-            'high'
3608
-        );
3609
-    }
3610
-
3611
-
3612
-    /**
3613
-     * Metabox for attendee contact info
3614
-     *
3615
-     * @param  WP_Post $post wp post object
3616
-     * @return string attendee contact info ( and form )
3617
-     * @throws EE_Error
3618
-     * @throws InvalidArgumentException
3619
-     * @throws InvalidDataTypeException
3620
-     * @throws InvalidInterfaceException
3621
-     * @throws LogicException
3622
-     * @throws DomainException
3623
-     */
3624
-    public function attendee_contact_info($post)
3625
-    {
3626
-        //get attendee object ( should already have it )
3627
-        $form = $this->getAttendeeContactDetailsMetaboxFormHandler($this->_cpt_model_obj);
3628
-        $form->enqueueStylesAndScripts();
3629
-        echo $form->display();
3630
-    }
3631
-
3632
-
3633
-    /**
3634
-     * Return form handler for the contact details metabox
3635
-     *
3636
-     * @param EE_Attendee $attendee
3637
-     * @return AttendeeContactDetailsMetaboxFormHandler
3638
-     * @throws DomainException
3639
-     * @throws InvalidArgumentException
3640
-     * @throws InvalidDataTypeException
3641
-     * @throws InvalidInterfaceException
3642
-     */
3643
-    protected function getAttendeeContactDetailsMetaboxFormHandler(EE_Attendee $attendee)
3644
-    {
3645
-        return new AttendeeContactDetailsMetaboxFormHandler($attendee, EE_Registry::instance());
3646
-    }
3647
-
3648
-
3649
-    /**
3650
-     * Metabox for attendee details
3651
-     *
3652
-     * @param  WP_Post $post wp post object
3653
-     * @throws DomainException
3654
-     */
3655
-    public function attendee_address_details($post)
3656
-    {
3657
-        //get attendee object (should already have it)
3658
-        $this->_template_args['attendee']     = $this->_cpt_model_obj;
3659
-        $this->_template_args['state_html']   = EEH_Form_Fields::generate_form_input(
3660
-            new EE_Question_Form_Input(
3661
-                EE_Question::new_instance(
3662
-                    array(
3663
-                        'QST_ID'           => 0,
3664
-                        'QST_display_text' => esc_html__('State/Province', 'event_espresso'),
3665
-                        'QST_system'       => 'admin-state',
3666
-                    )
3667
-                ),
3668
-                EE_Answer::new_instance(
3669
-                    array(
3670
-                        'ANS_ID'    => 0,
3671
-                        'ANS_value' => $this->_cpt_model_obj->state_ID(),
3672
-                    )
3673
-                ),
3674
-                array(
3675
-                    'input_id'       => 'STA_ID',
3676
-                    'input_name'     => 'STA_ID',
3677
-                    'input_prefix'   => '',
3678
-                    'append_qstn_id' => false,
3679
-                )
3680
-            )
3681
-        );
3682
-        $this->_template_args['country_html'] = EEH_Form_Fields::generate_form_input(
3683
-            new EE_Question_Form_Input(
3684
-                EE_Question::new_instance(
3685
-                    array(
3686
-                        'QST_ID'           => 0,
3687
-                        'QST_display_text' => esc_html__('Country', 'event_espresso'),
3688
-                        'QST_system'       => 'admin-country',
3689
-                    )
3690
-                ),
3691
-                EE_Answer::new_instance(
3692
-                    array(
3693
-                        'ANS_ID'    => 0,
3694
-                        'ANS_value' => $this->_cpt_model_obj->country_ID(),
3695
-                    )
3696
-                ),
3697
-                array(
3698
-                    'input_id'       => 'CNT_ISO',
3699
-                    'input_name'     => 'CNT_ISO',
3700
-                    'input_prefix'   => '',
3701
-                    'append_qstn_id' => false,
3702
-                )
3703
-            )
3704
-        );
3705
-        $template                             =
3706
-            REG_TEMPLATE_PATH . 'attendee_address_details_metabox_content.template.php';
3707
-        EEH_Template::display_template($template, $this->_template_args);
3708
-    }
3709
-
3710
-
3711
-    /**
3712
-     *        _attendee_details
3713
-     *
3714
-     * @access protected
3715
-     * @param $post
3716
-     * @return void
3717
-     * @throws DomainException
3718
-     * @throws EE_Error
3719
-     */
3720
-    public function attendee_registrations_meta_box($post)
3721
-    {
3722
-        $this->_template_args['attendee']      = $this->_cpt_model_obj;
3723
-        $this->_template_args['registrations'] = $this->_cpt_model_obj->get_many_related('Registration');
3724
-        $template                              =
3725
-            REG_TEMPLATE_PATH . 'attendee_registrations_main_meta_box.template.php';
3726
-        EEH_Template::display_template($template, $this->_template_args);
3727
-    }
3728
-
3729
-
3730
-    /**
3731
-     * add in the form fields for the attendee edit
3732
-     *
3733
-     * @param  WP_Post $post wp post object
3734
-     * @return string html for new form.
3735
-     * @throws DomainException
3736
-     */
3737
-    public function after_title_form_fields($post)
3738
-    {
3739
-        if ($post->post_type == 'espresso_attendees') {
3740
-            $template                  = REG_TEMPLATE_PATH . 'attendee_details_after_title_form_fields.template.php';
3741
-            $template_args['attendee'] = $this->_cpt_model_obj;
3742
-            EEH_Template::display_template($template, $template_args);
3743
-        }
3744
-    }
3745
-
3746
-
3747
-    /**
3748
-     *        _trash_or_restore_attendee
3749
-     *
3750
-     * @param boolean $trash - whether to move item to trash (TRUE) or restore it (FALSE)
3751
-     * @return void
3752
-     * @throws EE_Error
3753
-     * @throws InvalidArgumentException
3754
-     * @throws InvalidDataTypeException
3755
-     * @throws InvalidInterfaceException
3756
-     * @access protected
3757
-     */
3758
-    protected function _trash_or_restore_attendees($trash = true)
3759
-    {
3760
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3761
-        $ATT_MDL = EEM_Attendee::instance();
3762
-        $success = 1;
3763
-        //Checkboxes
3764
-        if ( ! empty($this->_req_data['checkbox']) && is_array($this->_req_data['checkbox'])) {
3765
-            // if array has more than one element than success message should be plural
3766
-            $success = count($this->_req_data['checkbox']) > 1 ? 2 : 1;
3767
-            // cycle thru checkboxes
3768
-            while (list($ATT_ID, $value) = each($this->_req_data['checkbox'])) {
3769
-                $updated = $trash ? $ATT_MDL->update_by_ID(array('status' => 'trash'), $ATT_ID)
3770
-                    : $ATT_MDL->update_by_ID(array('status' => 'publish'), $ATT_ID);
3771
-                if ( ! $updated) {
3772
-                    $success = 0;
3773
-                }
3774
-            }
3775
-        } else {
3776
-            // grab single id and delete
3777
-            $ATT_ID = absint($this->_req_data['ATT_ID']);
3778
-            //get attendee
3779
-            $att     = $ATT_MDL->get_one_by_ID($ATT_ID);
3780
-            $updated = $trash ? $att->set_status('trash') : $att->set_status('publish');
3781
-            $updated = $att->save();
3782
-            if ( ! $updated) {
3783
-                $success = 0;
3784
-            }
3785
-        }
3786
-        $what        = $success > 1
3787
-            ? esc_html__('Contacts', 'event_espresso')
3788
-            : esc_html__('Contact', 'event_espresso');
3789
-        $action_desc = $trash
3790
-            ? esc_html__('moved to the trash', 'event_espresso')
3791
-            : esc_html__('restored', 'event_espresso');
3792
-        $this->_redirect_after_action($success, $what, $action_desc, array('action' => 'contact_list'));
3793
-    }
2958
+		}
2959
+		$template_args = array(
2960
+			'title'                    => '',
2961
+			'content'                  => '',
2962
+			'step_button_text'         => '',
2963
+			'show_notification_toggle' => false,
2964
+		);
2965
+		//to indicate we're processing a new registration
2966
+		$hidden_fields = array(
2967
+			'processing_registration' => array(
2968
+				'type'  => 'hidden',
2969
+				'value' => 0,
2970
+			),
2971
+			'event_id'                => array(
2972
+				'type'  => 'hidden',
2973
+				'value' => $this->_reg_event->ID(),
2974
+			),
2975
+		);
2976
+		//if the cart is empty then we know we're at step one so we'll display ticket selector
2977
+		$cart = EE_Registry::instance()->SSN->cart();
2978
+		$step = ! $cart instanceof EE_Cart ? 'ticket' : 'questions';
2979
+		switch ($step) {
2980
+			case 'ticket' :
2981
+				$hidden_fields['processing_registration']['value'] = 1;
2982
+				$template_args['title']                            = esc_html__(
2983
+					'Step One: Select the Ticket for this registration',
2984
+					'event_espresso'
2985
+				);
2986
+				$template_args['content']                          =
2987
+					EED_Ticket_Selector::instance()->display_ticket_selector($this->_reg_event);
2988
+				$template_args['step_button_text']                 = esc_html__(
2989
+					'Add Tickets and Continue to Registrant Details',
2990
+					'event_espresso'
2991
+				);
2992
+				$template_args['show_notification_toggle']         = false;
2993
+				break;
2994
+			case 'questions' :
2995
+				$hidden_fields['processing_registration']['value'] = 2;
2996
+				$template_args['title']                            = esc_html__(
2997
+					'Step Two: Add Registrant Details for this Registration',
2998
+					'event_espresso'
2999
+				);
3000
+				//in theory we should be able to run EED_SPCO at this point because the cart should have been setup
3001
+				// properly by the first process_reg_step run.
3002
+				$template_args['content']                  =
3003
+					EED_Single_Page_Checkout::registration_checkout_for_admin();
3004
+				$template_args['step_button_text']         = esc_html__(
3005
+					'Save Registration and Continue to Details',
3006
+					'event_espresso'
3007
+				);
3008
+				$template_args['show_notification_toggle'] = true;
3009
+				break;
3010
+		}
3011
+		//we come back to the process_registration_step route.
3012
+		$this->_set_add_edit_form_tags('process_reg_step', $hidden_fields);
3013
+		return EEH_Template::display_template(
3014
+			REG_TEMPLATE_PATH . 'reg_admin_register_new_attendee_step_content.template.php',
3015
+			$template_args,
3016
+			true
3017
+		);
3018
+	}
3019
+
3020
+
3021
+	/**
3022
+	 *        set_reg_event
3023
+	 *
3024
+	 * @access private
3025
+	 * @return bool
3026
+	 * @throws EE_Error
3027
+	 * @throws InvalidArgumentException
3028
+	 * @throws InvalidDataTypeException
3029
+	 * @throws InvalidInterfaceException
3030
+	 */
3031
+	private function _set_reg_event()
3032
+	{
3033
+		if (is_object($this->_reg_event)) {
3034
+			return true;
3035
+		}
3036
+		$EVT_ID = (! empty($this->_req_data['event_id'])) ? absint($this->_req_data['event_id']) : false;
3037
+		if ( ! $EVT_ID) {
3038
+			return false;
3039
+		}
3040
+		$this->_reg_event = EEM_Event::instance()->get_one_by_ID($EVT_ID);
3041
+		return true;
3042
+	}
3043
+
3044
+
3045
+	/**
3046
+	 * process_reg_step
3047
+	 *
3048
+	 * @access        public
3049
+	 * @return string
3050
+	 * @throws DomainException
3051
+	 * @throws EE_Error
3052
+	 * @throws InvalidArgumentException
3053
+	 * @throws InvalidDataTypeException
3054
+	 * @throws InvalidInterfaceException
3055
+	 * @throws ReflectionException
3056
+	 * @throws RuntimeException
3057
+	 */
3058
+	public function process_reg_step()
3059
+	{
3060
+		EE_System::do_not_cache();
3061
+		$this->_set_reg_event();
3062
+		EE_Registry::instance()->REQ->set_espresso_page(true);
3063
+		EE_Registry::instance()->REQ->set('uts', time());
3064
+		//what step are we on?
3065
+		$cart = EE_Registry::instance()->SSN->cart();
3066
+		$step = ! $cart instanceof EE_Cart ? 'ticket' : 'questions';
3067
+		//if doing ajax then we need to verify the nonce
3068
+		if (defined('DOING_AJAX')) {
3069
+			$nonce = isset($this->_req_data[$this->_req_nonce])
3070
+				? sanitize_text_field($this->_req_data[$this->_req_nonce]) : '';
3071
+			$this->_verify_nonce($nonce, $this->_req_nonce);
3072
+		}
3073
+		switch ($step) {
3074
+			case 'ticket' :
3075
+				//process ticket selection
3076
+				$success = EED_Ticket_Selector::instance()->process_ticket_selections();
3077
+				if ($success) {
3078
+					EE_Error::add_success(
3079
+						esc_html__(
3080
+							'Tickets Selected. Now complete the registration.',
3081
+							'event_espresso'
3082
+						)
3083
+					);
3084
+				} else {
3085
+					$query_args['step_error'] = $this->_req_data['step_error'] = true;
3086
+				}
3087
+				if (defined('DOING_AJAX')) {
3088
+					$this->new_registration(); //display next step
3089
+				} else {
3090
+					$query_args = array(
3091
+						'action'                  => 'new_registration',
3092
+						'processing_registration' => 1,
3093
+						'event_id'                => $this->_reg_event->ID(),
3094
+						'uts'                     => time(),
3095
+					);
3096
+					$this->_redirect_after_action(
3097
+						false,
3098
+						'',
3099
+						'',
3100
+						$query_args,
3101
+						true
3102
+					);
3103
+				}
3104
+				break;
3105
+			case 'questions' :
3106
+				if (! isset(
3107
+					$this->_req_data['txn_reg_status_change'],
3108
+					$this->_req_data['txn_reg_status_change']['send_notifications'])
3109
+				) {
3110
+					add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_false', 15);
3111
+				}
3112
+				//process registration
3113
+				$transaction = EED_Single_Page_Checkout::instance()->process_registration_from_admin();
3114
+				if ($cart instanceof EE_Cart) {
3115
+					$grand_total = $cart->get_cart_grand_total();
3116
+					if ($grand_total instanceof EE_Line_Item) {
3117
+						$grand_total->save_this_and_descendants_to_txn();
3118
+					}
3119
+				}
3120
+				if ( ! $transaction instanceof EE_Transaction) {
3121
+					$query_args = array(
3122
+						'action'                  => 'new_registration',
3123
+						'processing_registration' => 2,
3124
+						'event_id'                => $this->_reg_event->ID(),
3125
+						'uts'                     => time(),
3126
+					);
3127
+					if (defined('DOING_AJAX')) {
3128
+						//display registration form again because there are errors (maybe validation?)
3129
+						$this->new_registration();
3130
+						return;
3131
+					} else {
3132
+						$this->_redirect_after_action(
3133
+							false,
3134
+							'',
3135
+							'',
3136
+							$query_args,
3137
+							true
3138
+						);
3139
+						return;
3140
+					}
3141
+				}
3142
+				// maybe update status, and make sure to save transaction if not done already
3143
+				if ( ! $transaction->update_status_based_on_total_paid()) {
3144
+					$transaction->save();
3145
+				}
3146
+				EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
3147
+				$this->_req_data = array();
3148
+				$query_args      = array(
3149
+					'action'        => 'redirect_to_txn',
3150
+					'TXN_ID'        => $transaction->ID(),
3151
+					'EVT_ID'        => $this->_reg_event->ID(),
3152
+					'event_name'    => urlencode($this->_reg_event->name()),
3153
+					'redirect_from' => 'new_registration',
3154
+				);
3155
+				$this->_redirect_after_action(false, '', '', $query_args, true);
3156
+				break;
3157
+		}
3158
+		//what are you looking here for?  Should be nothing to do at this point.
3159
+	}
3160
+
3161
+
3162
+	/**
3163
+	 * redirect_to_txn
3164
+	 *
3165
+	 * @access public
3166
+	 * @return void
3167
+	 * @throws EE_Error
3168
+	 * @throws InvalidArgumentException
3169
+	 * @throws InvalidDataTypeException
3170
+	 * @throws InvalidInterfaceException
3171
+	 */
3172
+	public function redirect_to_txn()
3173
+	{
3174
+		EE_System::do_not_cache();
3175
+		EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
3176
+		$query_args = array(
3177
+			'action' => 'view_transaction',
3178
+			'TXN_ID' => isset($this->_req_data['TXN_ID']) ? absint($this->_req_data['TXN_ID']) : 0,
3179
+			'page'   => 'espresso_transactions',
3180
+		);
3181
+		if (isset($this->_req_data['EVT_ID'], $this->_req_data['redirect_from'])) {
3182
+			$query_args['EVT_ID']        = $this->_req_data['EVT_ID'];
3183
+			$query_args['event_name']    = urlencode($this->_req_data['event_name']);
3184
+			$query_args['redirect_from'] = $this->_req_data['redirect_from'];
3185
+		}
3186
+		EE_Error::add_success(
3187
+			esc_html__(
3188
+				'Registration Created.  Please review the transaction and add any payments as necessary',
3189
+				'event_espresso'
3190
+			)
3191
+		);
3192
+		$this->_redirect_after_action(false, '', '', $query_args, true);
3193
+	}
3194
+
3195
+
3196
+	/**
3197
+	 *        generates HTML for the Attendee Contact List
3198
+	 *
3199
+	 * @access protected
3200
+	 * @return void
3201
+	 */
3202
+	protected function _attendee_contact_list_table()
3203
+	{
3204
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3205
+		$this->_search_btn_label = esc_html__('Contacts', 'event_espresso');
3206
+		$this->display_admin_list_table_page_with_no_sidebar();
3207
+	}
3208
+
3209
+
3210
+	/**
3211
+	 *        get_attendees
3212
+	 *
3213
+	 * @param      $per_page
3214
+	 * @param bool $count whether to return count or data.
3215
+	 * @param bool $trash
3216
+	 * @return array
3217
+	 * @throws EE_Error
3218
+	 * @throws InvalidArgumentException
3219
+	 * @throws InvalidDataTypeException
3220
+	 * @throws InvalidInterfaceException
3221
+	 * @access public
3222
+	 */
3223
+	public function get_attendees($per_page, $count = false, $trash = false)
3224
+	{
3225
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3226
+		require_once(REG_ADMIN . 'EE_Attendee_Contact_List_Table.class.php');
3227
+		$ATT_MDL                    = EEM_Attendee::instance();
3228
+		$this->_req_data['orderby'] = ! empty($this->_req_data['orderby']) ? $this->_req_data['orderby'] : '';
3229
+		switch ($this->_req_data['orderby']) {
3230
+			case 'ATT_ID':
3231
+				$orderby = 'ATT_ID';
3232
+				break;
3233
+			case 'ATT_fname':
3234
+				$orderby = 'ATT_fname';
3235
+				break;
3236
+			case 'ATT_email':
3237
+				$orderby = 'ATT_email';
3238
+				break;
3239
+			case 'ATT_city':
3240
+				$orderby = 'ATT_city';
3241
+				break;
3242
+			case 'STA_ID':
3243
+				$orderby = 'STA_ID';
3244
+				break;
3245
+			case 'CNT_ID':
3246
+				$orderby = 'CNT_ID';
3247
+				break;
3248
+			case 'Registration_Count':
3249
+				$orderby = 'Registration_Count';
3250
+				break;
3251
+			default:
3252
+				$orderby = 'ATT_lname';
3253
+		}
3254
+		$sort         = (isset($this->_req_data['order']) && ! empty($this->_req_data['order']))
3255
+			? $this->_req_data['order']
3256
+			: 'ASC';
3257
+		$current_page = isset($this->_req_data['paged']) && ! empty($this->_req_data['paged'])
3258
+			? $this->_req_data['paged']
3259
+			: 1;
3260
+		$per_page     = isset($per_page) && ! empty($per_page) ? $per_page : 10;
3261
+		$per_page     = isset($this->_req_data['perpage']) && ! empty($this->_req_data['perpage'])
3262
+			? $this->_req_data['perpage']
3263
+			: $per_page;
3264
+		$_where       = array();
3265
+		if ( ! empty($this->_req_data['s'])) {
3266
+			$sstr         = '%' . $this->_req_data['s'] . '%';
3267
+			$_where['OR'] = array(
3268
+				'Registration.Event.EVT_name'       => array('LIKE', $sstr),
3269
+				'Registration.Event.EVT_desc'       => array('LIKE', $sstr),
3270
+				'Registration.Event.EVT_short_desc' => array('LIKE', $sstr),
3271
+				'ATT_fname'                         => array('LIKE', $sstr),
3272
+				'ATT_lname'                         => array('LIKE', $sstr),
3273
+				'ATT_short_bio'                     => array('LIKE', $sstr),
3274
+				'ATT_email'                         => array('LIKE', $sstr),
3275
+				'ATT_address'                       => array('LIKE', $sstr),
3276
+				'ATT_address2'                      => array('LIKE', $sstr),
3277
+				'ATT_city'                          => array('LIKE', $sstr),
3278
+				'Country.CNT_name'                  => array('LIKE', $sstr),
3279
+				'State.STA_name'                    => array('LIKE', $sstr),
3280
+				'ATT_phone'                         => array('LIKE', $sstr),
3281
+				'Registration.REG_final_price'      => array('LIKE', $sstr),
3282
+				'Registration.REG_code'             => array('LIKE', $sstr),
3283
+				'Registration.REG_group_size'       => array('LIKE', $sstr),
3284
+			);
3285
+		}
3286
+		$offset = ($current_page - 1) * $per_page;
3287
+		$limit  = $count ? null : array($offset, $per_page);
3288
+		$query_args = array(
3289
+			$_where,
3290
+			'extra_selects' => array('Registration_Count' => array('Registration.REG_ID', 'count', '%d')),
3291
+			'limit' => $limit
3292
+		);
3293
+		if (! $count) {
3294
+			$query_args['order_by'] = array($orderby => $sort);
3295
+		}
3296
+		if ($trash) {
3297
+			$query_args[0]['status'] = array('!=', 'publish');
3298
+			$all_attendees    = $count
3299
+				? $ATT_MDL->count($query_args, 'ATT_ID', true)
3300
+				: $ATT_MDL->get_all($query_args);
3301
+		} else {
3302
+			$query_args[0]['status'] = array('IN', array('publish'));
3303
+			$all_attendees    = $count
3304
+				? $ATT_MDL->count($query_args, 'ATT_ID', true)
3305
+				: $ATT_MDL->get_all($query_args);
3306
+		}
3307
+		return $all_attendees;
3308
+	}
3309
+
3310
+
3311
+	/**
3312
+	 * This is just taking care of resending the registration confirmation
3313
+	 *
3314
+	 * @access protected
3315
+	 * @return void
3316
+	 */
3317
+	protected function _resend_registration()
3318
+	{
3319
+		$this->_process_resend_registration();
3320
+		$query_args = isset($this->_req_data['redirect_to'])
3321
+			? array('action' => $this->_req_data['redirect_to'], '_REG_ID' => $this->_req_data['_REG_ID'])
3322
+			: array('action' => 'default');
3323
+		$this->_redirect_after_action(false, '', '', $query_args, true);
3324
+	}
3325
+
3326
+	/**
3327
+	 * Creates a registration report, but accepts the name of a method to use for preparing the query parameters
3328
+	 * to use when selecting registrations
3329
+	 * @param string $method_name_for_getting_query_params the name of the method (on this class) to use for preparing
3330
+	 *                                                     the query parameters from the request
3331
+	 * @return void ends the request with a redirect or download
3332
+	 */
3333
+	public function _registrations_report_base( $method_name_for_getting_query_params )
3334
+	{
3335
+		if (! defined('EE_USE_OLD_CSV_REPORT_CLASS')) {
3336
+			wp_redirect(EE_Admin_Page::add_query_args_and_nonce(
3337
+				array(
3338
+					'page'        => 'espresso_batch',
3339
+					'batch'       => 'file',
3340
+					'EVT_ID'      => isset($this->_req_data['EVT_ID']) ? $this->_req_data['EVT_ID'] : null,
3341
+					'filters'     => urlencode(
3342
+						serialize(
3343
+							call_user_func(
3344
+								array( $this, $method_name_for_getting_query_params ),
3345
+								EEH_Array::is_set(
3346
+									$this->_req_data,
3347
+									'filters',
3348
+									array()
3349
+								)
3350
+							)
3351
+						)
3352
+				),
3353
+				'use_filters' => EEH_Array::is_set($this->_req_data, 'use_filters', false),
3354
+				'job_handler' => urlencode('EventEspressoBatchRequest\JobHandlers\RegistrationsReport'),
3355
+				'return_url'  => urlencode($this->_req_data['return_url']),
3356
+			)));
3357
+		} else {
3358
+			$new_request_args = array(
3359
+				'export' => 'report',
3360
+				'action' => 'registrations_report_for_event',
3361
+				'EVT_ID' => isset($this->_req_data['EVT_ID']) ? $this->_req_data['EVT_ID'] : null,
3362
+			);
3363
+			$this->_req_data = array_merge($this->_req_data, $new_request_args);
3364
+			if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3365
+				require_once(EE_CLASSES . 'EE_Export.class.php');
3366
+				$EE_Export = EE_Export::instance($this->_req_data);
3367
+				$EE_Export->export();
3368
+			}
3369
+		}
3370
+	}
3371
+
3372
+
3373
+
3374
+	/**
3375
+	 * Creates a registration report using only query parameters in the request
3376
+	 * @return void
3377
+	 */
3378
+	public function _registrations_report()
3379
+	{
3380
+		$this->_registrations_report_base('_get_registration_query_parameters');
3381
+	}
3382
+
3383
+
3384
+	public function _contact_list_export()
3385
+	{
3386
+		if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3387
+			require_once(EE_CLASSES . 'EE_Export.class.php');
3388
+			$EE_Export = EE_Export::instance($this->_req_data);
3389
+			$EE_Export->export_attendees();
3390
+		}
3391
+	}
3392
+
3393
+
3394
+	public function _contact_list_report()
3395
+	{
3396
+		if ( ! defined('EE_USE_OLD_CSV_REPORT_CLASS')) {
3397
+			wp_redirect(EE_Admin_Page::add_query_args_and_nonce(array(
3398
+				'page'        => 'espresso_batch',
3399
+				'batch'       => 'file',
3400
+				'job_handler' => urlencode('EventEspressoBatchRequest\JobHandlers\AttendeesReport'),
3401
+				'return_url'  => urlencode($this->_req_data['return_url']),
3402
+			)));
3403
+		} else {
3404
+			if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3405
+				require_once(EE_CLASSES . 'EE_Export.class.php');
3406
+				$EE_Export = EE_Export::instance($this->_req_data);
3407
+				$EE_Export->report_attendees();
3408
+			}
3409
+		}
3410
+	}
3411
+
3412
+
3413
+
3414
+
3415
+
3416
+	/***************************************        ATTENDEE DETAILS        ***************************************/
3417
+	/**
3418
+	 * This duplicates the attendee object for the given incoming registration id and attendee_id.
3419
+	 *
3420
+	 * @return void
3421
+	 * @throws EE_Error
3422
+	 * @throws InvalidArgumentException
3423
+	 * @throws InvalidDataTypeException
3424
+	 * @throws InvalidInterfaceException
3425
+	 */
3426
+	protected function _duplicate_attendee()
3427
+	{
3428
+		$action = ! empty($this->_req_data['return']) ? $this->_req_data['return'] : 'default';
3429
+		//verify we have necessary info
3430
+		if (empty($this->_req_data['_REG_ID'])) {
3431
+			EE_Error::add_error(
3432
+				esc_html__(
3433
+					'Unable to create the contact for the registration because the required parameters are not present (_REG_ID )',
3434
+					'event_espresso'
3435
+				), __FILE__, __LINE__, __FUNCTION__
3436
+			);
3437
+			$query_args = array('action' => $action);
3438
+			$this->_redirect_after_action('', '', '', $query_args, true);
3439
+		}
3440
+		//okay necessary deets present... let's dupe the incoming attendee and attach to incoming registration.
3441
+		$registration = EEM_Registration::instance()->get_one_by_ID($this->_req_data['_REG_ID']);
3442
+		$attendee     = $registration->attendee();
3443
+		//remove relation of existing attendee on registration
3444
+		$registration->_remove_relation_to($attendee, 'Attendee');
3445
+		//new attendee
3446
+		$new_attendee = clone $attendee;
3447
+		$new_attendee->set('ATT_ID', 0);
3448
+		$new_attendee->save();
3449
+		//add new attendee to reg
3450
+		$registration->_add_relation_to($new_attendee, 'Attendee');
3451
+		EE_Error::add_success(
3452
+			esc_html__(
3453
+				'New Contact record created.  Now make any edits you wish to make for this contact.',
3454
+				'event_espresso'
3455
+			)
3456
+		);
3457
+		//redirect to edit page for attendee
3458
+		$query_args = array('post' => $new_attendee->ID(), 'action' => 'edit_attendee');
3459
+		$this->_redirect_after_action('', '', '', $query_args, true);
3460
+	}
3461
+
3462
+
3463
+	/**
3464
+	 * Callback invoked by parent EE_Admin_CPT class hooked in on `save_post` wp hook.
3465
+	 * @param int      $post_id
3466
+	 * @param WP_POST $post
3467
+	 * @throws DomainException
3468
+	 * @throws EE_Error
3469
+	 * @throws InvalidArgumentException
3470
+	 * @throws InvalidDataTypeException
3471
+	 * @throws InvalidInterfaceException
3472
+	 * @throws LogicException
3473
+	 * @throws InvalidFormSubmissionException
3474
+	 */
3475
+	protected function _insert_update_cpt_item($post_id, $post)
3476
+	{
3477
+		$success  = true;
3478
+		$attendee = $post instanceof WP_Post && $post->post_type === 'espresso_attendees'
3479
+			? EEM_Attendee::instance()->get_one_by_ID($post_id)
3480
+			: null;
3481
+		//for attendee updates
3482
+		if ($attendee instanceof EE_Attendee) {
3483
+			//note we should only be UPDATING attendees at this point.
3484
+			$updated_fields = array(
3485
+				'ATT_fname'     => $this->_req_data['ATT_fname'],
3486
+				'ATT_lname'     => $this->_req_data['ATT_lname'],
3487
+				'ATT_full_name' => $this->_req_data['ATT_fname'] . ' ' . $this->_req_data['ATT_lname'],
3488
+				'ATT_address'   => isset($this->_req_data['ATT_address']) ? $this->_req_data['ATT_address'] : '',
3489
+				'ATT_address2'  => isset($this->_req_data['ATT_address2']) ? $this->_req_data['ATT_address2'] : '',
3490
+				'ATT_city'      => isset($this->_req_data['ATT_city']) ? $this->_req_data['ATT_city'] : '',
3491
+				'STA_ID'        => isset($this->_req_data['STA_ID']) ? $this->_req_data['STA_ID'] : '',
3492
+				'CNT_ISO'       => isset($this->_req_data['CNT_ISO']) ? $this->_req_data['CNT_ISO'] : '',
3493
+				'ATT_zip'       => isset($this->_req_data['ATT_zip']) ? $this->_req_data['ATT_zip'] : '',
3494
+			);
3495
+			foreach ($updated_fields as $field => $value) {
3496
+				$attendee->set($field, $value);
3497
+			}
3498
+
3499
+			//process contact details metabox form handler (which will also save the attendee)
3500
+			$contact_details_form = $this->getAttendeeContactDetailsMetaboxFormHandler($attendee);
3501
+			$success = $contact_details_form->process($this->_req_data);
3502
+
3503
+			$attendee_update_callbacks = apply_filters(
3504
+				'FHEE__Registrations_Admin_Page__insert_update_cpt_item__attendee_update',
3505
+				array()
3506
+			);
3507
+			foreach ($attendee_update_callbacks as $a_callback) {
3508
+				if (false === call_user_func_array($a_callback, array($attendee, $this->_req_data))) {
3509
+					throw new EE_Error(
3510
+						sprintf(
3511
+							esc_html__(
3512
+								'The %s callback given for the "FHEE__Registrations_Admin_Page__insert_update_cpt_item__attendee_update" filter is not a valid callback.  Please check the spelling.',
3513
+								'event_espresso'
3514
+							),
3515
+							$a_callback
3516
+						)
3517
+					);
3518
+				}
3519
+			}
3520
+		}
3521
+
3522
+		if ($success === false) {
3523
+			EE_Error::add_error(
3524
+				esc_html__(
3525
+					'Something went wrong with updating the meta table data for the registration.',
3526
+					'event_espresso'
3527
+				),
3528
+				__FILE__, __FUNCTION__, __LINE__
3529
+			);
3530
+		}
3531
+	}
3532
+
3533
+
3534
+	public function trash_cpt_item($post_id)
3535
+	{
3536
+	}
3537
+
3538
+
3539
+	public function delete_cpt_item($post_id)
3540
+	{
3541
+	}
3542
+
3543
+
3544
+	public function restore_cpt_item($post_id)
3545
+	{
3546
+	}
3547
+
3548
+
3549
+	protected function _restore_cpt_item($post_id, $revision_id)
3550
+	{
3551
+	}
3552
+
3553
+
3554
+	public function attendee_editor_metaboxes()
3555
+	{
3556
+		$this->verify_cpt_object();
3557
+		remove_meta_box(
3558
+			'postexcerpt',
3559
+			esc_html__('Excerpt', 'event_espresso'),
3560
+			'post_excerpt_meta_box',
3561
+			$this->_cpt_routes[$this->_req_action],
3562
+			'normal',
3563
+			'core'
3564
+		);
3565
+		remove_meta_box('commentstatusdiv', $this->_cpt_routes[$this->_req_action], 'normal', 'core');
3566
+		if (post_type_supports('espresso_attendees', 'excerpt')) {
3567
+			add_meta_box(
3568
+				'postexcerpt',
3569
+				esc_html__('Short Biography', 'event_espresso'),
3570
+				'post_excerpt_meta_box',
3571
+				$this->_cpt_routes[$this->_req_action],
3572
+				'normal'
3573
+			);
3574
+		}
3575
+		if (post_type_supports('espresso_attendees', 'comments')) {
3576
+			add_meta_box(
3577
+				'commentsdiv',
3578
+				esc_html__('Notes on the Contact', 'event_espresso'),
3579
+				'post_comment_meta_box',
3580
+				$this->_cpt_routes[$this->_req_action],
3581
+				'normal',
3582
+				'core'
3583
+			);
3584
+		}
3585
+		add_meta_box(
3586
+			'attendee_contact_info',
3587
+			esc_html__('Contact Info', 'event_espresso'),
3588
+			array($this, 'attendee_contact_info'),
3589
+			$this->_cpt_routes[$this->_req_action],
3590
+			'side',
3591
+			'core'
3592
+		);
3593
+		add_meta_box(
3594
+			'attendee_details_address',
3595
+			esc_html__('Address Details', 'event_espresso'),
3596
+			array($this, 'attendee_address_details'),
3597
+			$this->_cpt_routes[$this->_req_action],
3598
+			'normal',
3599
+			'core'
3600
+		);
3601
+		add_meta_box(
3602
+			'attendee_registrations',
3603
+			esc_html__('Registrations for this Contact', 'event_espresso'),
3604
+			array($this, 'attendee_registrations_meta_box'),
3605
+			$this->_cpt_routes[$this->_req_action],
3606
+			'normal',
3607
+			'high'
3608
+		);
3609
+	}
3610
+
3611
+
3612
+	/**
3613
+	 * Metabox for attendee contact info
3614
+	 *
3615
+	 * @param  WP_Post $post wp post object
3616
+	 * @return string attendee contact info ( and form )
3617
+	 * @throws EE_Error
3618
+	 * @throws InvalidArgumentException
3619
+	 * @throws InvalidDataTypeException
3620
+	 * @throws InvalidInterfaceException
3621
+	 * @throws LogicException
3622
+	 * @throws DomainException
3623
+	 */
3624
+	public function attendee_contact_info($post)
3625
+	{
3626
+		//get attendee object ( should already have it )
3627
+		$form = $this->getAttendeeContactDetailsMetaboxFormHandler($this->_cpt_model_obj);
3628
+		$form->enqueueStylesAndScripts();
3629
+		echo $form->display();
3630
+	}
3631
+
3632
+
3633
+	/**
3634
+	 * Return form handler for the contact details metabox
3635
+	 *
3636
+	 * @param EE_Attendee $attendee
3637
+	 * @return AttendeeContactDetailsMetaboxFormHandler
3638
+	 * @throws DomainException
3639
+	 * @throws InvalidArgumentException
3640
+	 * @throws InvalidDataTypeException
3641
+	 * @throws InvalidInterfaceException
3642
+	 */
3643
+	protected function getAttendeeContactDetailsMetaboxFormHandler(EE_Attendee $attendee)
3644
+	{
3645
+		return new AttendeeContactDetailsMetaboxFormHandler($attendee, EE_Registry::instance());
3646
+	}
3647
+
3648
+
3649
+	/**
3650
+	 * Metabox for attendee details
3651
+	 *
3652
+	 * @param  WP_Post $post wp post object
3653
+	 * @throws DomainException
3654
+	 */
3655
+	public function attendee_address_details($post)
3656
+	{
3657
+		//get attendee object (should already have it)
3658
+		$this->_template_args['attendee']     = $this->_cpt_model_obj;
3659
+		$this->_template_args['state_html']   = EEH_Form_Fields::generate_form_input(
3660
+			new EE_Question_Form_Input(
3661
+				EE_Question::new_instance(
3662
+					array(
3663
+						'QST_ID'           => 0,
3664
+						'QST_display_text' => esc_html__('State/Province', 'event_espresso'),
3665
+						'QST_system'       => 'admin-state',
3666
+					)
3667
+				),
3668
+				EE_Answer::new_instance(
3669
+					array(
3670
+						'ANS_ID'    => 0,
3671
+						'ANS_value' => $this->_cpt_model_obj->state_ID(),
3672
+					)
3673
+				),
3674
+				array(
3675
+					'input_id'       => 'STA_ID',
3676
+					'input_name'     => 'STA_ID',
3677
+					'input_prefix'   => '',
3678
+					'append_qstn_id' => false,
3679
+				)
3680
+			)
3681
+		);
3682
+		$this->_template_args['country_html'] = EEH_Form_Fields::generate_form_input(
3683
+			new EE_Question_Form_Input(
3684
+				EE_Question::new_instance(
3685
+					array(
3686
+						'QST_ID'           => 0,
3687
+						'QST_display_text' => esc_html__('Country', 'event_espresso'),
3688
+						'QST_system'       => 'admin-country',
3689
+					)
3690
+				),
3691
+				EE_Answer::new_instance(
3692
+					array(
3693
+						'ANS_ID'    => 0,
3694
+						'ANS_value' => $this->_cpt_model_obj->country_ID(),
3695
+					)
3696
+				),
3697
+				array(
3698
+					'input_id'       => 'CNT_ISO',
3699
+					'input_name'     => 'CNT_ISO',
3700
+					'input_prefix'   => '',
3701
+					'append_qstn_id' => false,
3702
+				)
3703
+			)
3704
+		);
3705
+		$template                             =
3706
+			REG_TEMPLATE_PATH . 'attendee_address_details_metabox_content.template.php';
3707
+		EEH_Template::display_template($template, $this->_template_args);
3708
+	}
3709
+
3710
+
3711
+	/**
3712
+	 *        _attendee_details
3713
+	 *
3714
+	 * @access protected
3715
+	 * @param $post
3716
+	 * @return void
3717
+	 * @throws DomainException
3718
+	 * @throws EE_Error
3719
+	 */
3720
+	public function attendee_registrations_meta_box($post)
3721
+	{
3722
+		$this->_template_args['attendee']      = $this->_cpt_model_obj;
3723
+		$this->_template_args['registrations'] = $this->_cpt_model_obj->get_many_related('Registration');
3724
+		$template                              =
3725
+			REG_TEMPLATE_PATH . 'attendee_registrations_main_meta_box.template.php';
3726
+		EEH_Template::display_template($template, $this->_template_args);
3727
+	}
3728
+
3729
+
3730
+	/**
3731
+	 * add in the form fields for the attendee edit
3732
+	 *
3733
+	 * @param  WP_Post $post wp post object
3734
+	 * @return string html for new form.
3735
+	 * @throws DomainException
3736
+	 */
3737
+	public function after_title_form_fields($post)
3738
+	{
3739
+		if ($post->post_type == 'espresso_attendees') {
3740
+			$template                  = REG_TEMPLATE_PATH . 'attendee_details_after_title_form_fields.template.php';
3741
+			$template_args['attendee'] = $this->_cpt_model_obj;
3742
+			EEH_Template::display_template($template, $template_args);
3743
+		}
3744
+	}
3745
+
3746
+
3747
+	/**
3748
+	 *        _trash_or_restore_attendee
3749
+	 *
3750
+	 * @param boolean $trash - whether to move item to trash (TRUE) or restore it (FALSE)
3751
+	 * @return void
3752
+	 * @throws EE_Error
3753
+	 * @throws InvalidArgumentException
3754
+	 * @throws InvalidDataTypeException
3755
+	 * @throws InvalidInterfaceException
3756
+	 * @access protected
3757
+	 */
3758
+	protected function _trash_or_restore_attendees($trash = true)
3759
+	{
3760
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3761
+		$ATT_MDL = EEM_Attendee::instance();
3762
+		$success = 1;
3763
+		//Checkboxes
3764
+		if ( ! empty($this->_req_data['checkbox']) && is_array($this->_req_data['checkbox'])) {
3765
+			// if array has more than one element than success message should be plural
3766
+			$success = count($this->_req_data['checkbox']) > 1 ? 2 : 1;
3767
+			// cycle thru checkboxes
3768
+			while (list($ATT_ID, $value) = each($this->_req_data['checkbox'])) {
3769
+				$updated = $trash ? $ATT_MDL->update_by_ID(array('status' => 'trash'), $ATT_ID)
3770
+					: $ATT_MDL->update_by_ID(array('status' => 'publish'), $ATT_ID);
3771
+				if ( ! $updated) {
3772
+					$success = 0;
3773
+				}
3774
+			}
3775
+		} else {
3776
+			// grab single id and delete
3777
+			$ATT_ID = absint($this->_req_data['ATT_ID']);
3778
+			//get attendee
3779
+			$att     = $ATT_MDL->get_one_by_ID($ATT_ID);
3780
+			$updated = $trash ? $att->set_status('trash') : $att->set_status('publish');
3781
+			$updated = $att->save();
3782
+			if ( ! $updated) {
3783
+				$success = 0;
3784
+			}
3785
+		}
3786
+		$what        = $success > 1
3787
+			? esc_html__('Contacts', 'event_espresso')
3788
+			: esc_html__('Contact', 'event_espresso');
3789
+		$action_desc = $trash
3790
+			? esc_html__('moved to the trash', 'event_espresso')
3791
+			: esc_html__('restored', 'event_espresso');
3792
+		$this->_redirect_after_action($success, $what, $action_desc, array('action' => 'contact_list'));
3793
+	}
3794 3794
 
3795 3795
 }
Please login to merge, or discard this patch.
Spacing   +93 added lines, -93 removed lines patch added patch discarded remove patch
@@ -76,7 +76,7 @@  discard block
 block discarded – undo
76 76
         // when adding a new registration...
77 77
         if (isset($this->_req_data['action']) && $this->_req_data['action'] === 'new_registration') {
78 78
             EE_System::do_not_cache();
79
-            if (! isset($this->_req_data['processing_registration'])
79
+            if ( ! isset($this->_req_data['processing_registration'])
80 80
                  || absint($this->_req_data['processing_registration']) !== 1
81 81
             ) {
82 82
                 // and it's NOT the attendee information reg step
@@ -171,7 +171,7 @@  discard block
 block discarded – undo
171 171
     public function _set_page_routes()
172 172
     {
173 173
         $this->_get_registration_status_array();
174
-        $reg_id             = ! empty($this->_req_data['_REG_ID']) && ! is_array($this->_req_data['_REG_ID'])
174
+        $reg_id = ! empty($this->_req_data['_REG_ID']) && ! is_array($this->_req_data['_REG_ID'])
175 175
             ? $this->_req_data['_REG_ID'] : 0;
176 176
         $reg_id = empty($reg_id) && ! empty($this->_req_data['reg_status_change_form']['REG_ID'])
177 177
             ? $this->_req_data['reg_status_change_form']['REG_ID']
@@ -669,7 +669,7 @@  discard block
 block discarded – undo
669 669
         //style
670 670
         wp_register_style(
671 671
             'espresso_reg',
672
-            REG_ASSETS_URL . 'espresso_registrations_admin.css',
672
+            REG_ASSETS_URL.'espresso_registrations_admin.css',
673 673
             array('ee-admin-css'),
674 674
             EVENT_ESPRESSO_VERSION
675 675
         );
@@ -677,7 +677,7 @@  discard block
 block discarded – undo
677 677
         //script
678 678
         wp_register_script(
679 679
             'espresso_reg',
680
-            REG_ASSETS_URL . 'espresso_registrations_admin.js',
680
+            REG_ASSETS_URL.'espresso_registrations_admin.js',
681 681
             array('jquery-ui-datepicker', 'jquery-ui-draggable', 'ee_admin_js'),
682 682
             EVENT_ESPRESSO_VERSION,
683 683
             true
@@ -715,7 +715,7 @@  discard block
 block discarded – undo
715 715
         wp_dequeue_style('espresso_reg');
716 716
         wp_register_style(
717 717
             'espresso_att',
718
-            REG_ASSETS_URL . 'espresso_attendees_admin.css',
718
+            REG_ASSETS_URL.'espresso_attendees_admin.css',
719 719
             array('ee-admin-css'),
720 720
             EVENT_ESPRESSO_VERSION
721 721
         );
@@ -727,7 +727,7 @@  discard block
 block discarded – undo
727 727
     {
728 728
         wp_register_script(
729 729
             'ee-spco-for-admin',
730
-            REG_ASSETS_URL . 'spco_for_admin.js',
730
+            REG_ASSETS_URL.'spco_for_admin.js',
731 731
             array('underscore', 'jquery'),
732 732
             EVENT_ESPRESSO_VERSION,
733 733
             true
@@ -861,7 +861,7 @@  discard block
 block discarded – undo
861 861
                     'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
862 862
                 ),
863 863
             );
864
-            $this->_views['trash']      = array(
864
+            $this->_views['trash'] = array(
865 865
                 'slug'        => 'trash',
866 866
                 'label'       => esc_html__('Trash', 'event_espresso'),
867 867
                 'count'       => 0,
@@ -950,7 +950,7 @@  discard block
 block discarded – undo
950 950
         }
951 951
         $sc_items = array(
952 952
             'approved_status'   => array(
953
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_approved,
953
+                'class' => 'ee-status-legend ee-status-legend-'.EEM_Registration::status_id_approved,
954 954
                 'desc'  => EEH_Template::pretty_status(
955 955
                     EEM_Registration::status_id_approved,
956 956
                     false,
@@ -958,7 +958,7 @@  discard block
 block discarded – undo
958 958
                 ),
959 959
             ),
960 960
             'pending_status'    => array(
961
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_pending_payment,
961
+                'class' => 'ee-status-legend ee-status-legend-'.EEM_Registration::status_id_pending_payment,
962 962
                 'desc'  => EEH_Template::pretty_status(
963 963
                     EEM_Registration::status_id_pending_payment,
964 964
                     false,
@@ -966,7 +966,7 @@  discard block
 block discarded – undo
966 966
                 ),
967 967
             ),
968 968
             'wait_list'         => array(
969
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_wait_list,
969
+                'class' => 'ee-status-legend ee-status-legend-'.EEM_Registration::status_id_wait_list,
970 970
                 'desc'  => EEH_Template::pretty_status(
971 971
                     EEM_Registration::status_id_wait_list,
972 972
                     false,
@@ -974,7 +974,7 @@  discard block
 block discarded – undo
974 974
                 ),
975 975
             ),
976 976
             'incomplete_status' => array(
977
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_incomplete,
977
+                'class' => 'ee-status-legend ee-status-legend-'.EEM_Registration::status_id_incomplete,
978 978
                 'desc'  => EEH_Template::pretty_status(
979 979
                     EEM_Registration::status_id_incomplete,
980 980
                     false,
@@ -982,7 +982,7 @@  discard block
 block discarded – undo
982 982
                 ),
983 983
             ),
984 984
             'not_approved'      => array(
985
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_not_approved,
985
+                'class' => 'ee-status-legend ee-status-legend-'.EEM_Registration::status_id_not_approved,
986 986
                 'desc'  => EEH_Template::pretty_status(
987 987
                     EEM_Registration::status_id_not_approved,
988 988
                     false,
@@ -990,7 +990,7 @@  discard block
 block discarded – undo
990 990
                 ),
991 991
             ),
992 992
             'declined_status'   => array(
993
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_declined,
993
+                'class' => 'ee-status-legend ee-status-legend-'.EEM_Registration::status_id_declined,
994 994
                 'desc'  => EEH_Template::pretty_status(
995 995
                     EEM_Registration::status_id_declined,
996 996
                     false,
@@ -998,7 +998,7 @@  discard block
 block discarded – undo
998 998
                 ),
999 999
             ),
1000 1000
             'cancelled_status'  => array(
1001
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_cancelled,
1001
+                'class' => 'ee-status-legend ee-status-legend-'.EEM_Registration::status_id_cancelled,
1002 1002
                 'desc'  => EEH_Template::pretty_status(
1003 1003
                     EEM_Registration::status_id_cancelled,
1004 1004
                     false,
@@ -1021,7 +1021,7 @@  discard block
 block discarded – undo
1021 1021
         $EVT_ID                                    = ! empty($this->_req_data['event_id'])
1022 1022
             ? absint($this->_req_data['event_id'])
1023 1023
             : 0;
1024
-        $ATT_ID = !empty($this->_req_data['ATT_ID'])
1024
+        $ATT_ID = ! empty($this->_req_data['ATT_ID'])
1025 1025
             ? absint($this->_req_data['ATT_ID'])
1026 1026
             : 0;
1027 1027
         if ($ATT_ID) {
@@ -1033,13 +1033,13 @@  discard block
 block discarded – undo
1033 1033
                         'event_espresso'
1034 1034
                     ),
1035 1035
                     '<h3 style="line-height:1.5em;">',
1036
-                    '<a href="' . EE_Admin_Page::add_query_args_and_nonce(
1036
+                    '<a href="'.EE_Admin_Page::add_query_args_and_nonce(
1037 1037
                         array(
1038 1038
                             'action' => 'edit_attendee',
1039 1039
                             'post' => $ATT_ID
1040 1040
                         ),
1041 1041
                         REG_ADMIN_URL
1042
-                    ) . '">' . $attendee->full_name() . '</a>',
1042
+                    ).'">'.$attendee->full_name().'</a>',
1043 1043
                     '</h3>'
1044 1044
                 );
1045 1045
             }
@@ -1050,7 +1050,7 @@  discard block
 block discarded – undo
1050 1050
                 'espresso_registrations_new_registration',
1051 1051
                 $EVT_ID
1052 1052
             )) {
1053
-                $this->_admin_page_title .= ' ' . $this->get_action_link_or_button(
1053
+                $this->_admin_page_title .= ' '.$this->get_action_link_or_button(
1054 1054
                     'new_registration',
1055 1055
                     'add-registrant',
1056 1056
                     array('event_id' => $EVT_ID),
@@ -1090,7 +1090,7 @@  discard block
 block discarded – undo
1090 1090
                 $this->_template_args['admin_page_header'] .= ' &nbsp;<span class="drk-grey-text">';
1091 1091
                 $this->_template_args['admin_page_header'] .= '<span class="dashicons dashicons-calendar"></span>';
1092 1092
                 $this->_template_args['admin_page_header'] .= $datetime->name();
1093
-                $this->_template_args['admin_page_header'] .= ' ( ' . $datetime->start_date() . ' )';
1093
+                $this->_template_args['admin_page_header'] .= ' ( '.$datetime->start_date().' )';
1094 1094
                 $this->_template_args['admin_page_header'] .= '</span></h3>';
1095 1095
             }
1096 1096
         }
@@ -1197,7 +1197,7 @@  discard block
 block discarded – undo
1197 1197
             'caps'                     => EEM_Registration::caps_read_admin,
1198 1198
             'default_where_conditions' => 'this_model_only',
1199 1199
         );
1200
-        if (! $count) {
1200
+        if ( ! $count) {
1201 1201
             $query_params = array_merge(
1202 1202
                 $query_params,
1203 1203
                 $this->_get_orderby_for_registrations_query(),
@@ -1218,7 +1218,7 @@  discard block
 block discarded – undo
1218 1218
     protected function addAttendeeIdToWhereConditions(array $request)
1219 1219
     {
1220 1220
         $where = array();
1221
-        if (! empty($request['ATT_ID'])) {
1221
+        if ( ! empty($request['ATT_ID'])) {
1222 1222
             $where['ATT_ID'] = absint($request['ATT_ID']);
1223 1223
         }
1224 1224
         return $where;
@@ -1234,7 +1234,7 @@  discard block
 block discarded – undo
1234 1234
     protected function _add_event_id_to_where_conditions(array $request)
1235 1235
     {
1236 1236
         $where = array();
1237
-        if (! empty($request['event_id'])) {
1237
+        if ( ! empty($request['event_id'])) {
1238 1238
             $where['EVT_ID'] = absint($request['event_id']);
1239 1239
         }
1240 1240
         return $where;
@@ -1250,7 +1250,7 @@  discard block
 block discarded – undo
1250 1250
     protected function _add_category_id_to_where_conditions(array $request)
1251 1251
     {
1252 1252
         $where = array();
1253
-        if (! empty($request['EVT_CAT']) && (int)$request['EVT_CAT'] !== -1) {
1253
+        if ( ! empty($request['EVT_CAT']) && (int) $request['EVT_CAT'] !== -1) {
1254 1254
             $where['Event.Term_Taxonomy.term_id'] = absint($request['EVT_CAT']);
1255 1255
         }
1256 1256
         return $where;
@@ -1266,10 +1266,10 @@  discard block
 block discarded – undo
1266 1266
     protected function _add_datetime_id_to_where_conditions(array $request)
1267 1267
     {
1268 1268
         $where = array();
1269
-        if (! empty($request['datetime_id'])) {
1269
+        if ( ! empty($request['datetime_id'])) {
1270 1270
             $where['Ticket.Datetime.DTT_ID'] = absint($request['datetime_id']);
1271 1271
         }
1272
-        if (! empty($request['DTT_ID'])) {
1272
+        if ( ! empty($request['DTT_ID'])) {
1273 1273
             $where['Ticket.Datetime.DTT_ID'] = absint($request['DTT_ID']);
1274 1274
         }
1275 1275
         return $where;
@@ -1295,7 +1295,7 @@  discard block
 block discarded – undo
1295 1295
          * If not filtering by specified status, then we show all registrations excluding incomplete registrations
1296 1296
          * UNLESS viewing trashed registrations.
1297 1297
          */
1298
-        if (! empty($registration_status)) {
1298
+        if ( ! empty($registration_status)) {
1299 1299
             $where['STS_ID'] = $registration_status;
1300 1300
         } else {
1301 1301
             //make sure we exclude incomplete registrations, but only if not trashed.
@@ -1338,12 +1338,12 @@  discard block
 block discarded – undo
1338 1338
                 array(
1339 1339
                     EEM_Registration::instance()->convert_datetime_for_query(
1340 1340
                         'REG_date',
1341
-                        $now . ' 00:00:00',
1341
+                        $now.' 00:00:00',
1342 1342
                         'Y-m-d H:i:s'
1343 1343
                     ),
1344 1344
                     EEM_Registration::instance()->convert_datetime_for_query(
1345 1345
                         'REG_date',
1346
-                        $now . ' 23:59:59',
1346
+                        $now.' 23:59:59',
1347 1347
                         'Y-m-d H:i:s'
1348 1348
                     ),
1349 1349
                 ),
@@ -1356,12 +1356,12 @@  discard block
 block discarded – undo
1356 1356
                 array(
1357 1357
                     EEM_Registration::instance()->convert_datetime_for_query(
1358 1358
                         'REG_date',
1359
-                        $current_year_and_month . '-01 00:00:00',
1359
+                        $current_year_and_month.'-01 00:00:00',
1360 1360
                         'Y-m-d H:i:s'
1361 1361
                     ),
1362 1362
                     EEM_Registration::instance()->convert_datetime_for_query(
1363 1363
                         'REG_date',
1364
-                        $current_year_and_month . '-' . $days_this_month . ' 23:59:59',
1364
+                        $current_year_and_month.'-'.$days_this_month.' 23:59:59',
1365 1365
                         'Y-m-d H:i:s'
1366 1366
                     ),
1367 1367
                 ),
@@ -1376,18 +1376,18 @@  discard block
 block discarded – undo
1376 1376
                 : '';
1377 1377
             //if there is not a month or year then we can't go further
1378 1378
             if ($month_requested && $year_requested) {
1379
-                $days_in_month     = date('t', strtotime($year_requested . '-' . $month_requested . '-' . '01'));
1379
+                $days_in_month     = date('t', strtotime($year_requested.'-'.$month_requested.'-'.'01'));
1380 1380
                 $where['REG_date'] = array(
1381 1381
                     'BETWEEN',
1382 1382
                     array(
1383 1383
                         EEM_Registration::instance()->convert_datetime_for_query(
1384 1384
                             'REG_date',
1385
-                            $year_requested . '-' . $month_requested . '-01 00:00:00',
1385
+                            $year_requested.'-'.$month_requested.'-01 00:00:00',
1386 1386
                             'Y-m-d H:i:s'
1387 1387
                         ),
1388 1388
                         EEM_Registration::instance()->convert_datetime_for_query(
1389 1389
                             'REG_date',
1390
-                            $year_requested . '-' . $month_requested . '-' . $days_in_month . ' 23:59:59',
1390
+                            $year_requested.'-'.$month_requested.'-'.$days_in_month.' 23:59:59',
1391 1391
                             'Y-m-d H:i:s'
1392 1392
                         ),
1393 1393
                     ),
@@ -1407,8 +1407,8 @@  discard block
 block discarded – undo
1407 1407
     protected function _add_search_to_where_conditions(array $request)
1408 1408
     {
1409 1409
         $where = array();
1410
-        if (! empty($request['s'])) {
1411
-            $search_string = '%' . sanitize_text_field($request['s']) . '%';
1410
+        if ( ! empty($request['s'])) {
1411
+            $search_string = '%'.sanitize_text_field($request['s']).'%';
1412 1412
             $where['OR*search_conditions'] = array(
1413 1413
                 'Event.EVT_name'                          => array('LIKE', $search_string),
1414 1414
                 'Event.EVT_desc'                          => array('LIKE', $search_string),
@@ -1525,7 +1525,7 @@  discard block
 block discarded – undo
1525 1525
             : $per_page;
1526 1526
 
1527 1527
         //-1 means return all results so get out if that's set.
1528
-        if ((int)$per_page === -1) {
1528
+        if ((int) $per_page === -1) {
1529 1529
             return array();
1530 1530
         }
1531 1531
         $per_page = absint($per_page);
@@ -1581,7 +1581,7 @@  discard block
 block discarded – undo
1581 1581
                 ),
1582 1582
                 REG_ADMIN_URL
1583 1583
             );
1584
-            $this->_template_args['filtered_transactions_link']  = EE_Admin_Page::add_query_args_and_nonce(
1584
+            $this->_template_args['filtered_transactions_link'] = EE_Admin_Page::add_query_args_and_nonce(
1585 1585
                 array(
1586 1586
                     'action' => 'default',
1587 1587
                     'EVT_ID' => $event_id,
@@ -1589,7 +1589,7 @@  discard block
 block discarded – undo
1589 1589
                 ),
1590 1590
                 admin_url('admin.php')
1591 1591
             );
1592
-            $this->_template_args['event_link']                  = EE_Admin_Page::add_query_args_and_nonce(
1592
+            $this->_template_args['event_link'] = EE_Admin_Page::add_query_args_and_nonce(
1593 1593
                 array(
1594 1594
                     'page'   => 'espresso_events',
1595 1595
                     'action' => 'edit',
@@ -1598,12 +1598,12 @@  discard block
 block discarded – undo
1598 1598
                 admin_url('admin.php')
1599 1599
             );
1600 1600
             //next and previous links
1601
-            $next_reg                                      = $this->_registration->next(
1601
+            $next_reg = $this->_registration->next(
1602 1602
                 null,
1603 1603
                 array(),
1604 1604
                 'REG_ID'
1605 1605
             );
1606
-            $this->_template_args['next_registration']     = $next_reg
1606
+            $this->_template_args['next_registration'] = $next_reg
1607 1607
                 ? $this->_next_link(
1608 1608
                     EE_Admin_Page::add_query_args_and_nonce(
1609 1609
                         array(
@@ -1615,7 +1615,7 @@  discard block
 block discarded – undo
1615 1615
                     'dashicons dashicons-arrow-right ee-icon-size-22'
1616 1616
                 )
1617 1617
                 : '';
1618
-            $previous_reg                                  = $this->_registration->previous(
1618
+            $previous_reg = $this->_registration->previous(
1619 1619
                 null,
1620 1620
                 array(),
1621 1621
                 'REG_ID'
@@ -1633,7 +1633,7 @@  discard block
 block discarded – undo
1633 1633
                 )
1634 1634
                 : '';
1635 1635
             // grab header
1636
-            $template_path                             = REG_TEMPLATE_PATH . 'reg_admin_details_header.template.php';
1636
+            $template_path                             = REG_TEMPLATE_PATH.'reg_admin_details_header.template.php';
1637 1637
             $this->_template_args['REG_ID']            = $this->_registration->ID();
1638 1638
             $this->_template_args['admin_page_header'] = EEH_Template::display_template(
1639 1639
                 $template_path,
@@ -1753,7 +1753,7 @@  discard block
 block discarded – undo
1753 1753
                             EEH_HTML::strong(
1754 1754
                                 $this->_registration->pretty_status(),
1755 1755
                                 '',
1756
-                                'status-' . $this->_registration->status_ID(),
1756
+                                'status-'.$this->_registration->status_ID(),
1757 1757
                                 'line-height: 1em; font-size: 1.5em; font-weight: bold;'
1758 1758
                             )
1759 1759
                         )
@@ -1833,11 +1833,11 @@  discard block
 block discarded – undo
1833 1833
     {
1834 1834
         if (isset($this->_req_data['reg_status_change_form'])) {
1835 1835
             $REG_IDs = isset($this->_req_data['reg_status_change_form']['REG_ID'])
1836
-                ? (array)$this->_req_data['reg_status_change_form']['REG_ID']
1836
+                ? (array) $this->_req_data['reg_status_change_form']['REG_ID']
1837 1837
                 : array();
1838 1838
         } else {
1839 1839
             $REG_IDs = isset($this->_req_data['_REG_ID'])
1840
-                ? (array)$this->_req_data['_REG_ID']
1840
+                ? (array) $this->_req_data['_REG_ID']
1841 1841
                 : array();
1842 1842
         }
1843 1843
         // sanitize $REG_IDs
@@ -1900,7 +1900,7 @@  discard block
 block discarded – undo
1900 1900
     {
1901 1901
         $success = false;
1902 1902
         // typecast $REG_IDs
1903
-        $REG_IDs = (array)$REG_IDs;
1903
+        $REG_IDs = (array) $REG_IDs;
1904 1904
         if ( ! empty($REG_IDs)) {
1905 1905
             $success = true;
1906 1906
             // set default status if none is passed
@@ -2050,7 +2050,7 @@  discard block
 block discarded – undo
2050 2050
             $action,
2051 2051
             $notify
2052 2052
         );
2053
-        $method = $action . '_registration';
2053
+        $method = $action.'_registration';
2054 2054
         if (method_exists($this, $method)) {
2055 2055
             $this->$method($notify);
2056 2056
         }
@@ -2168,7 +2168,7 @@  discard block
 block discarded – undo
2168 2168
             $filtered_line_item_tree,
2169 2169
             array('EE_Registration' => $this->_registration)
2170 2170
         );
2171
-        $attendee                                = $this->_registration->attendee();
2171
+        $attendee = $this->_registration->attendee();
2172 2172
         if (EE_Registry::instance()->CAP->current_user_can(
2173 2173
             'ee_read_transaction',
2174 2174
             'espresso_transactions_view_transaction'
@@ -2247,7 +2247,7 @@  discard block
 block discarded – undo
2247 2247
                 'Payment method response',
2248 2248
                 'event_espresso'
2249 2249
             );
2250
-            $this->_template_args['reg_details']['response_msg']['class']   = 'regular-text';
2250
+            $this->_template_args['reg_details']['response_msg']['class'] = 'regular-text';
2251 2251
         }
2252 2252
         $this->_template_args['reg_details']['registration_session']['value'] = $reg_details['registration_session'];
2253 2253
         $this->_template_args['reg_details']['registration_session']['label'] = esc_html__(
@@ -2275,7 +2275,7 @@  discard block
 block discarded – undo
2275 2275
         $this->_template_args['REG_ID']                                       = $this->_registration->ID();
2276 2276
         $this->_template_args['event_id']                                     = $this->_registration->event_ID();
2277 2277
         $template_path                                                        =
2278
-            REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_reg_details.template.php';
2278
+            REG_TEMPLATE_PATH.'reg_admin_details_main_meta_box_reg_details.template.php';
2279 2279
         echo EEH_Template::display_template($template_path, $this->_template_args, true);
2280 2280
     }
2281 2281
 
@@ -2304,7 +2304,7 @@  discard block
 block discarded – undo
2304 2304
             $this->_template_args['reg_questions_form_action'] = 'edit_registration';
2305 2305
             $this->_template_args['REG_ID']                    = $this->_registration->ID();
2306 2306
             $template_path                                     =
2307
-                REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_reg_questions.template.php';
2307
+                REG_TEMPLATE_PATH.'reg_admin_details_main_meta_box_reg_questions.template.php';
2308 2308
             echo EEH_Template::display_template($template_path, $this->_template_args, true);
2309 2309
         }
2310 2310
     }
@@ -2321,7 +2321,7 @@  discard block
 block discarded – undo
2321 2321
     public function form_before_question_group($output)
2322 2322
     {
2323 2323
         EE_Error::doing_it_wrong(
2324
-            __CLASS__ . '::' . __FUNCTION__,
2324
+            __CLASS__.'::'.__FUNCTION__,
2325 2325
             esc_html__(
2326 2326
                 'This method would have been protected but was used on a filter callback so needed to be public. Please discontinue usage as it will be removed soon.',
2327 2327
                 'event_espresso'
@@ -2346,7 +2346,7 @@  discard block
 block discarded – undo
2346 2346
     public function form_after_question_group($output)
2347 2347
     {
2348 2348
         EE_Error::doing_it_wrong(
2349
-            __CLASS__ . '::' . __FUNCTION__,
2349
+            __CLASS__.'::'.__FUNCTION__,
2350 2350
             esc_html__(
2351 2351
                 'This method would have been protected but was used on a filter callback so needed to be public. Please discontinue usage as it will be removed soon.',
2352 2352
                 'event_espresso'
@@ -2384,7 +2384,7 @@  discard block
 block discarded – undo
2384 2384
     public function form_form_field_label_wrap($label)
2385 2385
     {
2386 2386
         EE_Error::doing_it_wrong(
2387
-            __CLASS__ . '::' . __FUNCTION__,
2387
+            __CLASS__.'::'.__FUNCTION__,
2388 2388
             esc_html__(
2389 2389
                 'This method would have been protected but was used on a filter callback so needed to be public. Please discontinue usage as it will be removed soon.',
2390 2390
                 'event_espresso'
@@ -2394,7 +2394,7 @@  discard block
 block discarded – undo
2394 2394
         return '
2395 2395
 			<tr>
2396 2396
 				<th>
2397
-					' . $label . '
2397
+					' . $label.'
2398 2398
 				</th>';
2399 2399
     }
2400 2400
 
@@ -2410,7 +2410,7 @@  discard block
 block discarded – undo
2410 2410
     public function form_form_field_input__wrap($input)
2411 2411
     {
2412 2412
         EE_Error::doing_it_wrong(
2413
-            __CLASS__ . '::' . __FUNCTION__,
2413
+            __CLASS__.'::'.__FUNCTION__,
2414 2414
             esc_html__(
2415 2415
                 'This method would have been protected but was used on a filter callback so needed to be public. Please discontinue usage as it will be removed soon.',
2416 2416
                 'event_espresso'
@@ -2419,7 +2419,7 @@  discard block
 block discarded – undo
2419 2419
         );
2420 2420
         return '
2421 2421
 				<td class="reg-admin-attendee-questions-input-td disabled-input">
2422
-					' . $input . '
2422
+					' . $input.'
2423 2423
 				</td>
2424 2424
 			</tr>';
2425 2425
     }
@@ -2464,7 +2464,7 @@  discard block
 block discarded – undo
2464 2464
     protected function _get_reg_custom_questions_form($REG_ID)
2465 2465
     {
2466 2466
         if ( ! $this->_reg_custom_questions_form) {
2467
-            require_once(REG_ADMIN . 'form_sections' . DS . 'EE_Registration_Custom_Questions_Form.form.php');
2467
+            require_once(REG_ADMIN.'form_sections'.DS.'EE_Registration_Custom_Questions_Form.form.php');
2468 2468
             $this->_reg_custom_questions_form = new EE_Registration_Custom_Questions_Form(
2469 2469
                 EEM_Registration::instance()->get_one_by_ID($REG_ID)
2470 2470
             );
@@ -2500,7 +2500,7 @@  discard block
 block discarded – undo
2500 2500
         if ($form->is_valid()) {
2501 2501
             foreach ($form->subforms() as $question_group_id => $question_group_form) {
2502 2502
                 foreach ($question_group_form->inputs() as $question_id => $input) {
2503
-                    $where_conditions    = array(
2503
+                    $where_conditions = array(
2504 2504
                         'QST_ID' => $question_id,
2505 2505
                         'REG_ID' => $REG_ID,
2506 2506
                     );
@@ -2541,7 +2541,7 @@  discard block
 block discarded – undo
2541 2541
         $REG = EEM_Registration::instance();
2542 2542
         //get all other registrations on this transaction, and cache
2543 2543
         //the attendees for them so we don't have to run another query using force_join
2544
-        $registrations                           = $REG->get_all(array(
2544
+        $registrations = $REG->get_all(array(
2545 2545
             array(
2546 2546
                 'TXN_ID' => $this->_registration->transaction_ID(),
2547 2547
                 'REG_ID' => array('!=', $this->_registration->ID()),
@@ -2565,7 +2565,7 @@  discard block
 block discarded – undo
2565 2565
             $att_nmbr = 1;
2566 2566
             foreach ($registrations as $registration) {
2567 2567
                 /* @var $registration EE_Registration */
2568
-                $attendee                                                    = $registration->attendee()
2568
+                $attendee = $registration->attendee()
2569 2569
                     ? $registration->attendee()
2570 2570
                     : EEM_Attendee::instance()
2571 2571
                                   ->create_default_object();
@@ -2578,19 +2578,19 @@  discard block
 block discarded – undo
2578 2578
                     ', ',
2579 2579
                     $attendee->full_address_as_array()
2580 2580
                 );
2581
-                $this->_template_args['attendees'][$att_nmbr]['att_link']    = self::add_query_args_and_nonce(
2581
+                $this->_template_args['attendees'][$att_nmbr]['att_link'] = self::add_query_args_and_nonce(
2582 2582
                     array(
2583 2583
                         'action' => 'edit_attendee',
2584 2584
                         'post'   => $attendee->ID(),
2585 2585
                     ),
2586 2586
                     REG_ADMIN_URL
2587 2587
                 );
2588
-                $this->_template_args['attendees'][$att_nmbr]['event_name']  = $registration->event_obj()->name();
2588
+                $this->_template_args['attendees'][$att_nmbr]['event_name'] = $registration->event_obj()->name();
2589 2589
                 $att_nmbr++;
2590 2590
             }
2591 2591
             $this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
2592 2592
         }
2593
-        $template_path = REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_attendees.template.php';
2593
+        $template_path = REG_TEMPLATE_PATH.'reg_admin_details_main_meta_box_attendees.template.php';
2594 2594
         echo EEH_Template::display_template($template_path, $this->_template_args, true);
2595 2595
     }
2596 2596
 
@@ -2633,20 +2633,20 @@  discard block
 block discarded – undo
2633 2633
         $this->_template_args['phone']             = $attendee->phone();
2634 2634
         $this->_template_args['formatted_address'] = EEH_Address::format($attendee);
2635 2635
         //edit link
2636
-        $this->_template_args['att_edit_link']  = EE_Admin_Page::add_query_args_and_nonce(array(
2636
+        $this->_template_args['att_edit_link'] = EE_Admin_Page::add_query_args_and_nonce(array(
2637 2637
             'action' => 'edit_attendee',
2638 2638
             'post'   => $attendee->ID(),
2639 2639
         ), REG_ADMIN_URL);
2640 2640
         $this->_template_args['att_edit_label'] = esc_html__('View/Edit Contact', 'event_espresso');
2641 2641
         //create link
2642
-        $this->_template_args['create_link']  = $primary_registration instanceof EE_Registration
2642
+        $this->_template_args['create_link'] = $primary_registration instanceof EE_Registration
2643 2643
             ? EE_Admin_Page::add_query_args_and_nonce(array(
2644 2644
                 'action'  => 'duplicate_attendee',
2645 2645
                 '_REG_ID' => $this->_registration->ID(),
2646 2646
             ), REG_ADMIN_URL) : '';
2647 2647
         $this->_template_args['create_label'] = esc_html__('Create Contact', 'event_espresso');
2648 2648
         $this->_template_args['att_check']    = $att_check;
2649
-        $template_path                        = REG_TEMPLATE_PATH . 'reg_admin_details_side_meta_box_registrant.template.php';
2649
+        $template_path                        = REG_TEMPLATE_PATH.'reg_admin_details_side_meta_box_registrant.template.php';
2650 2650
         echo EEH_Template::display_template($template_path, $this->_template_args, true);
2651 2651
     }
2652 2652
 
@@ -2691,7 +2691,7 @@  discard block
 block discarded – undo
2691 2691
             /** @var EE_Registration $REG */
2692 2692
             $REG = EEM_Registration::instance()->get_one_by_ID($REG_ID);
2693 2693
             $payments = $REG->registration_payments();
2694
-            if (! empty($payments)) {
2694
+            if ( ! empty($payments)) {
2695 2695
                 $name = $REG->attendee() instanceof EE_Attendee
2696 2696
                     ? $REG->attendee()->full_name()
2697 2697
                     : esc_html__('Unknown Attendee', 'event_espresso');
@@ -2887,7 +2887,7 @@  discard block
 block discarded – undo
2887 2887
                 'action' => 'edit',
2888 2888
                 'post'   => $this->_reg_event->ID(),
2889 2889
             ), EVENTS_ADMIN_URL);
2890
-            $edit_event_lnk                     = '<a href="'
2890
+            $edit_event_lnk = '<a href="'
2891 2891
                                                   . $edit_event_url
2892 2892
                                                   . '" title="'
2893 2893
                                                   . esc_attr__('Edit ', 'event_espresso')
@@ -2905,7 +2905,7 @@  discard block
 block discarded – undo
2905 2905
         }
2906 2906
         // grab header
2907 2907
         $template_path                              =
2908
-            REG_TEMPLATE_PATH . 'reg_admin_register_new_attendee.template.php';
2908
+            REG_TEMPLATE_PATH.'reg_admin_register_new_attendee.template.php';
2909 2909
         $this->_template_args['admin_page_content'] = EEH_Template::display_template($template_path,
2910 2910
             $this->_template_args, true);
2911 2911
         //$this->_set_publish_post_box_vars( NULL, FALSE, FALSE, NULL, FALSE );
@@ -2943,7 +2943,7 @@  discard block
 block discarded – undo
2943 2943
                 '</b>'
2944 2944
             );
2945 2945
             return '
2946
-	<div id="ee-add-reg-back-button-dv"><p>' . $warning_msg . '</p></div>
2946
+	<div id="ee-add-reg-back-button-dv"><p>' . $warning_msg.'</p></div>
2947 2947
 	<script >
2948 2948
 		// WHOAH !!! it appears that someone is using the back button from the Transaction admin page
2949 2949
 		// after just adding a new registration... we gotta try to put a stop to that !!!
@@ -3011,7 +3011,7 @@  discard block
 block discarded – undo
3011 3011
         //we come back to the process_registration_step route.
3012 3012
         $this->_set_add_edit_form_tags('process_reg_step', $hidden_fields);
3013 3013
         return EEH_Template::display_template(
3014
-            REG_TEMPLATE_PATH . 'reg_admin_register_new_attendee_step_content.template.php',
3014
+            REG_TEMPLATE_PATH.'reg_admin_register_new_attendee_step_content.template.php',
3015 3015
             $template_args,
3016 3016
             true
3017 3017
         );
@@ -3033,7 +3033,7 @@  discard block
 block discarded – undo
3033 3033
         if (is_object($this->_reg_event)) {
3034 3034
             return true;
3035 3035
         }
3036
-        $EVT_ID = (! empty($this->_req_data['event_id'])) ? absint($this->_req_data['event_id']) : false;
3036
+        $EVT_ID = ( ! empty($this->_req_data['event_id'])) ? absint($this->_req_data['event_id']) : false;
3037 3037
         if ( ! $EVT_ID) {
3038 3038
             return false;
3039 3039
         }
@@ -3103,7 +3103,7 @@  discard block
 block discarded – undo
3103 3103
                 }
3104 3104
                 break;
3105 3105
             case 'questions' :
3106
-                if (! isset(
3106
+                if ( ! isset(
3107 3107
                     $this->_req_data['txn_reg_status_change'],
3108 3108
                     $this->_req_data['txn_reg_status_change']['send_notifications'])
3109 3109
                 ) {
@@ -3223,7 +3223,7 @@  discard block
 block discarded – undo
3223 3223
     public function get_attendees($per_page, $count = false, $trash = false)
3224 3224
     {
3225 3225
         do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3226
-        require_once(REG_ADMIN . 'EE_Attendee_Contact_List_Table.class.php');
3226
+        require_once(REG_ADMIN.'EE_Attendee_Contact_List_Table.class.php');
3227 3227
         $ATT_MDL                    = EEM_Attendee::instance();
3228 3228
         $this->_req_data['orderby'] = ! empty($this->_req_data['orderby']) ? $this->_req_data['orderby'] : '';
3229 3229
         switch ($this->_req_data['orderby']) {
@@ -3263,7 +3263,7 @@  discard block
 block discarded – undo
3263 3263
             : $per_page;
3264 3264
         $_where       = array();
3265 3265
         if ( ! empty($this->_req_data['s'])) {
3266
-            $sstr         = '%' . $this->_req_data['s'] . '%';
3266
+            $sstr         = '%'.$this->_req_data['s'].'%';
3267 3267
             $_where['OR'] = array(
3268 3268
                 'Registration.Event.EVT_name'       => array('LIKE', $sstr),
3269 3269
                 'Registration.Event.EVT_desc'       => array('LIKE', $sstr),
@@ -3290,17 +3290,17 @@  discard block
 block discarded – undo
3290 3290
             'extra_selects' => array('Registration_Count' => array('Registration.REG_ID', 'count', '%d')),
3291 3291
             'limit' => $limit
3292 3292
         );
3293
-        if (! $count) {
3293
+        if ( ! $count) {
3294 3294
             $query_args['order_by'] = array($orderby => $sort);
3295 3295
         }
3296 3296
         if ($trash) {
3297 3297
             $query_args[0]['status'] = array('!=', 'publish');
3298
-            $all_attendees    = $count
3298
+            $all_attendees = $count
3299 3299
                 ? $ATT_MDL->count($query_args, 'ATT_ID', true)
3300 3300
                 : $ATT_MDL->get_all($query_args);
3301 3301
         } else {
3302 3302
             $query_args[0]['status'] = array('IN', array('publish'));
3303
-            $all_attendees    = $count
3303
+            $all_attendees = $count
3304 3304
                 ? $ATT_MDL->count($query_args, 'ATT_ID', true)
3305 3305
                 : $ATT_MDL->get_all($query_args);
3306 3306
         }
@@ -3330,9 +3330,9 @@  discard block
 block discarded – undo
3330 3330
      *                                                     the query parameters from the request
3331 3331
      * @return void ends the request with a redirect or download
3332 3332
      */
3333
-    public function _registrations_report_base( $method_name_for_getting_query_params )
3333
+    public function _registrations_report_base($method_name_for_getting_query_params)
3334 3334
     {
3335
-        if (! defined('EE_USE_OLD_CSV_REPORT_CLASS')) {
3335
+        if ( ! defined('EE_USE_OLD_CSV_REPORT_CLASS')) {
3336 3336
             wp_redirect(EE_Admin_Page::add_query_args_and_nonce(
3337 3337
                 array(
3338 3338
                     'page'        => 'espresso_batch',
@@ -3341,7 +3341,7 @@  discard block
 block discarded – undo
3341 3341
                     'filters'     => urlencode(
3342 3342
                         serialize(
3343 3343
                             call_user_func(
3344
-                                array( $this, $method_name_for_getting_query_params ),
3344
+                                array($this, $method_name_for_getting_query_params),
3345 3345
                                 EEH_Array::is_set(
3346 3346
                                     $this->_req_data,
3347 3347
                                     'filters',
@@ -3361,8 +3361,8 @@  discard block
 block discarded – undo
3361 3361
                 'EVT_ID' => isset($this->_req_data['EVT_ID']) ? $this->_req_data['EVT_ID'] : null,
3362 3362
             );
3363 3363
             $this->_req_data = array_merge($this->_req_data, $new_request_args);
3364
-            if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3365
-                require_once(EE_CLASSES . 'EE_Export.class.php');
3364
+            if (is_readable(EE_CLASSES.'EE_Export.class.php')) {
3365
+                require_once(EE_CLASSES.'EE_Export.class.php');
3366 3366
                 $EE_Export = EE_Export::instance($this->_req_data);
3367 3367
                 $EE_Export->export();
3368 3368
             }
@@ -3383,8 +3383,8 @@  discard block
 block discarded – undo
3383 3383
 
3384 3384
     public function _contact_list_export()
3385 3385
     {
3386
-        if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3387
-            require_once(EE_CLASSES . 'EE_Export.class.php');
3386
+        if (is_readable(EE_CLASSES.'EE_Export.class.php')) {
3387
+            require_once(EE_CLASSES.'EE_Export.class.php');
3388 3388
             $EE_Export = EE_Export::instance($this->_req_data);
3389 3389
             $EE_Export->export_attendees();
3390 3390
         }
@@ -3401,8 +3401,8 @@  discard block
 block discarded – undo
3401 3401
                 'return_url'  => urlencode($this->_req_data['return_url']),
3402 3402
             )));
3403 3403
         } else {
3404
-            if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3405
-                require_once(EE_CLASSES . 'EE_Export.class.php');
3404
+            if (is_readable(EE_CLASSES.'EE_Export.class.php')) {
3405
+                require_once(EE_CLASSES.'EE_Export.class.php');
3406 3406
                 $EE_Export = EE_Export::instance($this->_req_data);
3407 3407
                 $EE_Export->report_attendees();
3408 3408
             }
@@ -3484,7 +3484,7 @@  discard block
 block discarded – undo
3484 3484
             $updated_fields = array(
3485 3485
                 'ATT_fname'     => $this->_req_data['ATT_fname'],
3486 3486
                 'ATT_lname'     => $this->_req_data['ATT_lname'],
3487
-                'ATT_full_name' => $this->_req_data['ATT_fname'] . ' ' . $this->_req_data['ATT_lname'],
3487
+                'ATT_full_name' => $this->_req_data['ATT_fname'].' '.$this->_req_data['ATT_lname'],
3488 3488
                 'ATT_address'   => isset($this->_req_data['ATT_address']) ? $this->_req_data['ATT_address'] : '',
3489 3489
                 'ATT_address2'  => isset($this->_req_data['ATT_address2']) ? $this->_req_data['ATT_address2'] : '',
3490 3490
                 'ATT_city'      => isset($this->_req_data['ATT_city']) ? $this->_req_data['ATT_city'] : '',
@@ -3702,8 +3702,8 @@  discard block
 block discarded – undo
3702 3702
                 )
3703 3703
             )
3704 3704
         );
3705
-        $template                             =
3706
-            REG_TEMPLATE_PATH . 'attendee_address_details_metabox_content.template.php';
3705
+        $template =
3706
+            REG_TEMPLATE_PATH.'attendee_address_details_metabox_content.template.php';
3707 3707
         EEH_Template::display_template($template, $this->_template_args);
3708 3708
     }
3709 3709
 
@@ -3722,7 +3722,7 @@  discard block
 block discarded – undo
3722 3722
         $this->_template_args['attendee']      = $this->_cpt_model_obj;
3723 3723
         $this->_template_args['registrations'] = $this->_cpt_model_obj->get_many_related('Registration');
3724 3724
         $template                              =
3725
-            REG_TEMPLATE_PATH . 'attendee_registrations_main_meta_box.template.php';
3725
+            REG_TEMPLATE_PATH.'attendee_registrations_main_meta_box.template.php';
3726 3726
         EEH_Template::display_template($template, $this->_template_args);
3727 3727
     }
3728 3728
 
@@ -3737,7 +3737,7 @@  discard block
 block discarded – undo
3737 3737
     public function after_title_form_fields($post)
3738 3738
     {
3739 3739
         if ($post->post_type == 'espresso_attendees') {
3740
-            $template                  = REG_TEMPLATE_PATH . 'attendee_details_after_title_form_fields.template.php';
3740
+            $template                  = REG_TEMPLATE_PATH.'attendee_details_after_title_form_fields.template.php';
3741 3741
             $template_args['attendee'] = $this->_cpt_model_obj;
3742 3742
             EEH_Template::display_template($template, $template_args);
3743 3743
         }
Please login to merge, or discard this patch.
core/services/Benchmark.php 2 patches
Indentation   +304 added lines, -304 removed lines patch added patch discarded remove patch
@@ -20,310 +20,310 @@
 block discarded – undo
20 20
 class Benchmark
21 21
 {
22 22
 
23
-    /**
24
-     * array containing the start time for the timers
25
-     */
26
-    private static $start_times;
27
-
28
-    /**
29
-     * array containing all the timer'd times, which can be outputted via show_times()
30
-     */
31
-    private static $times = array();
32
-
33
-    /**
34
-     * @var array
35
-     */
36
-    protected static $memory_usage = array();
37
-
38
-
39
-
40
-    /**
41
-     * whether to benchmark code or not
42
-     */
43
-    public static function doNotRun()
44
-    {
45
-        return ! WP_DEBUG || (defined('DOING_AJAX') && DOING_AJAX);
46
-    }
47
-
48
-
49
-
50
-    /**
51
-     * resetTimes
52
-     */
53
-    public static function resetTimes()
54
-    {
55
-        Benchmark::$times = array();
56
-    }
57
-
58
-
59
-
60
-    /**
61
-     * Add Benchmark::startTimer() before a block of code you want to measure the performance of
62
-     *
63
-     * @param null $timer_name
64
-     */
65
-    public static function startTimer($timer_name = null)
66
-    {
67
-        if (Benchmark::doNotRun()) {
68
-            return;
69
-        }
70
-        $timer_name = $timer_name !== '' ? $timer_name : get_called_class();
71
-        Benchmark::$start_times[$timer_name] = microtime(true);
72
-    }
73
-
74
-
75
-
76
-    /**
77
-     * Add Benchmark::stopTimer() after a block of code you want to measure the performance of
78
-     *
79
-     * @param string $timer_name
80
-     */
81
-    public static function stopTimer($timer_name = '')
82
-    {
83
-        if (Benchmark::doNotRun()) {
84
-            return;
85
-        }
86
-        $timer_name = $timer_name !== '' ? $timer_name : get_called_class();
87
-        if (isset(Benchmark::$start_times[$timer_name])) {
88
-            $start_time = Benchmark::$start_times[$timer_name];
89
-            unset(Benchmark::$start_times[$timer_name]);
90
-        } else {
91
-            $start_time = array_pop(Benchmark::$start_times);
92
-        }
93
-        Benchmark::$times[$timer_name] = number_format(microtime(true) - $start_time, 8);
94
-    }
95
-
96
-
97
-
98
-    /**
99
-     * Measure the memory usage by PHP so far.
100
-     *
101
-     * @param string  $label      The label to show for this time eg "Start of calling Some_Class::some_function"
102
-     * @param boolean $output_now whether to echo now, or wait until EEH_Debug_Tools::show_times() is called
103
-     * @param bool    $formatted
104
-     * @return void
105
-     */
106
-    public static function measureMemory($label = 'memory usage', $output_now = false, $formatted = true)
107
-    {
108
-        if (Benchmark::doNotRun()) {
109
-            return;
110
-        }
111
-        $memory_used = Benchmark::convert(memory_get_usage(true));
112
-        Benchmark::$memory_usage[$label] = $memory_used;
113
-        if ($output_now) {
114
-            echo $formatted
115
-                ? "<br>{$label} : {$memory_used}"
116
-                : "\n {$label} : {$memory_used}";
117
-        }
118
-    }
119
-
120
-
121
-
122
-    /**
123
-     * will display the benchmarking results at shutdown
124
-     *
125
-     * @param bool $formatted
126
-     * @return void
127
-     */
128
-    public static function displayResultsAtShutdown($formatted = true)
129
-    {
130
-        add_action(
131
-            'shutdown',
132
-            function () use ($formatted) {
133
-                Benchmark::displayResults(true, $formatted);
134
-            }
135
-        );
136
-    }
137
-
138
-
139
-
140
-    /**
141
-     * will display the benchmarking results at shutdown
142
-     *
143
-     * @param string $filepath
144
-     * @param bool   $formatted
145
-     * @param bool   $append
146
-     * @return void
147
-     */
148
-    public static function writeResultsAtShutdown($filepath = '', $formatted = true, $append = true)
149
-    {
150
-        add_action(
151
-            'shutdown',
152
-            function () use ($filepath, $formatted, $append) {
153
-                Benchmark::writeResultsToFile($filepath, $formatted, $append);
154
-            }
155
-        );
156
-    }
157
-
158
-
159
-
160
-    /**
161
-     * @param bool $formatted
162
-     * @return string
163
-     */
164
-    private static function generateResults($formatted = true)
165
-    {
166
-        if (Benchmark::doNotRun()) {
167
-            return '';
168
-        }
169
-        $output = '';
170
-        if (! empty(Benchmark::$times)) {
171
-            $total = 0;
172
-            $output .= $formatted
173
-                ? '<span style="color:#999999; font-size:.8em;">( time in milliseconds )</span><br />'
174
-                : '';
175
-            foreach (Benchmark::$times as $timer_name => $total_time) {
176
-                $output .= Benchmark::formatTime($timer_name, $total_time, $formatted);
177
-                $output .= $formatted ? '<br />'  : "\n";
178
-                $total += $total_time;
179
-            }
180
-            if($formatted) {
181
-                $output .= '<br />';
182
-                $output .= '<h4>TOTAL TIME</h4>';
183
-                $output .= Benchmark::formatTime('', $total, $formatted);
184
-                $output .= '<span style="color:#999999; font-size:.8em;"> milliseconds</span><br />';
185
-                $output .= '<br />';
186
-                $output .= '<h5>Performance scale (from best to worse)</h5>';
187
-                $output .= '<span style="color:mediumpurple">Like wow! How about a Scooby snack?</span><br />';
188
-                $output .= '<span style="color:deepskyblue">Like...no way man!</span><br />';
189
-                $output .= '<span style="color:limegreen">Like...groovy!</span><br />';
190
-                $output .= '<span style="color:gold">Ruh Oh</span><br />';
191
-                $output .= '<span style="color:darkorange">Zoinks!</span><br />';
192
-                $output .= '<span style="color:red">Like...HEEELLLP</span><br />';
193
-            }
194
-        }
195
-        if (! empty(Benchmark::$memory_usage)) {
196
-            $output .= $formatted
197
-                ? '<h5>Memory</h5>'
198
-                : "\nMemory";
199
-            foreach (Benchmark::$memory_usage as $label => $memory_usage) {
200
-                $output .= $formatted
201
-                    ? '<br />'
202
-                    : "\n";
203
-                $output .= "{$memory_usage} : {$label}";
204
-            }
205
-        }
206
-        if (empty($output)) {
207
-            return '';
208
-        }
209
-        $output = $formatted
210
-            ? '<div style="border:1px solid #dddddd; background-color:#ffffff;'
211
-              . (is_admin()
212
-                ? ' margin:2em 2em 2em 180px;'
213
-                : ' margin:2em;')
214
-              . ' padding:2em;">'
215
-              . '<h4>BENCHMARKING</h4>'
216
-              . $output
217
-              . '</div>'
218
-            : $output;
219
-        return $output;
220
-    }
221
-
222
-
223
-
224
-    /**
225
-     * @param bool $echo
226
-     * @param bool $formatted
227
-     * @return string
228
-     */
229
-    public static function displayResults($echo = true, $formatted = true)
230
-    {
231
-        $results = Benchmark::generateResults($formatted);
232
-        if ($echo) {
233
-            echo $results;
234
-            $results = '';
235
-        }
236
-        return $results;
237
-    }
238
-
239
-
240
-    /**
241
-     * @param string $filepath
242
-     * @param bool   $formatted
243
-     * @param bool   $append
244
-     * @throws EE_Error
245
-     */
246
-    public static function writeResultsToFile($filepath = '', $formatted = true, $append = true)
247
-    {
248
-        $filepath = ! empty($filepath) && is_readable(dirname($filepath))
249
-            ? $filepath
250
-            : '';
251
-        if( empty($filepath)) {
252
-            $filepath = EVENT_ESPRESSO_UPLOAD_DIR . 'logs/benchmarking-' . date('Y-m-d') . '.html';
253
-        }
254
-        EEH_File::ensure_file_exists_and_is_writable($filepath);
255
-        file_put_contents(
256
-            $filepath,
257
-            "\n" . date('Y-m-d H:i:s') . Benchmark::generateResults($formatted),
258
-            $append ? FILE_APPEND | LOCK_EX : LOCK_EX
259
-        );
260
-    }
261
-
262
-
263
-
264
-    /**
265
-     * Converts a measure of memory bytes into the most logical units (eg kb, mb, etc)
266
-     *
267
-     * @param int $size
268
-     * @return string
269
-     */
270
-    public static function convert($size)
271
-    {
272
-        $unit = array('b', 'kb', 'mb', 'gb', 'tb', 'pb');
273
-        return round(
274
-            $size / pow(1024, $i = floor(log($size, 1024))),
275
-            2
276
-        ) . ' ' . $unit[absint($i)];
277
-    }
278
-
279
-
280
-
281
-    /**
282
-     * @param string $timer_name
283
-     * @param float  $total_time
284
-     * @param bool   $formatted
285
-     * @return string
286
-     */
287
-    public static function formatTime($timer_name, $total_time, $formatted = true)
288
-    {
289
-        $total_time *= 1000;
290
-        switch ($total_time) {
291
-            case $total_time > 12500 :
292
-                $color = 'red';
293
-                $bold = 'bold';
294
-                break;
295
-            case $total_time > 2500 :
296
-                $color = 'darkorange';
297
-                $bold = 'bold';
298
-                break;
299
-            case $total_time > 500 :
300
-                $color = 'gold';
301
-                $bold = 'bold';
302
-                break;
303
-            case $total_time > 100 :
304
-                $color = 'limegreen';
305
-                $bold = 'normal';
306
-                break;
307
-            case $total_time > 20 :
308
-                $color = 'deepskyblue';
309
-                $bold = 'normal';
310
-                break;
311
-            default :
312
-                $color = 'mediumpurple';
313
-                $bold = 'normal';
314
-                break;
315
-        }
316
-        return $formatted
317
-            ? '<span style="min-width: 10px; margin:0 1em; color:'
318
-               . $color
319
-               . '; font-weight:'
320
-               . $bold
321
-               . '; font-size:1.2em;">'
322
-               . str_pad(number_format($total_time, 3), 9, '0', STR_PAD_LEFT)
323
-               . '</span> '
324
-               . $timer_name
325
-            :  str_pad(number_format($total_time, 3), 9, '0', STR_PAD_LEFT);
326
-    }
23
+	/**
24
+	 * array containing the start time for the timers
25
+	 */
26
+	private static $start_times;
27
+
28
+	/**
29
+	 * array containing all the timer'd times, which can be outputted via show_times()
30
+	 */
31
+	private static $times = array();
32
+
33
+	/**
34
+	 * @var array
35
+	 */
36
+	protected static $memory_usage = array();
37
+
38
+
39
+
40
+	/**
41
+	 * whether to benchmark code or not
42
+	 */
43
+	public static function doNotRun()
44
+	{
45
+		return ! WP_DEBUG || (defined('DOING_AJAX') && DOING_AJAX);
46
+	}
47
+
48
+
49
+
50
+	/**
51
+	 * resetTimes
52
+	 */
53
+	public static function resetTimes()
54
+	{
55
+		Benchmark::$times = array();
56
+	}
57
+
58
+
59
+
60
+	/**
61
+	 * Add Benchmark::startTimer() before a block of code you want to measure the performance of
62
+	 *
63
+	 * @param null $timer_name
64
+	 */
65
+	public static function startTimer($timer_name = null)
66
+	{
67
+		if (Benchmark::doNotRun()) {
68
+			return;
69
+		}
70
+		$timer_name = $timer_name !== '' ? $timer_name : get_called_class();
71
+		Benchmark::$start_times[$timer_name] = microtime(true);
72
+	}
73
+
74
+
75
+
76
+	/**
77
+	 * Add Benchmark::stopTimer() after a block of code you want to measure the performance of
78
+	 *
79
+	 * @param string $timer_name
80
+	 */
81
+	public static function stopTimer($timer_name = '')
82
+	{
83
+		if (Benchmark::doNotRun()) {
84
+			return;
85
+		}
86
+		$timer_name = $timer_name !== '' ? $timer_name : get_called_class();
87
+		if (isset(Benchmark::$start_times[$timer_name])) {
88
+			$start_time = Benchmark::$start_times[$timer_name];
89
+			unset(Benchmark::$start_times[$timer_name]);
90
+		} else {
91
+			$start_time = array_pop(Benchmark::$start_times);
92
+		}
93
+		Benchmark::$times[$timer_name] = number_format(microtime(true) - $start_time, 8);
94
+	}
95
+
96
+
97
+
98
+	/**
99
+	 * Measure the memory usage by PHP so far.
100
+	 *
101
+	 * @param string  $label      The label to show for this time eg "Start of calling Some_Class::some_function"
102
+	 * @param boolean $output_now whether to echo now, or wait until EEH_Debug_Tools::show_times() is called
103
+	 * @param bool    $formatted
104
+	 * @return void
105
+	 */
106
+	public static function measureMemory($label = 'memory usage', $output_now = false, $formatted = true)
107
+	{
108
+		if (Benchmark::doNotRun()) {
109
+			return;
110
+		}
111
+		$memory_used = Benchmark::convert(memory_get_usage(true));
112
+		Benchmark::$memory_usage[$label] = $memory_used;
113
+		if ($output_now) {
114
+			echo $formatted
115
+				? "<br>{$label} : {$memory_used}"
116
+				: "\n {$label} : {$memory_used}";
117
+		}
118
+	}
119
+
120
+
121
+
122
+	/**
123
+	 * will display the benchmarking results at shutdown
124
+	 *
125
+	 * @param bool $formatted
126
+	 * @return void
127
+	 */
128
+	public static function displayResultsAtShutdown($formatted = true)
129
+	{
130
+		add_action(
131
+			'shutdown',
132
+			function () use ($formatted) {
133
+				Benchmark::displayResults(true, $formatted);
134
+			}
135
+		);
136
+	}
137
+
138
+
139
+
140
+	/**
141
+	 * will display the benchmarking results at shutdown
142
+	 *
143
+	 * @param string $filepath
144
+	 * @param bool   $formatted
145
+	 * @param bool   $append
146
+	 * @return void
147
+	 */
148
+	public static function writeResultsAtShutdown($filepath = '', $formatted = true, $append = true)
149
+	{
150
+		add_action(
151
+			'shutdown',
152
+			function () use ($filepath, $formatted, $append) {
153
+				Benchmark::writeResultsToFile($filepath, $formatted, $append);
154
+			}
155
+		);
156
+	}
157
+
158
+
159
+
160
+	/**
161
+	 * @param bool $formatted
162
+	 * @return string
163
+	 */
164
+	private static function generateResults($formatted = true)
165
+	{
166
+		if (Benchmark::doNotRun()) {
167
+			return '';
168
+		}
169
+		$output = '';
170
+		if (! empty(Benchmark::$times)) {
171
+			$total = 0;
172
+			$output .= $formatted
173
+				? '<span style="color:#999999; font-size:.8em;">( time in milliseconds )</span><br />'
174
+				: '';
175
+			foreach (Benchmark::$times as $timer_name => $total_time) {
176
+				$output .= Benchmark::formatTime($timer_name, $total_time, $formatted);
177
+				$output .= $formatted ? '<br />'  : "\n";
178
+				$total += $total_time;
179
+			}
180
+			if($formatted) {
181
+				$output .= '<br />';
182
+				$output .= '<h4>TOTAL TIME</h4>';
183
+				$output .= Benchmark::formatTime('', $total, $formatted);
184
+				$output .= '<span style="color:#999999; font-size:.8em;"> milliseconds</span><br />';
185
+				$output .= '<br />';
186
+				$output .= '<h5>Performance scale (from best to worse)</h5>';
187
+				$output .= '<span style="color:mediumpurple">Like wow! How about a Scooby snack?</span><br />';
188
+				$output .= '<span style="color:deepskyblue">Like...no way man!</span><br />';
189
+				$output .= '<span style="color:limegreen">Like...groovy!</span><br />';
190
+				$output .= '<span style="color:gold">Ruh Oh</span><br />';
191
+				$output .= '<span style="color:darkorange">Zoinks!</span><br />';
192
+				$output .= '<span style="color:red">Like...HEEELLLP</span><br />';
193
+			}
194
+		}
195
+		if (! empty(Benchmark::$memory_usage)) {
196
+			$output .= $formatted
197
+				? '<h5>Memory</h5>'
198
+				: "\nMemory";
199
+			foreach (Benchmark::$memory_usage as $label => $memory_usage) {
200
+				$output .= $formatted
201
+					? '<br />'
202
+					: "\n";
203
+				$output .= "{$memory_usage} : {$label}";
204
+			}
205
+		}
206
+		if (empty($output)) {
207
+			return '';
208
+		}
209
+		$output = $formatted
210
+			? '<div style="border:1px solid #dddddd; background-color:#ffffff;'
211
+			  . (is_admin()
212
+				? ' margin:2em 2em 2em 180px;'
213
+				: ' margin:2em;')
214
+			  . ' padding:2em;">'
215
+			  . '<h4>BENCHMARKING</h4>'
216
+			  . $output
217
+			  . '</div>'
218
+			: $output;
219
+		return $output;
220
+	}
221
+
222
+
223
+
224
+	/**
225
+	 * @param bool $echo
226
+	 * @param bool $formatted
227
+	 * @return string
228
+	 */
229
+	public static function displayResults($echo = true, $formatted = true)
230
+	{
231
+		$results = Benchmark::generateResults($formatted);
232
+		if ($echo) {
233
+			echo $results;
234
+			$results = '';
235
+		}
236
+		return $results;
237
+	}
238
+
239
+
240
+	/**
241
+	 * @param string $filepath
242
+	 * @param bool   $formatted
243
+	 * @param bool   $append
244
+	 * @throws EE_Error
245
+	 */
246
+	public static function writeResultsToFile($filepath = '', $formatted = true, $append = true)
247
+	{
248
+		$filepath = ! empty($filepath) && is_readable(dirname($filepath))
249
+			? $filepath
250
+			: '';
251
+		if( empty($filepath)) {
252
+			$filepath = EVENT_ESPRESSO_UPLOAD_DIR . 'logs/benchmarking-' . date('Y-m-d') . '.html';
253
+		}
254
+		EEH_File::ensure_file_exists_and_is_writable($filepath);
255
+		file_put_contents(
256
+			$filepath,
257
+			"\n" . date('Y-m-d H:i:s') . Benchmark::generateResults($formatted),
258
+			$append ? FILE_APPEND | LOCK_EX : LOCK_EX
259
+		);
260
+	}
261
+
262
+
263
+
264
+	/**
265
+	 * Converts a measure of memory bytes into the most logical units (eg kb, mb, etc)
266
+	 *
267
+	 * @param int $size
268
+	 * @return string
269
+	 */
270
+	public static function convert($size)
271
+	{
272
+		$unit = array('b', 'kb', 'mb', 'gb', 'tb', 'pb');
273
+		return round(
274
+			$size / pow(1024, $i = floor(log($size, 1024))),
275
+			2
276
+		) . ' ' . $unit[absint($i)];
277
+	}
278
+
279
+
280
+
281
+	/**
282
+	 * @param string $timer_name
283
+	 * @param float  $total_time
284
+	 * @param bool   $formatted
285
+	 * @return string
286
+	 */
287
+	public static function formatTime($timer_name, $total_time, $formatted = true)
288
+	{
289
+		$total_time *= 1000;
290
+		switch ($total_time) {
291
+			case $total_time > 12500 :
292
+				$color = 'red';
293
+				$bold = 'bold';
294
+				break;
295
+			case $total_time > 2500 :
296
+				$color = 'darkorange';
297
+				$bold = 'bold';
298
+				break;
299
+			case $total_time > 500 :
300
+				$color = 'gold';
301
+				$bold = 'bold';
302
+				break;
303
+			case $total_time > 100 :
304
+				$color = 'limegreen';
305
+				$bold = 'normal';
306
+				break;
307
+			case $total_time > 20 :
308
+				$color = 'deepskyblue';
309
+				$bold = 'normal';
310
+				break;
311
+			default :
312
+				$color = 'mediumpurple';
313
+				$bold = 'normal';
314
+				break;
315
+		}
316
+		return $formatted
317
+			? '<span style="min-width: 10px; margin:0 1em; color:'
318
+			   . $color
319
+			   . '; font-weight:'
320
+			   . $bold
321
+			   . '; font-size:1.2em;">'
322
+			   . str_pad(number_format($total_time, 3), 9, '0', STR_PAD_LEFT)
323
+			   . '</span> '
324
+			   . $timer_name
325
+			:  str_pad(number_format($total_time, 3), 9, '0', STR_PAD_LEFT);
326
+	}
327 327
 
328 328
 
329 329
 
Please login to merge, or discard this patch.
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -129,7 +129,7 @@  discard block
 block discarded – undo
129 129
     {
130 130
         add_action(
131 131
             'shutdown',
132
-            function () use ($formatted) {
132
+            function() use ($formatted) {
133 133
                 Benchmark::displayResults(true, $formatted);
134 134
             }
135 135
         );
@@ -149,7 +149,7 @@  discard block
 block discarded – undo
149 149
     {
150 150
         add_action(
151 151
             'shutdown',
152
-            function () use ($filepath, $formatted, $append) {
152
+            function() use ($filepath, $formatted, $append) {
153 153
                 Benchmark::writeResultsToFile($filepath, $formatted, $append);
154 154
             }
155 155
         );
@@ -167,17 +167,17 @@  discard block
 block discarded – undo
167 167
             return '';
168 168
         }
169 169
         $output = '';
170
-        if (! empty(Benchmark::$times)) {
170
+        if ( ! empty(Benchmark::$times)) {
171 171
             $total = 0;
172 172
             $output .= $formatted
173 173
                 ? '<span style="color:#999999; font-size:.8em;">( time in milliseconds )</span><br />'
174 174
                 : '';
175 175
             foreach (Benchmark::$times as $timer_name => $total_time) {
176 176
                 $output .= Benchmark::formatTime($timer_name, $total_time, $formatted);
177
-                $output .= $formatted ? '<br />'  : "\n";
177
+                $output .= $formatted ? '<br />' : "\n";
178 178
                 $total += $total_time;
179 179
             }
180
-            if($formatted) {
180
+            if ($formatted) {
181 181
                 $output .= '<br />';
182 182
                 $output .= '<h4>TOTAL TIME</h4>';
183 183
                 $output .= Benchmark::formatTime('', $total, $formatted);
@@ -192,7 +192,7 @@  discard block
 block discarded – undo
192 192
                 $output .= '<span style="color:red">Like...HEEELLLP</span><br />';
193 193
             }
194 194
         }
195
-        if (! empty(Benchmark::$memory_usage)) {
195
+        if ( ! empty(Benchmark::$memory_usage)) {
196 196
             $output .= $formatted
197 197
                 ? '<h5>Memory</h5>'
198 198
                 : "\nMemory";
@@ -248,13 +248,13 @@  discard block
 block discarded – undo
248 248
         $filepath = ! empty($filepath) && is_readable(dirname($filepath))
249 249
             ? $filepath
250 250
             : '';
251
-        if( empty($filepath)) {
252
-            $filepath = EVENT_ESPRESSO_UPLOAD_DIR . 'logs/benchmarking-' . date('Y-m-d') . '.html';
251
+        if (empty($filepath)) {
252
+            $filepath = EVENT_ESPRESSO_UPLOAD_DIR.'logs/benchmarking-'.date('Y-m-d').'.html';
253 253
         }
254 254
         EEH_File::ensure_file_exists_and_is_writable($filepath);
255 255
         file_put_contents(
256 256
             $filepath,
257
-            "\n" . date('Y-m-d H:i:s') . Benchmark::generateResults($formatted),
257
+            "\n".date('Y-m-d H:i:s').Benchmark::generateResults($formatted),
258 258
             $append ? FILE_APPEND | LOCK_EX : LOCK_EX
259 259
         );
260 260
     }
@@ -273,7 +273,7 @@  discard block
 block discarded – undo
273 273
         return round(
274 274
             $size / pow(1024, $i = floor(log($size, 1024))),
275 275
             2
276
-        ) . ' ' . $unit[absint($i)];
276
+        ).' '.$unit[absint($i)];
277 277
     }
278 278
 
279 279
 
Please login to merge, or discard this patch.