Completed
Branch more-edtr-ui-fixes (2c574f)
by
unknown
35:48 queued 28:48
created
admin_pages/transactions/Transactions_Admin_Page.core.php 1 patch
Indentation   +2518 added lines, -2518 removed lines patch added patch discarded remove patch
@@ -13,2522 +13,2522 @@
 block discarded – undo
13 13
  */
14 14
 class Transactions_Admin_Page extends EE_Admin_Page
15 15
 {
16
-    /**
17
-     * @var EE_Transaction
18
-     */
19
-    private $_transaction;
20
-
21
-    /**
22
-     * @var EE_Session
23
-     */
24
-    private $_session;
25
-
26
-    /**
27
-     * @var array $_txn_status
28
-     */
29
-    private static $_txn_status;
30
-
31
-    /**
32
-     * @var array $_pay_status
33
-     */
34
-    private static $_pay_status;
35
-
36
-    /**
37
-     * @var array $_existing_reg_payment_REG_IDs
38
-     */
39
-    protected $_existing_reg_payment_REG_IDs;
40
-
41
-
42
-    /**
43
-     *    _init_page_props
44
-     *
45
-     * @return void
46
-     */
47
-    protected function _init_page_props()
48
-    {
49
-        $this->page_slug        = TXN_PG_SLUG;
50
-        $this->page_label       = esc_html__('Transactions', 'event_espresso');
51
-        $this->_admin_base_url  = TXN_ADMIN_URL;
52
-        $this->_admin_base_path = TXN_ADMIN;
53
-    }
54
-
55
-
56
-    /**
57
-     *    _ajax_hooks
58
-     *
59
-     * @return void
60
-     */
61
-    protected function _ajax_hooks()
62
-    {
63
-        // add_action('wp_ajax_espresso_apply_payment', [$this, 'apply_payments_or_refunds']);
64
-        // add_action('wp_ajax_espresso_apply_refund', [$this, 'apply_payments_or_refunds']);
65
-        // add_action('wp_ajax_espresso_delete_payment', [$this, 'delete_payment']);
66
-    }
67
-
68
-
69
-    /**
70
-     *    _define_page_props
71
-     *
72
-     * @return void
73
-     */
74
-    protected function _define_page_props()
75
-    {
76
-        $this->_admin_page_title = $this->page_label;
77
-        $this->_labels           = [
78
-            'buttons' => [
79
-                'add'    => esc_html__('Add New Transaction', 'event_espresso'),
80
-                'edit'   => esc_html__('Edit Transaction', 'event_espresso'),
81
-                'delete' => esc_html__('Delete Transaction', 'event_espresso'),
82
-            ],
83
-        ];
84
-    }
85
-
86
-
87
-    /**
88
-     *        grab url requests and route them
89
-     *
90
-     * @access private
91
-     * @return void
92
-     * @throws EE_Error
93
-     * @throws InvalidArgumentException
94
-     * @throws InvalidDataTypeException
95
-     * @throws InvalidInterfaceException
96
-     */
97
-    public function _set_page_routes()
98
-    {
99
-
100
-        $this->_set_transaction_status_array();
101
-        $TXN_ID = $this->request->getRequestParam('TXN_ID', 0, 'int');
102
-
103
-        $this->_page_routes = [
104
-
105
-            'default' => [
106
-                'func'       => '_transactions_overview_list_table',
107
-                'capability' => 'ee_read_transactions',
108
-            ],
109
-
110
-            'view_transaction' => [
111
-                'func'       => '_transaction_details',
112
-                'capability' => 'ee_read_transaction',
113
-                'obj_id'     => $TXN_ID,
114
-            ],
115
-
116
-            'send_payment_reminder' => [
117
-                'func'       => '_send_payment_reminder',
118
-                'noheader'   => true,
119
-                'capability' => 'ee_send_message',
120
-            ],
121
-
122
-            'espresso_apply_payment' => [
123
-                'func'       => 'apply_payments_or_refunds',
124
-                'noheader'   => true,
125
-                'capability' => 'ee_edit_payments',
126
-            ],
127
-
128
-            'espresso_apply_refund' => [
129
-                'func'       => 'apply_payments_or_refunds',
130
-                'noheader'   => true,
131
-                'capability' => 'ee_edit_payments',
132
-            ],
133
-
134
-            'espresso_delete_payment' => [
135
-                'func'       => [$this, 'delete_payment'],
136
-                'noheader'   => true,
137
-                'capability' => 'ee_delete_payments',
138
-            ],
139
-
140
-            'espresso_recalculate_line_items' => [
141
-                'func'       => 'recalculateLineItems',
142
-                'noheader'   => true,
143
-                'capability' => 'ee_edit_payments',
144
-            ],
145
-
146
-        ];
147
-    }
148
-
149
-
150
-    protected function _set_page_config()
151
-    {
152
-        $TXN_ID = $this->request->getRequestParam('TXN_ID', 0, 'int');
153
-        $this->_page_config = [
154
-            'default'          => [
155
-                'nav'           => [
156
-                    'label' => esc_html__('Overview', 'event_espresso'),
157
-                    'icon' => 'dashicons-list-view',
158
-                    'order' => 10,
159
-                ],
160
-                'list_table'    => 'EE_Admin_Transactions_List_Table',
161
-                'help_tabs'     => [
162
-                    'transactions_overview_help_tab'                       => [
163
-                        'title'    => esc_html__('Transactions Overview', 'event_espresso'),
164
-                        'filename' => 'transactions_overview',
165
-                    ],
166
-                    'transactions_overview_table_column_headings_help_tab' => [
167
-                        'title'    => esc_html__('Transactions Table Column Headings', 'event_espresso'),
168
-                        'filename' => 'transactions_overview_table_column_headings',
169
-                    ],
170
-                    'transactions_overview_views_filters_help_tab'         => [
171
-                        'title'    => esc_html__('Transaction Views & Filters & Search', 'event_espresso'),
172
-                        'filename' => 'transactions_overview_views_filters_search',
173
-                    ],
174
-                ],
175
-                'require_nonce' => false,
176
-            ],
177
-            'view_transaction' => [
178
-                'nav'       => [
179
-                    'label'      => esc_html__('View Transaction', 'event_espresso'),
180
-                    'icon' => 'dashicons-cart',
181
-                    'order'      => 5,
182
-                    'url'        => $TXN_ID
183
-                        ? add_query_arg(['TXN_ID' => $TXN_ID], $this->_current_page_view_url)
184
-                        : $this->_admin_base_url,
185
-                    'persistent' => false,
186
-                ],
187
-                'help_tabs' => [
188
-                    'transactions_view_transaction_help_tab'                                              => [
189
-                        'title'    => esc_html__('View Transaction', 'event_espresso'),
190
-                        'filename' => 'transactions_view_transaction',
191
-                    ],
192
-                    'transactions_view_transaction_transaction_details_table_help_tab'                    => [
193
-                        'title'    => esc_html__('Transaction Details Table', 'event_espresso'),
194
-                        'filename' => 'transactions_view_transaction_transaction_details_table',
195
-                    ],
196
-                    'transactions_view_transaction_attendees_registered_help_tab'                         => [
197
-                        'title'    => esc_html__('Attendees Registered', 'event_espresso'),
198
-                        'filename' => 'transactions_view_transaction_attendees_registered',
199
-                    ],
200
-                    'transactions_view_transaction_views_primary_registrant_billing_information_help_tab' => [
201
-                        'title'    => esc_html__('Primary Registrant & Billing Information', 'event_espresso'),
202
-                        'filename' => 'transactions_view_transaction_primary_registrant_billing_information',
203
-                    ],
204
-                ],
205
-                'qtips'     => ['Transaction_Details_Tips'],
206
-                'metaboxes' => ['_transaction_details_metaboxes'],
207
-
208
-                'require_nonce' => false,
209
-            ],
210
-        ];
211
-    }
212
-
213
-
214
-    /**
215
-     * The below methods aren't used by this class currently
216
-     */
217
-    protected function _add_screen_options()
218
-    {
219
-        // noop
220
-    }
221
-
222
-
223
-    protected function _add_feature_pointers()
224
-    {
225
-        // noop
226
-    }
227
-
228
-
229
-    public function admin_init()
230
-    {
231
-        $EVT_ID = $this->request->getRequestParam('EVT_ID', 0, 'int');
232
-        $event_name = $this->request->getRequestParam('event_name');
233
-        $redirect_from = $this->request->getRequestParam('redirect_from', '', 'url');
234
-        // IF a registration was JUST added via the admin...
235
-        if ($EVT_ID && $event_name && $redirect_from) {
236
-            // then set a cookie so that we can block any attempts to use
237
-            // the back button as a way to enter another registration.
238
-            setcookie('ee_registration_added', $EVT_ID, time() + WEEK_IN_SECONDS, '/');
239
-            // and update the global
240
-            $_COOKIE['ee_registration_added'] = $EVT_ID;
241
-        }
242
-        EE_Registry::$i18n_js_strings['invalid_server_response'] = esc_html__(
243
-            'An error occurred! Your request may have been processed, but a valid response from the server was not received. Please refresh the page and try again.',
244
-            'event_espresso'
245
-        );
246
-        EE_Registry::$i18n_js_strings['error_occurred']          = esc_html__(
247
-            'An error occurred! Please refresh the page and try again.',
248
-            'event_espresso'
249
-        );
250
-        EE_Registry::$i18n_js_strings['txn_status_array']        = self::$_txn_status;
251
-        EE_Registry::$i18n_js_strings['pay_status_array']        = self::$_pay_status;
252
-        EE_Registry::$i18n_js_strings['payments_total']          = esc_html__('Payments Total', 'event_espresso');
253
-        EE_Registry::$i18n_js_strings['transaction_overpaid']    = esc_html__(
254
-            'This transaction has been overpaid ! Payments Total',
255
-            'event_espresso'
256
-        );
257
-    }
258
-
259
-
260
-    public function admin_notices()
261
-    {
262
-        // noop
263
-    }
264
-
265
-
266
-    public function admin_footer_scripts()
267
-    {
268
-        // noop
269
-    }
270
-
271
-
272
-    /**
273
-     * _set_transaction_status_array
274
-     * sets list of transaction statuses
275
-     *
276
-     * @access private
277
-     * @return void
278
-     * @throws EE_Error
279
-     * @throws InvalidArgumentException
280
-     * @throws InvalidDataTypeException
281
-     * @throws InvalidInterfaceException
282
-     */
283
-    private function _set_transaction_status_array()
284
-    {
285
-        self::$_txn_status = EEM_Transaction::instance()->status_array(true);
286
-    }
287
-
288
-
289
-    /**
290
-     * get_transaction_status_array
291
-     * return the transaction status array for wp_list_table
292
-     *
293
-     * @access public
294
-     * @return array
295
-     */
296
-    public function get_transaction_status_array()
297
-    {
298
-        return self::$_txn_status;
299
-    }
300
-
301
-
302
-    /**
303
-     *    get list of payment statuses
304
-     *
305
-     * @access private
306
-     * @return void
307
-     * @throws EE_Error
308
-     * @throws InvalidArgumentException
309
-     * @throws InvalidDataTypeException
310
-     * @throws InvalidInterfaceException
311
-     */
312
-    private function _get_payment_status_array()
313
-    {
314
-        self::$_pay_status                      = EEM_Payment::instance()->status_array(true);
315
-        $this->_template_args['payment_status'] = self::$_pay_status;
316
-    }
317
-
318
-
319
-    /**
320
-     *    _add_screen_options_default
321
-     *
322
-     * @access protected
323
-     * @return void
324
-     * @throws InvalidArgumentException
325
-     * @throws InvalidDataTypeException
326
-     * @throws InvalidInterfaceException
327
-     */
328
-    protected function _add_screen_options_default()
329
-    {
330
-        $this->_per_page_screen_option();
331
-    }
332
-
333
-
334
-    /**
335
-     * load_scripts_styles
336
-     *
337
-     * @access public
338
-     * @return void
339
-     */
340
-    public function load_scripts_styles()
341
-    {
342
-        // enqueue style
343
-        wp_register_style(
344
-            'espresso_txn',
345
-            TXN_ASSETS_URL . 'espresso_transactions_admin.css',
346
-            [],
347
-            EVENT_ESPRESSO_VERSION
348
-        );
349
-        wp_enqueue_style('espresso_txn');
350
-        // scripts
351
-        wp_register_script(
352
-            'espresso_txn',
353
-            TXN_ASSETS_URL . 'espresso_transactions_admin.js',
354
-            [
355
-                'ee_admin_js',
356
-                'ee-datepicker',
357
-                'jquery-ui-datepicker',
358
-                'jquery-ui-draggable',
359
-                'ee-dialog',
360
-                'ee-accounting',
361
-                'ee-serialize-full-array',
362
-            ],
363
-            EVENT_ESPRESSO_VERSION,
364
-            true
365
-        );
366
-        wp_enqueue_script('espresso_txn');
367
-    }
368
-
369
-
370
-    /**
371
-     *    load_scripts_styles_view_transaction
372
-     *
373
-     * @access public
374
-     * @return void
375
-     */
376
-    public function load_scripts_styles_view_transaction()
377
-    {
378
-        // styles
379
-        wp_enqueue_style('espresso-ui-theme');
380
-    }
381
-
382
-
383
-    /**
384
-     *    load_scripts_styles_default
385
-     *
386
-     * @access public
387
-     * @return void
388
-     */
389
-    public function load_scripts_styles_default()
390
-    {
391
-        // styles
392
-        wp_enqueue_style('espresso-ui-theme');
393
-    }
394
-
395
-
396
-    /**
397
-     *    _set_list_table_views_default
398
-     *
399
-     * @access protected
400
-     * @return void
401
-     */
402
-    protected function _set_list_table_views_default()
403
-    {
404
-        $this->_views = [
405
-            'all'        => [
406
-                'slug'  => 'all',
407
-                'label' => esc_html__('View All Transactions', 'event_espresso'),
408
-                'count' => 0,
409
-            ],
410
-            'abandoned'  => [
411
-                'slug'  => 'abandoned',
412
-                'label' => esc_html__('Abandoned Transactions', 'event_espresso'),
413
-                'count' => 0,
414
-            ],
415
-            'incomplete' => [
416
-                'slug'  => 'incomplete',
417
-                'label' => esc_html__('Incomplete Transactions', 'event_espresso'),
418
-                'count' => 0,
419
-            ],
420
-        ];
421
-        if (
422
-            /**
423
-             * Filters whether a link to the "Failed Transactions" list table
424
-             * appears on the Transactions Admin Page list table.
425
-             * List display can be turned back on via the following:
426
-             * add_filter(
427
-             *     'FHEE__Transactions_Admin_Page___set_list_table_views_default__display_failed_txns_list',
428
-             *     '__return_true'
429
-             * );
430
-             *
431
-             * @param boolean                 $display_failed_txns_list
432
-             * @param Transactions_Admin_Page $this
433
-             * @since 4.9.70.p
434
-             */
435
-            apply_filters(
436
-                'FHEE__Transactions_Admin_Page___set_list_table_views_default__display_failed_txns_list',
437
-                false,
438
-                $this
439
-            )
440
-        ) {
441
-            $this->_views['failed'] = [
442
-                'slug'  => 'failed',
443
-                'label' => esc_html__('Failed Transactions', 'event_espresso'),
444
-                'count' => 0,
445
-            ];
446
-        }
447
-    }
448
-
449
-
450
-    /**
451
-     * _set_transaction_object
452
-     * This sets the _transaction property for the transaction details screen
453
-     *
454
-     * @access private
455
-     * @return void
456
-     * @throws EE_Error
457
-     * @throws InvalidArgumentException
458
-     * @throws RuntimeException
459
-     * @throws InvalidDataTypeException
460
-     * @throws InvalidInterfaceException
461
-     * @throws ReflectionException
462
-     */
463
-    private function _set_transaction_object()
464
-    {
465
-        if ($this->_transaction instanceof EE_Transaction) {
466
-            return;
467
-        } //get out we've already set the object
468
-
469
-        $TXN_ID = $this->request->getRequestParam('TXN_ID', 0, 'int');
470
-
471
-        // get transaction object
472
-        $this->_transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
473
-        $this->_session     = $this->_transaction instanceof EE_Transaction
474
-            ? $this->_transaction->session_data()
475
-            : null;
476
-        if ($this->_transaction instanceof EE_Transaction) {
477
-            $this->_transaction->verify_abandoned_transaction_status();
478
-        }
479
-
480
-        if (! $this->_transaction instanceof EE_Transaction) {
481
-            $error_msg = sprintf(
482
-                esc_html__(
483
-                    'An error occurred and the details for the transaction with the ID # %d could not be retrieved.',
484
-                    'event_espresso'
485
-                ),
486
-                $TXN_ID
487
-            );
488
-            EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
489
-        }
490
-    }
491
-
492
-
493
-    /**
494
-     *    _transaction_legend_items
495
-     *
496
-     * @access protected
497
-     * @return array
498
-     * @throws EE_Error
499
-     * @throws InvalidArgumentException
500
-     * @throws ReflectionException
501
-     * @throws InvalidDataTypeException
502
-     * @throws InvalidInterfaceException
503
-     */
504
-    protected function _transaction_legend_items()
505
-    {
506
-        EE_Registry::instance()->load_helper('MSG_Template');
507
-        $items = [];
508
-
509
-        if (
510
-            EE_Registry::instance()->CAP->current_user_can(
511
-                'ee_read_global_messages',
512
-                'view_filtered_messages'
513
-            )
514
-        ) {
515
-            $related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
516
-            if (
517
-                is_array($related_for_icon)
518
-                && isset($related_for_icon['css_class'], $related_for_icon['label'])
519
-            ) {
520
-                $items['view_related_messages'] = [
521
-                    'class' => $related_for_icon['css_class'],
522
-                    'desc'  => $related_for_icon['label'],
523
-                ];
524
-            }
525
-        }
526
-
527
-        $items = apply_filters(
528
-            'FHEE__Transactions_Admin_Page___transaction_legend_items__items',
529
-            array_merge(
530
-                $items,
531
-                [
532
-                    'view_details'          => [
533
-                        'class' => 'dashicons dashicons-cart',
534
-                        'desc'  => esc_html__('View Transaction Details', 'event_espresso'),
535
-                    ],
536
-                    'view_invoice'          => [
537
-                        'class' => 'dashicons dashicons-media-spreadsheet',
538
-                        'desc'  => esc_html__('View Transaction Invoice', 'event_espresso'),
539
-                    ],
540
-                    'view_receipt'          => [
541
-                        'class' => 'dashicons dashicons-text-page',
542
-                        'desc'  => esc_html__('View Transaction Receipt', 'event_espresso'),
543
-                    ],
544
-                    'view_registration'     => [
545
-                        'class' => 'dashicons dashicons-clipboard',
546
-                        'desc'  => esc_html__('View Registration Details', 'event_espresso'),
547
-                    ],
548
-                    'payment_overview_link' => [
549
-                        'class' => 'dashicons dashicons-money',
550
-                        'desc'  => esc_html__('Make Payment on Frontend', 'event_espresso'),
551
-                    ],
552
-                ]
553
-            )
554
-        );
555
-
556
-        if (
557
-            EEH_MSG_Template::is_mt_active('payment_reminder')
558
-            && EE_Registry::instance()->CAP->current_user_can(
559
-                'ee_send_message',
560
-                'espresso_transactions_send_payment_reminder'
561
-            )
562
-        ) {
563
-            $items['send_payment_reminder'] = [
564
-                'class' => 'dashicons dashicons-email-alt',
565
-                'desc'  => esc_html__('Send Payment Reminder', 'event_espresso'),
566
-            ];
567
-        } else {
568
-            $items['blank*'] = [
569
-                'class' => '',
570
-                'desc'  => '',
571
-            ];
572
-        }
573
-        $more_items = apply_filters(
574
-            'FHEE__Transactions_Admin_Page___transaction_legend_items__more_items',
575
-            [
576
-                'overpaid'   => [
577
-                    'class' => 'ee-status-legend ee-status-bg--' . EEM_Transaction::overpaid_status_code,
578
-                    'desc'  => EEH_Template::pretty_status(
579
-                        EEM_Transaction::overpaid_status_code,
580
-                        false,
581
-                        'sentence'
582
-                    ),
583
-                ],
584
-                'complete'   => [
585
-                    'class' => 'ee-status-legend ee-status-bg--' . EEM_Transaction::complete_status_code,
586
-                    'desc'  => EEH_Template::pretty_status(
587
-                        EEM_Transaction::complete_status_code,
588
-                        false,
589
-                        'sentence'
590
-                    ),
591
-                ],
592
-                'incomplete' => [
593
-                    'class' => 'ee-status-legend ee-status-bg--' . EEM_Transaction::incomplete_status_code,
594
-                    'desc'  => EEH_Template::pretty_status(
595
-                        EEM_Transaction::incomplete_status_code,
596
-                        false,
597
-                        'sentence'
598
-                    ),
599
-                ],
600
-                'abandoned'  => [
601
-                    'class' => 'ee-status-legend ee-status-bg--' . EEM_Transaction::abandoned_status_code,
602
-                    'desc'  => EEH_Template::pretty_status(
603
-                        EEM_Transaction::abandoned_status_code,
604
-                        false,
605
-                        'sentence'
606
-                    ),
607
-                ],
608
-                'failed'     => [
609
-                    'class' => 'ee-status-legend ee-status-bg--' . EEM_Transaction::failed_status_code,
610
-                    'desc'  => EEH_Template::pretty_status(
611
-                        EEM_Transaction::failed_status_code,
612
-                        false,
613
-                        'sentence'
614
-                    ),
615
-                ],
616
-            ]
617
-        );
618
-
619
-        return array_merge($items, $more_items);
620
-    }
621
-
622
-
623
-    /**
624
-     *    _transactions_overview_list_table
625
-     *
626
-     * @access protected
627
-     * @return void
628
-     * @throws DomainException
629
-     * @throws EE_Error
630
-     * @throws InvalidArgumentException
631
-     * @throws InvalidDataTypeException
632
-     * @throws InvalidInterfaceException
633
-     * @throws ReflectionException
634
-     */
635
-    protected function _transactions_overview_list_table()
636
-    {
637
-        $this->_admin_page_title = esc_html__('Transactions', 'event_espresso');
638
-
639
-        $EVT_ID = $this->request->getRequestParam('EVT_ID', 0, 'int');
640
-        $event = EEM_Event::instance()->get_one_by_ID($EVT_ID);
641
-        $this->_template_args['admin_page_header'] = $event instanceof EE_Event
642
-            ? sprintf(
643
-                esc_html__('%sViewing Transactions for the Event: %s%s', 'event_espresso'),
644
-                '<h3>',
645
-                '<a href="'
646
-                . EE_Admin_Page::add_query_args_and_nonce(
647
-                    ['action' => 'edit', 'post' => $event->ID()],
648
-                    EVENTS_ADMIN_URL
649
-                )
650
-                . '" title="'
651
-                . esc_attr__('Click to Edit event', 'event_espresso')
652
-                . '">' . $event->name() . '</a>',
653
-                '</h3>'
654
-            )
655
-            : '';
656
-        $this->_template_args['after_list_table']  = $this->_display_legend($this->_transaction_legend_items());
657
-        $this->display_admin_list_table_page_with_no_sidebar();
658
-    }
659
-
660
-
661
-    /**
662
-     *    _transaction_details
663
-     * generates HTML for the View Transaction Details Admin page
664
-     *
665
-     * @access protected
666
-     * @return void
667
-     * @throws DomainException
668
-     * @throws EE_Error
669
-     * @throws InvalidArgumentException
670
-     * @throws InvalidDataTypeException
671
-     * @throws InvalidInterfaceException
672
-     * @throws RuntimeException
673
-     * @throws ReflectionException
674
-     */
675
-    protected function _transaction_details()
676
-    {
677
-        do_action('AHEE__Transactions_Admin_Page__transaction_details__start', $this->_transaction);
678
-
679
-        $this->_set_transaction_status_array();
680
-
681
-        $this->_template_args                      = [];
682
-        $this->_template_args['transactions_page'] = $this->_wp_page_slug;
683
-
684
-        $this->_set_transaction_object();
685
-
686
-        if (! $this->_transaction instanceof EE_Transaction) {
687
-            return;
688
-        }
689
-
690
-        $this->_template_args['txn_nmbr']['value'] = $this->_transaction->ID();
691
-        $this->_template_args['txn_nmbr']['label'] = esc_html__('Transaction Number', 'event_espresso');
692
-
693
-        $this->_template_args['txn_datetime']['value'] = $this->_transaction->get_i18n_datetime('TXN_timestamp');
694
-        $this->_template_args['txn_datetime']['label'] = esc_html__('Date', 'event_espresso');
695
-
696
-        $this->_template_args['txn_status']['value'] = self::$_txn_status[ $this->_transaction->status_ID() ];
697
-        $this->_template_args['txn_status']['label'] = esc_html__('Transaction Status', 'event_espresso');
698
-        $this->_template_args['txn_status']['class'] = $this->_transaction->status_ID();
699
-
700
-        $txn_total  = $this->_transaction->total();
701
-        $total_paid = $this->_transaction->paid();
702
-        $amount_due = $txn_total - $total_paid;
703
-
704
-        $this->_template_args['grand_total'] = $txn_total;
705
-        $this->_template_args['total_paid']  = $total_paid;
706
-
707
-        $this->_template_args['amount_due'] = EEH_Template::format_currency($amount_due, false, false);
708
-
709
-        $this->_template_args['amount_due_class'] = '';
710
-
711
-        if ($txn_total === (float) 0) {
712
-            // free event
713
-            $this->_template_args['amount_due'] = false;
714
-        } elseif ($amount_due < (float) 0) {
715
-            // overpaid
716
-            $this->_template_args['amount_due_class'] = 'txn-overview-no-payment-spn';
717
-        } elseif ($amount_due > (float) 0) {
718
-            // monies owing
719
-            $this->_template_args['amount_due_class'] = 'txn-overview-part-payment-spn ee-txn-amount-owing';
720
-        } elseif ($total_paid === (float) 0) {
721
-            // no payments made yet
722
-            $this->_template_args['amount_due_class'] = 'txn-overview-no-payment-spn';
723
-        }
724
-
725
-        $payment_method = $this->_transaction->payment_method();
726
-
727
-        $this->_template_args['method_of_payment_name'] = $payment_method instanceof EE_Payment_Method
728
-            ? $payment_method->admin_name()
729
-            : esc_html__('Unknown', 'event_espresso');
730
-
731
-        $this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
732
-        // link back to overview
733
-        $this->_template_args['txn_overview_url'] = $this->request->getServerParam(
734
-            'HTTP_REFERER',
735
-            TXN_ADMIN_URL
736
-        );
737
-
738
-
739
-        // next link
740
-        $next_txn                                 = $this->_transaction->next(
741
-            null,
742
-            [['STS_ID' => ['!=', EEM_Transaction::failed_status_code]]],
743
-            'TXN_ID'
744
-        );
745
-        $this->_template_args['next_transaction'] = $next_txn
746
-            ? $this->_next_link(
747
-                EE_Admin_Page::add_query_args_and_nonce(
748
-                    ['action' => 'view_transaction', 'TXN_ID' => $next_txn['TXN_ID']],
749
-                    TXN_ADMIN_URL
750
-                ),
751
-                'dashicons dashicons-arrow-right ee-icon-size-22'
752
-            )
753
-            : '';
754
-        // previous link
755
-        $previous_txn                                 = $this->_transaction->previous(
756
-            null,
757
-            [['STS_ID' => ['!=', EEM_Transaction::failed_status_code]]],
758
-            'TXN_ID'
759
-        );
760
-        $this->_template_args['previous_transaction'] = $previous_txn
761
-            ? $this->_previous_link(
762
-                EE_Admin_Page::add_query_args_and_nonce(
763
-                    ['action' => 'view_transaction', 'TXN_ID' => $previous_txn['TXN_ID']],
764
-                    TXN_ADMIN_URL
765
-                ),
766
-                'dashicons dashicons-arrow-left ee-icon-size-22'
767
-            )
768
-            : '';
769
-
770
-        $EVT_ID        = $this->request->getRequestParam('EVT_ID', 0, 'int');
771
-        $event_name    = $this->request->getRequestParam('event_name');
772
-        $redirect_from = $this->request->getRequestParam('redirect_from', '', 'url');
773
-
774
-        // were we just redirected here after adding a new registration ???
775
-        if ($EVT_ID && $event_name && $redirect_from) {
776
-            if (
777
-                EE_Registry::instance()->CAP->current_user_can(
778
-                    'ee_edit_registrations',
779
-                    'espresso_registrations_new_registration',
780
-                    $EVT_ID
781
-                )
782
-            ) {
783
-                $this->_admin_page_title .= '<a id="add-new-registration" class="add-new-h2 button--primary" href="';
784
-                $this->_admin_page_title .= EE_Admin_Page::add_query_args_and_nonce(
785
-                    [
786
-                        'page'     => 'espresso_registrations',
787
-                        'action'   => 'new_registration',
788
-                        'return'   => 'default',
789
-                        'TXN_ID'   => $this->_transaction->ID(),
790
-                        'event_id' => $EVT_ID,
791
-                    ],
792
-                    REG_ADMIN_URL
793
-                );
794
-                $this->_admin_page_title .= '">';
795
-
796
-                $this->_admin_page_title .= sprintf(
797
-                    esc_html__('Add Another New Registration to Event: "%1$s" ?', 'event_espresso'),
798
-                    htmlentities(urldecode($event_name), ENT_QUOTES, 'UTF-8')
799
-                );
800
-                $this->_admin_page_title .= '</a>';
801
-            }
802
-            EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
803
-        }
804
-        // grab messages at the last second
805
-        $this->_template_args['notices'] = EE_Error::get_notices();
806
-        // path to template
807
-        $template_path                             = TXN_TEMPLATE_PATH . 'txn_admin_details_header.template.php';
808
-        $this->_template_args['admin_page_header'] = EEH_Template::display_template(
809
-            $template_path,
810
-            $this->_template_args,
811
-            true
812
-        );
813
-
814
-        // the details template wrapper
815
-        $this->display_admin_page_with_sidebar();
816
-    }
817
-
818
-
819
-    /**
820
-     *        _transaction_details_metaboxes
821
-     *
822
-     * @access protected
823
-     * @return void
824
-     * @throws EE_Error
825
-     * @throws InvalidArgumentException
826
-     * @throws InvalidDataTypeException
827
-     * @throws InvalidInterfaceException
828
-     * @throws RuntimeException
829
-     * @throws ReflectionException
830
-     */
831
-    protected function _transaction_details_metaboxes()
832
-    {
833
-
834
-        $this->_set_transaction_object();
835
-
836
-        if (! $this->_transaction instanceof EE_Transaction) {
837
-            return;
838
-        }
839
-        $this->addMetaBox(
840
-            'edit-txn-details-mbox',
841
-            '<span>' . esc_html__('Transaction Details', 'event_espresso')
842
-            . '&nbsp;<span class="dashicons dashicons-cart" ></span></span>',
843
-            [$this, 'txn_details_meta_box'],
844
-            $this->_wp_page_slug
845
-        );
846
-        $this->addMetaBox(
847
-            'edit-txn-attendees-mbox',
848
-            '<span>' . esc_html__('Attendees Registered in this Transaction', 'event_espresso')
849
-            . '&nbsp;<span class="dashicons dashicons-groups" ></span></span>',
850
-            [$this, 'txn_attendees_meta_box'],
851
-            $this->_wp_page_slug,
852
-            'normal',
853
-            'high',
854
-            ['TXN_ID' => $this->_transaction->ID()]
855
-        );
856
-        $this->addMetaBox(
857
-            'edit-txn-registrant-mbox',
858
-            esc_html__('Primary Contact', 'event_espresso'),
859
-            [$this, 'txn_registrant_side_meta_box'],
860
-            $this->_wp_page_slug,
861
-            'side'
862
-        );
863
-        $this->addMetaBox(
864
-            'edit-txn-billing-info-mbox',
865
-            esc_html__('Billing Information', 'event_espresso'),
866
-            [$this, 'txn_billing_info_side_meta_box'],
867
-            $this->_wp_page_slug,
868
-            'side'
869
-        );
870
-    }
871
-
872
-
873
-    /**
874
-     * Callback for transaction actions metabox.
875
-     *
876
-     * @param EE_Transaction|null $transaction
877
-     * @return string
878
-     * @throws DomainException
879
-     * @throws EE_Error
880
-     * @throws InvalidArgumentException
881
-     * @throws InvalidDataTypeException
882
-     * @throws InvalidInterfaceException
883
-     * @throws ReflectionException
884
-     * @throws RuntimeException
885
-     */
886
-    public function getActionButtons(EE_Transaction $transaction = null)
887
-    {
888
-        $content = '';
889
-        $actions = [];
890
-        if (! $transaction instanceof EE_Transaction) {
891
-            return $content;
892
-        }
893
-        /** @var EE_Registration $primary_registration */
894
-        $primary_registration = $transaction->primary_registration();
895
-        $attendee             = $primary_registration instanceof EE_Registration
896
-            ? $primary_registration->attendee()
897
-            : null;
898
-
899
-        if (
900
-            $attendee instanceof EE_Attendee
901
-            && EE_Registry::instance()->CAP->current_user_can(
902
-                'ee_send_message',
903
-                'espresso_transactions_send_payment_reminder'
904
-            )
905
-        ) {
906
-            $actions['payment_reminder'] =
907
-                EEH_MSG_Template::is_mt_active('payment_reminder')
908
-                && $this->_transaction->status_ID() !== EEM_Transaction::complete_status_code
909
-                && $this->_transaction->status_ID() !== EEM_Transaction::overpaid_status_code
910
-                    ? EEH_Template::get_button_or_link(
911
-                        EE_Admin_Page::add_query_args_and_nonce(
912
-                            [
913
-                            'action'      => 'send_payment_reminder',
914
-                            'TXN_ID'      => $this->_transaction->ID(),
915
-                            'redirect_to' => 'view_transaction',
916
-                            ],
917
-                            TXN_ADMIN_URL
918
-                        ),
919
-                        esc_html__(' Send Payment Reminder', 'event_espresso'),
920
-                        'button button--secondary',
921
-                        'dashicons dashicons-email-alt'
922
-                    )
923
-                    : '';
924
-        }
925
-
926
-        if (
927
-            EE_Registry::instance()->CAP->current_user_can(
928
-                'ee_edit_payments',
929
-                'espresso_transactions_recalculate_line_items'
930
-            )
931
-        ) {
932
-            $actions['recalculate_line_items'] = EEH_Template::get_button_or_link(
933
-                EE_Admin_Page::add_query_args_and_nonce(
934
-                    [
935
-                        'action'      => 'espresso_recalculate_line_items',
936
-                        'TXN_ID'      => $this->_transaction->ID(),
937
-                        'redirect_to' => 'view_transaction',
938
-                    ],
939
-                    TXN_ADMIN_URL
940
-                ),
941
-                esc_html__(' Recalculate Taxes and Total', 'event_espresso'),
942
-                'button button--secondary',
943
-                'dashicons dashicons-update'
944
-            );
945
-        }
946
-
947
-        if (
948
-            $primary_registration instanceof EE_Registration
949
-            && EEH_MSG_Template::is_mt_active('receipt')
950
-        ) {
951
-            $actions['receipt'] = EEH_Template::get_button_or_link(
952
-                $primary_registration->receipt_url(),
953
-                esc_html__('View Receipt', 'event_espresso'),
954
-                'button button--secondary',
955
-                'dashicons dashicons-text-page'
956
-            );
957
-        }
958
-
959
-        if (
960
-            $primary_registration instanceof EE_Registration
961
-            && EEH_MSG_Template::is_mt_active('invoice')
962
-        ) {
963
-            $actions['invoice'] = EEH_Template::get_button_or_link(
964
-                $primary_registration->invoice_url(),
965
-                esc_html__('View Invoice', 'event_espresso'),
966
-                'button button--secondary',
967
-                'dashicons dashicons-media-spreadsheet'
968
-            );
969
-        }
970
-        $actions = array_filter(
971
-            apply_filters('FHEE__Transactions_Admin_Page__getActionButtons__actions', $actions, $transaction)
972
-        );
973
-        if ($actions) {
974
-            $content .= implode('', $actions);
975
-        }
976
-        return $content;
977
-    }
978
-
979
-
980
-    /**
981
-     * txn_details_meta_box
982
-     * generates HTML for the Transaction main meta box
983
-     *
984
-     * @return void
985
-     * @throws DomainException
986
-     * @throws EE_Error
987
-     * @throws InvalidArgumentException
988
-     * @throws InvalidDataTypeException
989
-     * @throws InvalidInterfaceException
990
-     * @throws RuntimeException
991
-     * @throws ReflectionException
992
-     */
993
-    public function txn_details_meta_box()
994
-    {
995
-        $this->_set_transaction_object();
996
-        $this->_template_args['TXN_ID']              = $this->_transaction->ID();
997
-        $this->_template_args['attendee']            =
998
-            $this->_transaction->primary_registration() instanceof EE_Registration
999
-                ? $this->_transaction->primary_registration()->attendee()
1000
-                : null;
1001
-        $this->_template_args['can_edit_payments']   = EE_Registry::instance()->CAP->current_user_can(
1002
-            'ee_edit_payments',
1003
-            'apply_payment_or_refund_from_registration_details'
1004
-        );
1005
-        $this->_template_args['can_delete_payments'] = EE_Registry::instance()->CAP->current_user_can(
1006
-            'ee_delete_payments',
1007
-            'delete_payment_from_registration_details'
1008
-        );
1009
-
1010
-        // get line table
1011
-        EEH_Autoloader::register_line_item_display_autoloaders();
1012
-        $Line_Item_Display                       = new EE_Line_Item_Display(
1013
-            'admin_table',
1014
-            'EE_Admin_Table_Line_Item_Display_Strategy'
1015
-        );
1016
-        $this->_template_args['line_item_table'] = $Line_Item_Display->display_line_item(
1017
-            $this->_transaction->total_line_item()
1018
-        );
1019
-        $this->_template_args['REG_code']        =
1020
-            $this->_transaction->primary_registration() instanceof EE_Registration
1021
-                ? $this->_transaction->primary_registration()->reg_code()
1022
-                : null;
1023
-        // process taxes
1024
-        $taxes                         = $this->_transaction->line_items([['LIN_type' => EEM_Line_Item::type_tax]]);
1025
-        $this->_template_args['taxes'] = ! empty($taxes) ? $taxes : false;
1026
-
1027
-        $this->_template_args['grand_total']     = EEH_Template::format_currency(
1028
-            $this->_transaction->total(),
1029
-            false,
1030
-            false
1031
-        );
1032
-        $this->_template_args['grand_raw_total'] = $this->_transaction->total();
1033
-        $this->_template_args['TXN_status']      = $this->_transaction->status_ID();
1034
-
1035
-        // process payment details
1036
-        $payments = $this->_transaction->payments();
1037
-        if (! empty($payments)) {
1038
-            $this->_template_args['payments']              = $payments;
1039
-            $this->_template_args['existing_reg_payments'] = $this->_get_registration_payment_IDs($payments);
1040
-        } else {
1041
-            $this->_template_args['payments']              = false;
1042
-            $this->_template_args['existing_reg_payments'] = [];
1043
-        }
1044
-
1045
-        $this->_template_args['edit_payment_url']   = add_query_arg(['action' => 'edit_payment'], TXN_ADMIN_URL);
1046
-        $this->_template_args['delete_payment_url'] = add_query_arg(
1047
-            ['action' => 'espresso_delete_payment'],
1048
-            TXN_ADMIN_URL
1049
-        );
1050
-
1051
-        if (isset($txn_details['invoice_number'])) {
1052
-            $this->_template_args['txn_details']['invoice_number']['value'] = $this->_template_args['REG_code'];
1053
-            $this->_template_args['txn_details']['invoice_number']['label'] = esc_html__(
1054
-                'Invoice Number',
1055
-                'event_espresso'
1056
-            );
1057
-        }
1058
-
1059
-        $this->_template_args['txn_details']['registration_session']['value'] =
1060
-            $this->_transaction->primary_registration() instanceof EE_Registration
1061
-                ? $this->_transaction->primary_registration()->session_ID()
1062
-                : null;
1063
-        $this->_template_args['txn_details']['registration_session']['label'] = esc_html__(
1064
-            'Registration Session',
1065
-            'event_espresso'
1066
-        );
1067
-
1068
-        $this->_template_args['txn_details']['ip_address']['value'] = $this->_session['ip_address'] ?? '';
1069
-        $this->_template_args['txn_details']['ip_address']['label'] = esc_html__(
1070
-            'Transaction placed from IP',
1071
-            'event_espresso'
1072
-        );
1073
-
1074
-        $this->_template_args['txn_details']['user_agent']['value'] = $this->_session['user_agent'] ?? '';
1075
-        $this->_template_args['txn_details']['user_agent']['label'] = esc_html__(
1076
-            'Registrant User Agent',
1077
-            'event_espresso'
1078
-        );
1079
-
1080
-        $reg_steps = '<div class="ee-txn-reg-step-status-steps ee-layout-row">';
1081
-        foreach ($this->_transaction->reg_steps() as $reg_step => $reg_step_status) {
1082
-            if ($reg_step_status === true) {
1083
-                $reg_steps .= '<div class="ee-status-pill ee-status-bg--success">'
1084
-                              . sprintf(
1085
-                                  esc_html__('%1$s : Completed', 'event_espresso'),
1086
-                                  ucwords(str_replace('_', ' ', $reg_step))
1087
-                              )
1088
-                              . '</div>';
1089
-            } elseif ($reg_step_status !== false && is_numeric($reg_step_status)) {
1090
-                $reg_steps .= '<div class="ee-status-pill ee-status-bg--attention">'
1091
-                              . sprintf(
1092
-                                  esc_html__('%1$s : Initiated %2$s', 'event_espresso'),
1093
-                                  ucwords(str_replace('_', ' ', $reg_step)),
1094
-                                  date(
1095
-                                      get_option('date_format') . ' ' . get_option('time_format'),
1096
-                                      $reg_step_status + (get_option('gmt_offset') * HOUR_IN_SECONDS)
1097
-                                  )
1098
-                              )
1099
-                              . '</div>';
1100
-            } else {
1101
-                $reg_steps .= '<div class="ee-status-pill ee-status-bg--error">'
1102
-                              . sprintf(
1103
-                                  esc_html__('%1$s : Never Initiated', 'event_espresso'),
1104
-                                  ucwords(str_replace('_', ' ', $reg_step))
1105
-                              )
1106
-                              . '</div>';
1107
-            }
1108
-        }
1109
-        $reg_steps                                                 .= '</ul>';
1110
-        $this->_template_args['txn_details']['reg_steps']['value'] = $reg_steps;
1111
-        $this->_template_args['txn_details']['reg_steps']['label'] = esc_html__(
1112
-            'Registration Step Progress',
1113
-            'event_espresso'
1114
-        );
1115
-
1116
-
1117
-        $this->_get_registrations_to_apply_payment_to();
1118
-        $this->_get_payment_methods($payments);
1119
-        $this->_get_payment_status_array();
1120
-        $this->_get_reg_status_selection(); // sets up the template args for the reg status array for the transaction.
1121
-
1122
-        $this->_template_args['transaction_form_url']    = add_query_arg(
1123
-            [
1124
-                'action'  => 'edit_transaction',
1125
-                'process' => 'transaction',
1126
-            ],
1127
-            TXN_ADMIN_URL
1128
-        );
1129
-        $this->_template_args['apply_payment_form_url']  = add_query_arg(
1130
-            [
1131
-                'page'   => 'espresso_transactions',
1132
-                'action' => 'espresso_apply_payment',
1133
-            ],
1134
-            TXN_ADMIN_URL
1135
-        );
1136
-        $this->_template_args['delete_payment_form_url'] = add_query_arg(
1137
-            [
1138
-                'page'   => 'espresso_transactions',
1139
-                'action' => 'espresso_delete_payment',
1140
-            ],
1141
-            TXN_ADMIN_URL
1142
-        );
1143
-
1144
-        $this->_template_args['action_buttons'] = $this->getActionButtons($this->_transaction);
1145
-
1146
-        // 'espresso_delete_payment_nonce'
1147
-
1148
-        $template_path = TXN_TEMPLATE_PATH . 'txn_admin_details_main_meta_box_txn_details.template.php';
1149
-        echo EEH_Template::display_template($template_path, $this->_template_args, true);
1150
-    }
1151
-
1152
-
1153
-    /**
1154
-     * _get_registration_payment_IDs
1155
-     *    generates an array of Payment IDs and their corresponding Registration IDs
1156
-     *
1157
-     * @access protected
1158
-     * @param EE_Payment[] $payments
1159
-     * @return array
1160
-     * @throws EE_Error
1161
-     * @throws InvalidArgumentException
1162
-     * @throws InvalidDataTypeException
1163
-     * @throws InvalidInterfaceException
1164
-     * @throws ReflectionException
1165
-     */
1166
-    protected function _get_registration_payment_IDs($payments = [])
1167
-    {
1168
-        $existing_reg_payments = [];
1169
-        // get all reg payments for these payments
1170
-        $reg_payments = EEM_Registration_Payment::instance()->get_all(
1171
-            [
1172
-                [
1173
-                    'PAY_ID' => [
1174
-                        'IN',
1175
-                        array_keys($payments),
1176
-                    ],
1177
-                ],
1178
-            ]
1179
-        );
1180
-        if (! empty($reg_payments)) {
1181
-            foreach ($payments as $payment) {
1182
-                if (! $payment instanceof EE_Payment) {
1183
-                    continue;
1184
-                } elseif (! isset($existing_reg_payments[ $payment->ID() ])) {
1185
-                    $existing_reg_payments[ $payment->ID() ] = [];
1186
-                }
1187
-                foreach ($reg_payments as $reg_payment) {
1188
-                    if (
1189
-                        $reg_payment instanceof EE_Registration_Payment
1190
-                        && $reg_payment->payment_ID() === $payment->ID()
1191
-                    ) {
1192
-                        $existing_reg_payments[ $payment->ID() ][] = $reg_payment->registration_ID();
1193
-                    }
1194
-                }
1195
-            }
1196
-        }
1197
-
1198
-        return $existing_reg_payments;
1199
-    }
1200
-
1201
-
1202
-    /**
1203
-     * _get_registrations_to_apply_payment_to
1204
-     *    generates HTML for displaying a series of checkboxes in the admin payment modal window
1205
-     * which allows the admin to only apply the payment to the specific registrations
1206
-     *
1207
-     * @access protected
1208
-     * @return void
1209
-     * @throws EE_Error
1210
-     * @throws InvalidArgumentException
1211
-     * @throws InvalidDataTypeException
1212
-     * @throws InvalidInterfaceException
1213
-     * @throws ReflectionException
1214
-     */
1215
-    protected function _get_registrations_to_apply_payment_to()
1216
-    {
1217
-        // we want any registration with an active status (ie: not deleted or cancelled)
1218
-        $query_params                      = [
1219
-            [
1220
-                'STS_ID' => [
1221
-                    'IN',
1222
-                    [
1223
-                        EEM_Registration::status_id_approved,
1224
-                        EEM_Registration::status_id_pending_payment,
1225
-                        EEM_Registration::status_id_not_approved,
1226
-                    ],
1227
-                ],
1228
-            ],
1229
-        ];
1230
-        $registrations_to_apply_payment_to = EEH_HTML::br() . EEH_HTML::div(
1231
-            '',
1232
-            'txn-admin-apply-payment-to-registrations-dv',
1233
-            '',
1234
-            'clear: both; margin: 1.5em 0 0; display: none;'
1235
-        );
1236
-        $registrations_to_apply_payment_to .= EEH_HTML::br() . EEH_HTML::div('', '', 'admin-primary-mbox-tbl-wrap');
1237
-        $registrations_to_apply_payment_to .= EEH_HTML::table('', '', 'admin-primary-mbox-tbl striped');
1238
-        $registrations_to_apply_payment_to .= EEH_HTML::thead(
1239
-            EEH_HTML::tr(
1240
-                EEH_HTML::th(esc_html__('ID', 'event_espresso')) .
1241
-                EEH_HTML::th(esc_html__('Registrant', 'event_espresso')) .
1242
-                EEH_HTML::th(esc_html__('Ticket', 'event_espresso')) .
1243
-                EEH_HTML::th(esc_html__('Event', 'event_espresso')) .
1244
-                EEH_HTML::th(esc_html__('Paid', 'event_espresso'), '', 'txn-admin-payment-paid-td jst-cntr') .
1245
-                EEH_HTML::th(esc_html__('Owing', 'event_espresso'), '', 'txn-admin-payment-owing-td jst-cntr') .
1246
-                EEH_HTML::th(esc_html__('Apply', 'event_espresso'), '', 'jst-cntr')
1247
-            )
1248
-        );
1249
-        $registrations_to_apply_payment_to .= EEH_HTML::tbody();
1250
-        // get registrations for TXN
1251
-        $registrations         = $this->_transaction->registrations($query_params);
1252
-        $existing_reg_payments = $this->_template_args['existing_reg_payments'];
1253
-        foreach ($registrations as $registration) {
1254
-            if ($registration instanceof EE_Registration) {
1255
-                $attendee_name                     = $registration->attendee() instanceof EE_Attendee
1256
-                    ? $registration->attendee()->full_name()
1257
-                    : esc_html__('Unknown Attendee', 'event_espresso');
1258
-                $owing                             = $registration->final_price() - $registration->paid();
1259
-                $taxable                           = $registration->ticket()->taxable()
1260
-                    ? ' <span class="smaller-text lt-grey-text"> ' . esc_html__('+ tax', 'event_espresso') . '</span>'
1261
-                    : '';
1262
-                $checked                           = empty($existing_reg_payments)
1263
-                                                     || in_array($registration->ID(), $existing_reg_payments, true)
1264
-                    ? ' checked'
1265
-                    : '';
1266
-                $disabled                          = $registration->final_price() > 0 ? '' : ' disabled';
1267
-                $registrations_to_apply_payment_to .= EEH_HTML::tr(
1268
-                    EEH_HTML::td($registration->ID()) .
1269
-                    EEH_HTML::td($attendee_name) .
1270
-                    EEH_HTML::td(
1271
-                        $registration->ticket()->name() . ' : ' . $registration->ticket()->pretty_price() . $taxable
1272
-                    ) .
1273
-                    EEH_HTML::td($registration->event_name()) .
1274
-                    EEH_HTML::td($registration->pretty_paid(), '', 'txn-admin-payment-paid-td jst-cntr') .
1275
-                    EEH_HTML::td(
1276
-                        EEH_Template::format_currency($owing),
1277
-                        '',
1278
-                        'txn-admin-payment-owing-td jst-cntr'
1279
-                    ) .
1280
-                    EEH_HTML::td(
1281
-                        '<input type="checkbox" value="' . $registration->ID()
1282
-                        . '" name="txn_admin_payment[registrations]"'
1283
-                        . $checked . $disabled . '>',
1284
-                        '',
1285
-                        'jst-cntr'
1286
-                    ),
1287
-                    'apply-payment-registration-row-' . $registration->ID()
1288
-                );
1289
-            }
1290
-        }
1291
-        $registrations_to_apply_payment_to                         .= EEH_HTML::tbodyx();
1292
-        $registrations_to_apply_payment_to                         .= EEH_HTML::tablex();
1293
-        $registrations_to_apply_payment_to                         .= EEH_HTML::divx();
1294
-        $registrations_to_apply_payment_to                         .= EEH_HTML::p(
1295
-            esc_html__(
1296
-                'The payment will only be applied to the registrations that have a check mark in their corresponding check box. Checkboxes for free registrations have been disabled.',
1297
-                'event_espresso'
1298
-            ),
1299
-            '',
1300
-            'clear description'
1301
-        );
1302
-        $registrations_to_apply_payment_to                         .= EEH_HTML::divx();
1303
-        $this->_template_args['registrations_to_apply_payment_to'] = $registrations_to_apply_payment_to;
1304
-    }
1305
-
1306
-
1307
-    /**
1308
-     * _get_reg_status_selection
1309
-     *
1310
-     * @return void
1311
-     * @throws EE_Error
1312
-     * @todo   this will need to be adjusted either once MER comes along OR we move default reg status to tickets
1313
-     *         instead of events.
1314
-     * @access protected
1315
-     */
1316
-    protected function _get_reg_status_selection()
1317
-    {
1318
-        // first get all possible statuses
1319
-        $statuses = EEM_Registration::reg_status_array([], true);
1320
-        // let's add a "don't change" option.
1321
-        $status_array['NAN']                                 = esc_html__('Leave the Same', 'event_espresso');
1322
-        $status_array                                        = array_merge($status_array, $statuses);
1323
-        $this->_template_args['status_change_select']        = EEH_Form_Fields::select_input(
1324
-            'txn_reg_status_change[reg_status]',
1325
-            $status_array,
1326
-            'NAN',
1327
-            'id="txn-admin-payment-reg-status-inp"',
1328
-            'txn-reg-status-change-reg-status'
1329
-        );
1330
-        $this->_template_args['delete_status_change_select'] = EEH_Form_Fields::select_input(
1331
-            'delete_txn_reg_status_change[reg_status]',
1332
-            $status_array,
1333
-            'NAN',
1334
-            'delete-txn-admin-payment-reg-status-inp',
1335
-            'delete-txn-reg-status-change-reg-status'
1336
-        );
1337
-    }
1338
-
1339
-
1340
-    /**
1341
-     *    _get_payment_methods
1342
-     * Gets all the payment methods available generally, or the ones that are already
1343
-     * selected on these payments (in case their payment methods are no longer active).
1344
-     * Has the side-effect of updating the template args' payment_methods item
1345
-     *
1346
-     * @access private
1347
-     * @param EE_Payment[] to show on this page
1348
-     * @return void
1349
-     * @throws EE_Error
1350
-     * @throws InvalidArgumentException
1351
-     * @throws InvalidDataTypeException
1352
-     * @throws InvalidInterfaceException
1353
-     * @throws ReflectionException
1354
-     */
1355
-    private function _get_payment_methods($payments = [])
1356
-    {
1357
-        $payment_methods_of_payments = [];
1358
-        foreach ($payments as $payment) {
1359
-            if ($payment instanceof EE_Payment) {
1360
-                $payment_methods_of_payments[] = $payment->ID();
1361
-            }
1362
-        }
1363
-        if ($payment_methods_of_payments) {
1364
-            $query_args = [
1365
-                [
1366
-                    'OR*payment_method_for_payment' => [
1367
-                        'PMD_ID'    => ['IN', $payment_methods_of_payments],
1368
-                        'PMD_scope' => ['LIKE', '%' . EEM_Payment_Method::scope_admin . '%'],
1369
-                    ],
1370
-                ],
1371
-            ];
1372
-        } else {
1373
-            $query_args = [['PMD_scope' => ['LIKE', '%' . EEM_Payment_Method::scope_admin . '%']]];
1374
-        }
1375
-        $this->_template_args['payment_methods'] = EEM_Payment_Method::instance()->get_all($query_args);
1376
-    }
1377
-
1378
-
1379
-    /**
1380
-     * txn_attendees_meta_box
1381
-     *    generates HTML for the Attendees Transaction main meta box
1382
-     *
1383
-     * @access public
1384
-     * @param WP_Post $post
1385
-     * @param array   $metabox
1386
-     * @return void
1387
-     * @throws DomainException
1388
-     * @throws EE_Error
1389
-     * @throws InvalidArgumentException
1390
-     * @throws InvalidDataTypeException
1391
-     * @throws InvalidInterfaceException
1392
-     * @throws ReflectionException
1393
-     */
1394
-    public function txn_attendees_meta_box($post, $metabox = ['args' => []])
1395
-    {
1396
-
1397
-        /** @noinspection NonSecureExtractUsageInspection */
1398
-        extract($metabox['args']);
1399
-        $this->_template_args['post']            = $post;
1400
-        $this->_template_args['event_attendees'] = [];
1401
-        // process items in cart
1402
-        $line_items = $this->_transaction->get_many_related(
1403
-            'Line_Item',
1404
-            [['LIN_type' => 'line-item']]
1405
-        );
1406
-        if (! empty($line_items)) {
1407
-            foreach ($line_items as $item) {
1408
-                if ($item instanceof EE_Line_Item) {
1409
-                    switch ($item->OBJ_type()) {
1410
-                        case 'Event':
1411
-                            break;
1412
-                        case 'Ticket':
1413
-                            $ticket = $item->ticket();
1414
-                            // right now we're only handling tickets here.
1415
-                            // Cause its expected that only tickets will have attendees right?
1416
-                            if (! $ticket instanceof EE_Ticket) {
1417
-                                break;
1418
-                            }
1419
-                            try {
1420
-                                $event_name = $ticket->get_event_name();
1421
-                            } catch (Exception $e) {
1422
-                                EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1423
-                                $event_name = esc_html__('Unknown Event', 'event_espresso');
1424
-                            }
1425
-                            $event_name   .= ' - ' . $item->name();
1426
-                            $ticket_price = EEH_Template::format_currency($item->unit_price());
1427
-                            // now get all of the registrations for this transaction that use this ticket
1428
-                            $registrations = $ticket->registrations(
1429
-                                [['TXN_ID' => $this->_transaction->ID()]]
1430
-                            );
1431
-                            foreach ($registrations as $registration) {
1432
-                                if (! $registration instanceof EE_Registration) {
1433
-                                    break;
1434
-                                }
1435
-                                $this->_template_args['event_attendees'][ $registration->ID() ]['STS_ID']
1436
-                                    = $registration->status_ID();
1437
-                                $this->_template_args['event_attendees'][ $registration->ID() ]['att_num']
1438
-                                    = $registration->count();
1439
-                                $this->_template_args['event_attendees'][ $registration->ID() ]['event_ticket_name']
1440
-                                    = $event_name;
1441
-                                $this->_template_args['event_attendees'][ $registration->ID() ]['ticket_price']
1442
-                                    = $ticket_price;
1443
-                                // attendee info
1444
-                                $attendee = $registration->get_first_related('Attendee');
1445
-                                if ($attendee instanceof EE_Attendee) {
1446
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['att_id']
1447
-                                        = $attendee->ID();
1448
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['attendee']
1449
-                                        = $attendee->full_name();
1450
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['email']
1451
-                                        = '<a href="mailto:' . $attendee->email() . '?subject=' . $event_name
1452
-                                          . esc_html__(
1453
-                                              ' Event',
1454
-                                              'event_espresso'
1455
-                                          )
1456
-                                          . '">' . $attendee->email() . '</a>';
1457
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['address']
1458
-                                        = EEH_Address::format($attendee, 'inline', false, false);
1459
-                                } else {
1460
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['att_id']   = '';
1461
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['attendee'] = '';
1462
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['email']    = '';
1463
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['address']  = '';
1464
-                                }
1465
-                            }
1466
-                            break;
1467
-                    }
1468
-                }
1469
-            }
1470
-
1471
-            $this->_template_args['transaction_form_url'] = add_query_arg(
1472
-                [
1473
-                    'action'  => 'edit_transaction',
1474
-                    'process' => 'attendees',
1475
-                ],
1476
-                TXN_ADMIN_URL
1477
-            );
1478
-            echo EEH_Template::display_template(
1479
-                TXN_TEMPLATE_PATH . 'txn_admin_details_main_meta_box_attendees.template.php',
1480
-                $this->_template_args,
1481
-                true
1482
-            );
1483
-        } else {
1484
-            printf(
1485
-                esc_html__(
1486
-                    '%1$sFor some reason, there are no attendees registered for this transaction. Likely the registration was abandoned in process.%2$s',
1487
-                    'event_espresso'
1488
-                ),
1489
-                '<p class="important-notice">',
1490
-                '</p>'
1491
-            );
1492
-        }
1493
-    }
1494
-
1495
-
1496
-    /**
1497
-     * txn_registrant_side_meta_box
1498
-     * generates HTML for the Edit Transaction side meta box
1499
-     *
1500
-     * @access public
1501
-     * @return void
1502
-     * @throws DomainException
1503
-     * @throws EE_Error
1504
-     * @throws InvalidArgumentException
1505
-     * @throws InvalidDataTypeException
1506
-     * @throws InvalidInterfaceException
1507
-     * @throws ReflectionException
1508
-     */
1509
-    public function txn_registrant_side_meta_box()
1510
-    {
1511
-        $primary_att = $this->_transaction->primary_registration() instanceof EE_Registration
1512
-            ? $this->_transaction->primary_registration()->get_first_related('Attendee')
1513
-            : null;
1514
-        if (! $primary_att instanceof EE_Attendee) {
1515
-            $this->_template_args['no_attendee_message'] = esc_html__(
1516
-                'There is no attached contact for this transaction.  The transaction either failed due to an error or was abandoned.',
1517
-                'event_espresso'
1518
-            );
1519
-            $primary_att                           = EEM_Attendee::instance()->create_default_object();
1520
-        }
1521
-        $this->_template_args['ATT_ID']            = $primary_att->ID();
1522
-        $this->_template_args['prime_reg_fname']   = $primary_att->fname();
1523
-        $this->_template_args['prime_reg_lname']   = $primary_att->lname();
1524
-        $this->_template_args['prime_reg_email']   = $primary_att->email();
1525
-        $this->_template_args['prime_reg_phone']   = $primary_att->phone();
1526
-        $this->_template_args['edit_attendee_url'] = EE_Admin_Page::add_query_args_and_nonce(
1527
-            [
1528
-                'action' => 'edit_attendee',
1529
-                'post'   => $primary_att->ID(),
1530
-            ],
1531
-            REG_ADMIN_URL
1532
-        );
1533
-        // get formatted address for registrant
1534
-        $formatted_address = EEH_Address::format($primary_att);
1535
-        $formatted_address = $formatted_address !== '<div class="espresso-address-dv"><div></div></div>'
1536
-            ? $formatted_address
1537
-            : '';
1538
-        $this->_template_args['formatted_address'] = $formatted_address;
1539
-        echo EEH_Template::display_template(
1540
-            TXN_TEMPLATE_PATH . 'txn_admin_details_side_meta_box_registrant.template.php',
1541
-            $this->_template_args,
1542
-            true
1543
-        );
1544
-    }
1545
-
1546
-
1547
-    /**
1548
-     * txn_billing_info_side_meta_box
1549
-     *    generates HTML for the Edit Transaction side meta box
1550
-     *
1551
-     * @access public
1552
-     * @return void
1553
-     * @throws DomainException
1554
-     * @throws EE_Error
1555
-     * @throws ReflectionException
1556
-     */
1557
-    public function txn_billing_info_side_meta_box()
1558
-    {
1559
-
1560
-        $this->_template_args['billing_form']     = $this->_transaction->billing_info();
1561
-        $this->_template_args['billing_form_url'] = add_query_arg(
1562
-            ['action' => 'edit_transaction', 'process' => 'billing'],
1563
-            TXN_ADMIN_URL
1564
-        );
1565
-
1566
-        $template_path = TXN_TEMPLATE_PATH . 'txn_admin_details_side_meta_box_billing_info.template.php';
1567
-        echo EEH_Template::display_template($template_path, $this->_template_args, true);
1568
-    }
1569
-
1570
-
1571
-    /**
1572
-     * apply_payments_or_refunds
1573
-     *    registers a payment or refund made towards a transaction
1574
-     *
1575
-     * @access public
1576
-     * @return void
1577
-     * @throws EE_Error
1578
-     * @throws InvalidArgumentException
1579
-     * @throws ReflectionException
1580
-     * @throws RuntimeException
1581
-     * @throws InvalidDataTypeException
1582
-     * @throws InvalidInterfaceException
1583
-     */
1584
-    public function apply_payments_or_refunds()
1585
-    {
1586
-        $valid_data         = $this->_validate_payment_request_data();
1587
-        $has_access         = EE_Registry::instance()->CAP->current_user_can(
1588
-            'ee_edit_payments',
1589
-            'apply_payment_or_refund_from_registration_details'
1590
-        );
1591
-        $TXD_ID = $this->request->getRequestParam('txn_admin_payment[TXN_ID]', 0, 'int');
1592
-        $amount = 0;
1593
-        if (! empty($valid_data) && $has_access) {
1594
-            $PAY_ID = $valid_data['PAY_ID'];
1595
-            // save  the new payment
1596
-            $payment = $this->_create_payment_from_request_data($valid_data);
1597
-            $amount = $payment->amount();
1598
-            // get the TXN for this payment
1599
-            $transaction = $payment->transaction();
1600
-            // verify transaction
1601
-            if ($transaction instanceof EE_Transaction) {
1602
-                // calculate_total_payments_and_update_status
1603
-                $this->_process_transaction_payments($transaction);
1604
-                $REG_IDs = $this->_get_REG_IDs_to_apply_payment_to($payment);
1605
-                $this->_remove_existing_registration_payments($payment, $PAY_ID);
1606
-                // apply payment to registrations (if applicable)
1607
-                if (! empty($REG_IDs)) {
1608
-                    $this->_update_registration_payments($transaction, $payment, $REG_IDs);
1609
-                    $this->_maybe_send_notifications();
1610
-                    // now process status changes for the same registrations
1611
-                    $this->_process_registration_status_change($transaction, $REG_IDs);
1612
-                }
1613
-                $this->_maybe_send_notifications($payment);
1614
-                // prepare to render page
1615
-                do_action(
1616
-                    'AHEE__Transactions_Admin_Page__apply_payments_or_refund__after_recording',
1617
-                    $transaction,
1618
-                    $payment
1619
-                );
1620
-            } else {
1621
-                EE_Error::add_error(
1622
-                    esc_html__(
1623
-                        'A valid Transaction for this payment could not be retrieved.',
1624
-                        'event_espresso'
1625
-                    ),
1626
-                    __FILE__,
1627
-                    __FUNCTION__,
1628
-                    __LINE__
1629
-                );
1630
-            }
1631
-        } elseif ($has_access) {
1632
-            EE_Error::add_error(
1633
-                esc_html__(
1634
-                    'The payment form data could not be processed. Please try again.',
1635
-                    'event_espresso'
1636
-                ),
1637
-                __FILE__,
1638
-                __FUNCTION__,
1639
-                __LINE__
1640
-            );
1641
-        } else {
1642
-            EE_Error::add_error(
1643
-                esc_html__(
1644
-                    'You do not have access to apply payments or refunds to a registration.',
1645
-                    'event_espresso'
1646
-                ),
1647
-                __FILE__,
1648
-                __FUNCTION__,
1649
-                __LINE__
1650
-            );
1651
-        }
1652
-        $query_args = [
1653
-            'page' => 'espresso_transactions',
1654
-             'action' => 'view_transaction',
1655
-             'TXN_ID' => $TXD_ID
1656
-        ];
1657
-
1658
-        $this->_redirect_after_action(
1659
-            ! EE_Error::has_error(),
1660
-            $amount > 0
1661
-                ? esc_html__('payment', 'event_espresso')
1662
-                : esc_html__('refund', 'event_espresso'),
1663
-            esc_html__('processed', 'event_espresso'),
1664
-            $query_args
1665
-        );
1666
-    }
1667
-
1668
-
1669
-    /**
1670
-     * _validate_payment_request_data
1671
-     *
1672
-     * @return array
1673
-     * @throws EE_Error
1674
-     * @throws InvalidArgumentException
1675
-     * @throws InvalidDataTypeException
1676
-     * @throws InvalidInterfaceException
1677
-     */
1678
-    protected function _validate_payment_request_data()
1679
-    {
1680
-        if (! $this->request->requestParamIsSet('txn_admin_payment')) {
1681
-            return [];
1682
-        }
1683
-        $payment_form = $this->_generate_payment_form_section();
1684
-        try {
1685
-            if ($payment_form->was_submitted()) {
1686
-                $payment_form->receive_form_submission();
1687
-                if (! $payment_form->is_valid()) {
1688
-                    $submission_error_messages = [];
1689
-                    foreach ($payment_form->get_validation_errors_accumulated() as $validation_error) {
1690
-                        if ($validation_error instanceof EE_Validation_Error) {
1691
-                            $form_input = $validation_error->get_form_section();
1692
-                            $submission_error_messages[] = sprintf(
1693
-                                _x('%s : %s', 'Form Section Name : Form Validation Error', 'event_espresso'),
1694
-                                $form_input instanceof EE_Form_Input_Base ? $form_input->html_label_text() : '',
1695
-                                $validation_error->getMessage()
1696
-                            );
1697
-                        }
1698
-                    }
1699
-                    EE_Error::add_error(
1700
-                        implode('<br />', $submission_error_messages),
1701
-                        __FILE__,
1702
-                        __FUNCTION__,
1703
-                        __LINE__
1704
-                    );
1705
-                    return [];
1706
-                }
1707
-            }
1708
-        } catch (EE_Error $e) {
1709
-            EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1710
-            return [];
1711
-        }
1712
-
1713
-        return $payment_form->valid_data();
1714
-    }
1715
-
1716
-
1717
-    /**
1718
-     * _generate_payment_form_section
1719
-     *
1720
-     * @return EE_Form_Section_Proper
1721
-     * @throws EE_Error
1722
-     */
1723
-    protected function _generate_payment_form_section()
1724
-    {
1725
-        return new EE_Form_Section_Proper(
1726
-            [
1727
-                'name'        => 'txn_admin_payment',
1728
-                'subsections' => [
1729
-                    'PAY_ID'          => new EE_Text_Input(
1730
-                        [
1731
-                            'default'               => 0,
1732
-                            'required'              => false,
1733
-                            'html_label_text'       => esc_html__('Payment ID', 'event_espresso'),
1734
-                            'validation_strategies' => [new EE_Int_Normalization()],
1735
-                        ]
1736
-                    ),
1737
-                    'TXN_ID'          => new EE_Text_Input(
1738
-                        [
1739
-                            'default'               => 0,
1740
-                            'required'              => true,
1741
-                            'html_label_text'       => esc_html__('Transaction ID', 'event_espresso'),
1742
-                            'validation_strategies' => [new EE_Int_Normalization()],
1743
-                        ]
1744
-                    ),
1745
-                    'type'            => new EE_Text_Input(
1746
-                        [
1747
-                            'default'               => 1,
1748
-                            'required'              => true,
1749
-                            'html_label_text'       => esc_html__('Payment or Refund', 'event_espresso'),
1750
-                            'validation_strategies' => [new EE_Int_Normalization()],
1751
-                        ]
1752
-                    ),
1753
-                    'amount'          => new EE_Text_Input(
1754
-                        [
1755
-                            'default'               => 0,
1756
-                            'required'              => true,
1757
-                            'html_label_text'       => esc_html__('Payment amount', 'event_espresso'),
1758
-                            'validation_strategies' => [new EE_Float_Normalization()],
1759
-                        ]
1760
-                    ),
1761
-                    'status'          => new EE_Text_Input(
1762
-                        [
1763
-                            'default'         => EEM_Payment::status_id_approved,
1764
-                            'required'        => true,
1765
-                            'html_label_text' => esc_html__('Payment status', 'event_espresso'),
1766
-                        ]
1767
-                    ),
1768
-                    'PMD_ID'          => new EE_Text_Input(
1769
-                        [
1770
-                            'default'               => 2,
1771
-                            'required'              => true,
1772
-                            'html_label_text'       => esc_html__('Payment Method', 'event_espresso'),
1773
-                            'validation_strategies' => [new EE_Int_Normalization()],
1774
-                        ]
1775
-                    ),
1776
-                    'date'            => new EE_Text_Input(
1777
-                        [
1778
-                            'default'         => time(),
1779
-                            'required'        => true,
1780
-                            'html_label_text' => esc_html__('Payment date', 'event_espresso'),
1781
-                        ]
1782
-                    ),
1783
-                    'txn_id_chq_nmbr' => new EE_Text_Input(
1784
-                        [
1785
-                            'default'               => '',
1786
-                            'required'              => false,
1787
-                            'html_label_text'       => esc_html__('Transaction or Cheque Number', 'event_espresso'),
1788
-                            'validation_strategies' => [
1789
-                                new EE_Max_Length_Validation_Strategy(
1790
-                                    esc_html__('Input too long', 'event_espresso'),
1791
-                                    100
1792
-                                ),
1793
-                            ],
1794
-                        ]
1795
-                    ),
1796
-                    'po_number'       => new EE_Text_Input(
1797
-                        [
1798
-                            'default'               => '',
1799
-                            'required'              => false,
1800
-                            'html_label_text'       => esc_html__('Purchase Order Number', 'event_espresso'),
1801
-                            'validation_strategies' => [
1802
-                                new EE_Max_Length_Validation_Strategy(
1803
-                                    esc_html__('Input too long', 'event_espresso'),
1804
-                                    100
1805
-                                ),
1806
-                            ],
1807
-                        ]
1808
-                    ),
1809
-                    'accounting'      => new EE_Text_Input(
1810
-                        [
1811
-                            'default'               => '',
1812
-                            'required'              => false,
1813
-                            'html_label_text'       => esc_html__('Extra Field for Accounting', 'event_espresso'),
1814
-                            'validation_strategies' => [
1815
-                                new EE_Max_Length_Validation_Strategy(
1816
-                                    esc_html__('Input too long', 'event_espresso'),
1817
-                                    100
1818
-                                ),
1819
-                            ],
1820
-                        ]
1821
-                    ),
1822
-                ],
1823
-            ]
1824
-        );
1825
-    }
1826
-
1827
-
1828
-    /**
1829
-     * _create_payment_from_request_data
1830
-     *
1831
-     * @param array $valid_data
1832
-     * @return EE_Payment
1833
-     * @throws EE_Error
1834
-     * @throws InvalidArgumentException
1835
-     * @throws InvalidDataTypeException
1836
-     * @throws InvalidInterfaceException
1837
-     * @throws ReflectionException
1838
-     */
1839
-    protected function _create_payment_from_request_data($valid_data)
1840
-    {
1841
-        $PAY_ID = $valid_data['PAY_ID'];
1842
-        // get payment amount
1843
-        $amount = $valid_data['amount'] ? abs($valid_data['amount']) : 0;
1844
-        // payments have a type value of 1 and refunds have a type value of -1
1845
-        // so multiplying amount by type will give a positive value for payments, and negative values for refunds
1846
-        $amount = $valid_data['type'] < 0 ? $amount * -1 : $amount;
1847
-        // for some reason the date string coming in has extra spaces between the date and time.  This fixes that.
1848
-        $date    = $valid_data['date']
1849
-            ? preg_replace('/\s+/', ' ', $valid_data['date'])
1850
-            : date('Y-m-d g:i a', current_time('timestamp'));
1851
-        $payment = EE_Payment::new_instance(
1852
-            [
1853
-                'TXN_ID'              => $valid_data['TXN_ID'],
1854
-                'STS_ID'              => $valid_data['status'],
1855
-                'PAY_timestamp'       => $date,
1856
-                'PAY_source'          => EEM_Payment_Method::scope_admin,
1857
-                'PMD_ID'              => $valid_data['PMD_ID'],
1858
-                'PAY_amount'          => $amount,
1859
-                'PAY_txn_id_chq_nmbr' => $valid_data['txn_id_chq_nmbr'],
1860
-                'PAY_po_number'       => $valid_data['po_number'],
1861
-                'PAY_extra_accntng'   => $valid_data['accounting'],
1862
-                'PAY_details'         => $valid_data,
1863
-                'PAY_ID'              => $PAY_ID,
1864
-            ],
1865
-            '',
1866
-            ['Y-m-d', 'g:i a']
1867
-        );
1868
-
1869
-        if (! $payment->save()) {
1870
-            EE_Error::add_error(
1871
-                sprintf(
1872
-                    esc_html__('Payment %1$d has not been successfully saved to the database.', 'event_espresso'),
1873
-                    $payment->ID()
1874
-                ),
1875
-                __FILE__,
1876
-                __FUNCTION__,
1877
-                __LINE__
1878
-            );
1879
-        }
1880
-
1881
-        return $payment;
1882
-    }
1883
-
1884
-
1885
-    /**
1886
-     * _process_transaction_payments
1887
-     *
1888
-     * @param EE_Transaction $transaction
1889
-     * @return void
1890
-     * @throws EE_Error
1891
-     * @throws InvalidArgumentException
1892
-     * @throws ReflectionException
1893
-     * @throws InvalidDataTypeException
1894
-     * @throws InvalidInterfaceException
1895
-     */
1896
-    protected function _process_transaction_payments(EE_Transaction $transaction)
1897
-    {
1898
-        /** @type EE_Transaction_Payments $transaction_payments */
1899
-        $transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
1900
-        // update the transaction with this payment
1901
-        if ($transaction_payments->calculate_total_payments_and_update_status($transaction)) {
1902
-            EE_Error::add_success(
1903
-                esc_html__(
1904
-                    'The payment has been processed successfully.',
1905
-                    'event_espresso'
1906
-                ),
1907
-                __FILE__,
1908
-                __FUNCTION__,
1909
-                __LINE__
1910
-            );
1911
-        } else {
1912
-            EE_Error::add_error(
1913
-                esc_html__(
1914
-                    'The payment was processed successfully but the amount paid for the transaction was not updated.',
1915
-                    'event_espresso'
1916
-                ),
1917
-                __FILE__,
1918
-                __FUNCTION__,
1919
-                __LINE__
1920
-            );
1921
-        }
1922
-    }
1923
-
1924
-
1925
-    /**
1926
-     * _get_REG_IDs_to_apply_payment_to
1927
-     * returns a list of registration IDs that the payment will apply to
1928
-     *
1929
-     * @param EE_Payment $payment
1930
-     * @return array
1931
-     * @throws EE_Error
1932
-     * @throws InvalidArgumentException
1933
-     * @throws InvalidDataTypeException
1934
-     * @throws InvalidInterfaceException
1935
-     * @throws ReflectionException
1936
-     */
1937
-    protected function _get_REG_IDs_to_apply_payment_to(EE_Payment $payment)
1938
-    {
1939
-        // grab array of IDs for specific registrations to apply changes to
1940
-        $apply_to_all = $this->request->getRequestParam(
1941
-            'txn_admin_payment[apply_to_all_registrations]',
1942
-            false,
1943
-            DataType::BOOL
1944
-        );
1945
-        $REG_IDs = ! $apply_to_all
1946
-            ? $this->request->getRequestParam(
1947
-                'txn_admin_payment[registrations]',
1948
-                [],
1949
-                DataType::INT,
1950
-                true
1951
-            )
1952
-            : [];
1953
-        // nothing specified ? then get all reg IDs
1954
-        if ($apply_to_all || empty($REG_IDs)) {
1955
-            $registrations = $payment->transaction()->registrations();
1956
-            $REG_IDs       = ! empty($registrations)
1957
-                ? array_keys($registrations)
1958
-                : $this->_get_existing_reg_payment_REG_IDs($payment);
1959
-        }
1960
-        // ensure that REG_IDs are integers and NOT strings
1961
-        return array_map('absint', $REG_IDs);
1962
-    }
1963
-
1964
-
1965
-    /**
1966
-     * @return array
1967
-     */
1968
-    public function existing_reg_payment_REG_IDs()
1969
-    {
1970
-        return $this->_existing_reg_payment_REG_IDs;
1971
-    }
1972
-
1973
-
1974
-    /**
1975
-     * @param array $existing_reg_payment_REG_IDs
1976
-     */
1977
-    public function set_existing_reg_payment_REG_IDs($existing_reg_payment_REG_IDs = null)
1978
-    {
1979
-        $this->_existing_reg_payment_REG_IDs = $existing_reg_payment_REG_IDs;
1980
-    }
1981
-
1982
-
1983
-    /**
1984
-     * _get_existing_reg_payment_REG_IDs
1985
-     * returns a list of registration IDs that the payment is currently related to
1986
-     * as recorded in the database
1987
-     *
1988
-     * @param EE_Payment $payment
1989
-     * @return array
1990
-     * @throws EE_Error
1991
-     * @throws InvalidArgumentException
1992
-     * @throws InvalidDataTypeException
1993
-     * @throws InvalidInterfaceException
1994
-     * @throws ReflectionException
1995
-     */
1996
-    protected function _get_existing_reg_payment_REG_IDs(EE_Payment $payment)
1997
-    {
1998
-        if ($this->existing_reg_payment_REG_IDs() === null) {
1999
-            // let's get any existing reg payment records for this payment
2000
-            $existing_reg_payment_REG_IDs = $payment->get_many_related('Registration');
2001
-            // but we only want the REG IDs, so grab the array keys
2002
-            $existing_reg_payment_REG_IDs = ! empty($existing_reg_payment_REG_IDs)
2003
-                ? array_keys($existing_reg_payment_REG_IDs)
2004
-                : [];
2005
-            $this->set_existing_reg_payment_REG_IDs($existing_reg_payment_REG_IDs);
2006
-        }
2007
-
2008
-        return $this->existing_reg_payment_REG_IDs();
2009
-    }
2010
-
2011
-
2012
-    /**
2013
-     * _remove_existing_registration_payments
2014
-     * this calculates the difference between existing relations
2015
-     * to the supplied payment and the new list registration IDs,
2016
-     * removes any related registrations that no longer apply,
2017
-     * and then updates the registration paid fields
2018
-     *
2019
-     * @param EE_Payment $payment
2020
-     * @param int        $PAY_ID
2021
-     * @return bool;
2022
-     * @throws EE_Error
2023
-     * @throws InvalidArgumentException
2024
-     * @throws ReflectionException
2025
-     * @throws InvalidDataTypeException
2026
-     * @throws InvalidInterfaceException
2027
-     */
2028
-    protected function _remove_existing_registration_payments(EE_Payment $payment, $PAY_ID = 0)
2029
-    {
2030
-        // newly created payments will have nothing recorded for $PAY_ID
2031
-        if (absint($PAY_ID) === 0) {
2032
-            return false;
2033
-        }
2034
-        $existing_reg_payment_REG_IDs = $this->_get_existing_reg_payment_REG_IDs($payment);
2035
-        if (empty($existing_reg_payment_REG_IDs)) {
2036
-            return false;
2037
-        }
2038
-        /** @type EE_Transaction_Payments $transaction_payments */
2039
-        $transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
2040
-
2041
-        return $transaction_payments->delete_registration_payments_and_update_registrations(
2042
-            $payment,
2043
-            [
2044
-                [
2045
-                    'PAY_ID' => $payment->ID(),
2046
-                    'REG_ID' => ['IN', $existing_reg_payment_REG_IDs],
2047
-                ],
2048
-            ]
2049
-        );
2050
-    }
2051
-
2052
-
2053
-    /**
2054
-     * _update_registration_payments
2055
-     * this applies the payments to the selected registrations
2056
-     * but only if they have not already been paid for
2057
-     *
2058
-     * @param EE_Transaction $transaction
2059
-     * @param EE_Payment     $payment
2060
-     * @param array          $REG_IDs
2061
-     * @return void
2062
-     * @throws EE_Error
2063
-     * @throws InvalidArgumentException
2064
-     * @throws ReflectionException
2065
-     * @throws RuntimeException
2066
-     * @throws InvalidDataTypeException
2067
-     * @throws InvalidInterfaceException
2068
-     */
2069
-    protected function _update_registration_payments(
2070
-        EE_Transaction $transaction,
2071
-        EE_Payment $payment,
2072
-        $REG_IDs = []
2073
-    ) {
2074
-        // we can pass our own custom set of registrations to EE_Payment_Processor::process_registration_payments()
2075
-        // so let's do that using our set of REG_IDs from the form
2076
-        $registration_query_where_params = [
2077
-            'REG_ID' => ['IN', $REG_IDs],
2078
-        ];
2079
-        // but add in some conditions regarding payment,
2080
-        // so that we don't apply payments to registrations that are free or have already been paid for
2081
-        // but ONLY if the payment is NOT a refund ( ie: the payment amount is not negative )
2082
-        if (! $payment->is_a_refund()) {
2083
-            $registration_query_where_params['REG_final_price']  = ['!=', 0];
2084
-            $registration_query_where_params['REG_final_price*'] = ['!=', 'REG_paid', true];
2085
-        }
2086
-        $registrations = $transaction->registrations([$registration_query_where_params]);
2087
-        if (! empty($registrations)) {
2088
-            /** @type EE_Payment_Processor $payment_processor */
2089
-            $payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
2090
-            $payment_processor->process_registration_payments($transaction, $payment, $registrations);
2091
-        }
2092
-    }
2093
-
2094
-
2095
-    /**
2096
-     * _process_registration_status_change
2097
-     * This processes requested registration status changes for all the registrations
2098
-     * on a given transaction and (optionally) sends out notifications for the changes.
2099
-     *
2100
-     * @param EE_Transaction $transaction
2101
-     * @param array          $REG_IDs
2102
-     * @return bool
2103
-     * @throws EE_Error
2104
-     * @throws InvalidArgumentException
2105
-     * @throws ReflectionException
2106
-     * @throws InvalidDataTypeException
2107
-     * @throws InvalidInterfaceException
2108
-     */
2109
-    protected function _process_registration_status_change(EE_Transaction $transaction, $REG_IDs = [], $reg_status = '')
2110
-    {
2111
-        // first if there is no change in status then we get out.
2112
-        $reg_status = $reg_status ?: $this->request->getRequestParam('txn_reg_status_change[reg_status]', 'NAN');
2113
-        if ($reg_status === 'NAN') {
2114
-            // no error message, no change requested, just nothing to do man.
2115
-            return false;
2116
-        }
2117
-        /** @type EE_Transaction_Processor $transaction_processor */
2118
-        $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
2119
-
2120
-        // made it here dude?  Oh WOW.  K, let's take care of changing the statuses
2121
-        return $transaction_processor->manually_update_registration_statuses(
2122
-            $transaction,
2123
-            $reg_status,
2124
-            [['REG_ID' => ['IN', $REG_IDs]]]
2125
-        );
2126
-    }
2127
-
2128
-
2129
-    /**
2130
-     * _build_payment_json_response
2131
-     *
2132
-     * @access public
2133
-     * @param EE_Payment  $payment
2134
-     * @param array       $REG_IDs
2135
-     * @param bool | null $delete_txn_reg_status_change
2136
-     * @return array
2137
-     * @throws EE_Error
2138
-     * @throws InvalidArgumentException
2139
-     * @throws InvalidDataTypeException
2140
-     * @throws InvalidInterfaceException
2141
-     * @throws ReflectionException
2142
-     */
2143
-    protected function _build_payment_json_response(
2144
-        EE_Payment $payment,
2145
-        $REG_IDs = [],
2146
-        $delete_txn_reg_status_change = null
2147
-    ) {
2148
-        // was the payment deleted ?
2149
-        if (is_bool($delete_txn_reg_status_change)) {
2150
-            return [
2151
-                'PAY_ID'                       => $payment->ID(),
2152
-                'amount'                       => $payment->amount(),
2153
-                'total_paid'                   => $payment->transaction()->paid(),
2154
-                'txn_status'                   => $payment->transaction()->status_ID(),
2155
-                'pay_status'                   => $payment->STS_ID(),
2156
-                'registrations'                => $this->_registration_payment_data_array($REG_IDs),
2157
-                'delete_txn_reg_status_change' => $delete_txn_reg_status_change,
2158
-            ];
2159
-        }
2160
-
2161
-        $this->_get_payment_status_array();
2162
-        return [
2163
-            'amount'           => $payment->amount(),
2164
-            'total_paid'       => $payment->transaction()->paid(),
2165
-            'txn_status'       => $payment->transaction()->status_ID(),
2166
-            'pay_status'       => $payment->STS_ID(),
2167
-            'PAY_ID'           => $payment->ID(),
2168
-            'STS_ID'           => $payment->STS_ID(),
2169
-            'status'           => self::$_pay_status[ $payment->STS_ID() ],
2170
-            'date'             => $payment->timestamp('Y-m-d', 'h:i a'),
2171
-            'method'           => strtoupper($payment->source()),
2172
-            'PM_ID'            => $payment->payment_method() ? $payment->payment_method()->ID() : 1,
2173
-            'gateway'          => $payment->payment_method()
2174
-                ? $payment->payment_method()->admin_name()
2175
-                : esc_html__('Unknown', 'event_espresso'),
2176
-            'gateway_response' => $payment->gateway_response(),
2177
-            'txn_id_chq_nmbr'  => $payment->txn_id_chq_nmbr(),
2178
-            'po_number'        => $payment->po_number(),
2179
-            'extra_accntng'    => $payment->extra_accntng(),
2180
-            'registrations'    => $this->_registration_payment_data_array($REG_IDs),
2181
-        ];
2182
-    }
2183
-
2184
-
2185
-    /**
2186
-     * delete_payment
2187
-     *    delete a payment or refund made towards a transaction
2188
-     *
2189
-     * @access public
2190
-     * @return void
2191
-     * @throws EE_Error
2192
-     * @throws InvalidArgumentException
2193
-     * @throws ReflectionException
2194
-     * @throws InvalidDataTypeException
2195
-     * @throws InvalidInterfaceException
2196
-     */
2197
-    public function delete_payment()
2198
-    {
2199
-        $TXD_ID = $this->request->getRequestParam('delete_txn_admin_payment[TXN_ID]', 0, 'int');
2200
-        // $json_response_data = ['return_data' => false];
2201
-        $PAY_ID = $this->request->getRequestParam('delete_txn_admin_payment[PAY_ID]', 0, 'int');
2202
-        $amount = 0;
2203
-        $can_delete         = EE_Registry::instance()->CAP->current_user_can(
2204
-            'ee_delete_payments',
2205
-            'delete_payment_from_registration_details'
2206
-        );
2207
-        if ($PAY_ID && $can_delete) {
2208
-            $delete_txn_reg_status_change = $this->request->getRequestParam('delete_txn_reg_status_change[reg_status]');
2209
-            $payment = EEM_Payment::instance()->get_one_by_ID($PAY_ID);
2210
-            if ($payment instanceof EE_Payment) {
2211
-                $amount = $payment->amount();
2212
-                $REG_IDs = $this->_get_existing_reg_payment_REG_IDs($payment);
2213
-                /** @type EE_Transaction_Payments $transaction_payments */
2214
-                $transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
2215
-                if ($transaction_payments->delete_payment_and_update_transaction($payment)) {
2216
-                    if ($delete_txn_reg_status_change) {
2217
-                        $this->_maybe_send_notifications();
2218
-                        $this->_process_registration_status_change(
2219
-                            $payment->transaction(),
2220
-                            $REG_IDs,
2221
-                            $delete_txn_reg_status_change
2222
-                        );
2223
-                    }
2224
-                }
2225
-            } else {
2226
-                EE_Error::add_error(
2227
-                    esc_html__('Valid Payment data could not be retrieved from the database.', 'event_espresso'),
2228
-                    __FILE__,
2229
-                    __FUNCTION__,
2230
-                    __LINE__
2231
-                );
2232
-            }
2233
-        } elseif ($can_delete) {
2234
-            EE_Error::add_error(
2235
-                esc_html__(
2236
-                    'A valid Payment ID was not received, therefore payment form data could not be loaded.',
2237
-                    'event_espresso'
2238
-                ),
2239
-                __FILE__,
2240
-                __FUNCTION__,
2241
-                __LINE__
2242
-            );
2243
-        } else {
2244
-            EE_Error::add_error(
2245
-                esc_html__(
2246
-                    'You do not have access to delete a payment.',
2247
-                    'event_espresso'
2248
-                ),
2249
-                __FILE__,
2250
-                __FUNCTION__,
2251
-                __LINE__
2252
-            );
2253
-        }
2254
-        $query_args = [
2255
-            'page'   => 'espresso_transactions',
2256
-            'action' => 'view_transaction',
2257
-            'TXN_ID' => $TXD_ID
2258
-        ];
2259
-        $this->_redirect_after_action(
2260
-            ! EE_Error::has_error(),
2261
-            $amount > 0
2262
-                ? esc_html__('payment', 'event_espresso')
2263
-                : esc_html__('refund', 'event_espresso'),
2264
-            esc_html__('deleted', 'event_espresso'),
2265
-            $query_args
2266
-        );
2267
-    }
2268
-
2269
-
2270
-    /**
2271
-     * _registration_payment_data_array
2272
-     * adds info for 'owing' and 'paid' for each registration to the json response
2273
-     *
2274
-     * @access protected
2275
-     * @param array $REG_IDs
2276
-     * @return array
2277
-     * @throws EE_Error
2278
-     * @throws InvalidArgumentException
2279
-     * @throws InvalidDataTypeException
2280
-     * @throws InvalidInterfaceException
2281
-     * @throws ReflectionException
2282
-     */
2283
-    protected function _registration_payment_data_array($REG_IDs)
2284
-    {
2285
-        $registration_payment_data = [];
2286
-        // if non empty reg_ids lets get an array of registrations and update the values for the apply_payment/refund rows.
2287
-        if (! empty($REG_IDs)) {
2288
-            $registrations = EEM_Registration::instance()->get_all([['REG_ID' => ['IN', $REG_IDs]]]);
2289
-            foreach ($registrations as $registration) {
2290
-                if ($registration instanceof EE_Registration) {
2291
-                    $registration_payment_data[ $registration->ID() ] = [
2292
-                        'paid'  => $registration->pretty_paid(),
2293
-                        'owing' => EEH_Template::format_currency($registration->final_price() - $registration->paid()),
2294
-                    ];
2295
-                }
2296
-            }
2297
-        }
2298
-
2299
-        return $registration_payment_data;
2300
-    }
2301
-
2302
-
2303
-    /**
2304
-     * _maybe_send_notifications
2305
-     * determines whether or not the admin has indicated that notifications should be sent.
2306
-     * If so, will toggle a filter switch for delivering registration notices.
2307
-     * If passed an EE_Payment object, then it will trigger payment notifications instead.
2308
-     *
2309
-     * @access protected
2310
-     * @param EE_Payment | null $payment
2311
-     */
2312
-    protected function _maybe_send_notifications($payment = null)
2313
-    {
2314
-        switch ($payment instanceof EE_Payment) {
2315
-            // payment notifications
2316
-            case true:
2317
-                if ($this->request->getRequestParam('txn_payments[send_notifications]', false, 'bool')) {
2318
-                    $this->_process_payment_notification($payment);
2319
-                }
2320
-                break;
2321
-            // registration notifications
2322
-            case false:
2323
-                if ($this->request->getRequestParam('txn_reg_status_change[send_notifications]', false, 'bool')) {
2324
-                    add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true');
2325
-                }
2326
-                break;
2327
-        }
2328
-    }
2329
-
2330
-
2331
-    /**
2332
-     * _send_payment_reminder
2333
-     *    generates HTML for the View Transaction Details Admin page
2334
-     *
2335
-     * @access protected
2336
-     * @return void
2337
-     * @throws EE_Error
2338
-     * @throws InvalidArgumentException
2339
-     * @throws InvalidDataTypeException
2340
-     * @throws InvalidInterfaceException
2341
-     */
2342
-    protected function _send_payment_reminder()
2343
-    {
2344
-        $TXN_ID = $this->request->getRequestParam('TXN_ID', 0, 'int');
2345
-        $transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
2346
-        $redirect_to = $this->request->getRequestParam('redirect_to');
2347
-        $query_args  = $redirect_to ? ['action' => $redirect_to, 'TXN_ID' => $TXN_ID,] : [];
2348
-        do_action(
2349
-            'AHEE__Transactions_Admin_Page___send_payment_reminder__process_admin_payment_reminder',
2350
-            $transaction
2351
-        );
2352
-        $this->_redirect_after_action(
2353
-            false,
2354
-            esc_html__('payment reminder', 'event_espresso'),
2355
-            esc_html__('sent', 'event_espresso'),
2356
-            $query_args,
2357
-            true
2358
-        );
2359
-    }
2360
-
2361
-
2362
-    /**
2363
-     *  get_transactions
2364
-     *    get transactions for given parameters (used by list table)
2365
-     *
2366
-     * @param int     $per_page how many transactions displayed per page
2367
-     * @param boolean $count   return the count or objects
2368
-     * @param string  $view
2369
-     * @return EE_Transaction[]|int int = count || array of transaction objects
2370
-     * @throws EE_Error
2371
-     * @throws InvalidArgumentException
2372
-     * @throws InvalidDataTypeException
2373
-     * @throws InvalidInterfaceException
2374
-     */
2375
-    public function get_transactions($per_page, $count = false, $view = '')
2376
-    {
2377
-        $start_date = wp_strip_all_tags(
2378
-            $this->request->getRequestParam('txn-filter-start-date', date('m/d/Y', strtotime('-10 year')))
2379
-        );
2380
-        $end_date = wp_strip_all_tags(
2381
-            $this->request->getRequestParam('txn-filter-end-date', date('m/d/Y'))
2382
-        );
2383
-
2384
-        // make sure our timestamps start and end right at the boundaries for each day
2385
-        $start_date = date('Y-m-d', strtotime($start_date)) . ' 00:00:00';
2386
-        $end_date   = date('Y-m-d', strtotime($end_date)) . ' 23:59:59';
2387
-
2388
-
2389
-        // convert to timestamps
2390
-        $start_date = strtotime($start_date);
2391
-        $end_date   = strtotime($end_date);
2392
-
2393
-        // makes sure start date is the lowest value and vice versa
2394
-        $start_date = min($start_date, $end_date);
2395
-        $end_date   = max($start_date, $end_date);
2396
-
2397
-        // convert to correct format for query
2398
-        $start_date = EEM_Transaction::instance()->convert_datetime_for_query(
2399
-            'TXN_timestamp',
2400
-            date('Y-m-d H:i:s', $start_date),
2401
-            'Y-m-d H:i:s'
2402
-        );
2403
-        $end_date   = EEM_Transaction::instance()->convert_datetime_for_query(
2404
-            'TXN_timestamp',
2405
-            date('Y-m-d H:i:s', $end_date),
2406
-            'Y-m-d H:i:s'
2407
-        );
2408
-
2409
-
2410
-        // set orderby
2411
-        $orderby = $this->request->getRequestParam('orderby');
2412
-
2413
-        switch ($orderby) {
2414
-            case 'TXN_ID':
2415
-                break;
2416
-            case 'ATT_fname':
2417
-                $orderby = 'Registration.Attendee.ATT_fname';
2418
-                break;
2419
-            case 'event_name':
2420
-                $orderby = 'Registration.Event.EVT_name';
2421
-                break;
2422
-            default: // 'TXN_timestamp'
2423
-                $orderby = 'TXN_timestamp';
2424
-        }
2425
-
2426
-        $sort         = $this->request->getRequestParam('order', 'DESC');
2427
-        $current_page = $this->request->getRequestParam('paged', 1, 'int');
2428
-
2429
-        $per_page = absint($per_page) ? $per_page : 10;
2430
-        $per_page = $this->request->getRequestParam('perpage', $per_page, 'int');
2431
-
2432
-        $offset = ($current_page - 1) * $per_page;
2433
-        $limit  = [$offset, $per_page];
2434
-
2435
-        $_where = [
2436
-            'TXN_timestamp'          => ['BETWEEN', [$start_date, $end_date]],
2437
-            'Registration.REG_count' => 1,
2438
-        ];
2439
-
2440
-        $EVT_ID = $this->request->getRequestParam('EVT_ID', 0, 'int');
2441
-        if ($EVT_ID) {
2442
-            $_where['Registration.EVT_ID'] = $EVT_ID;
2443
-        }
2444
-
2445
-        $search_term = $this->request->getRequestParam('s');
2446
-        if ($search_term) {
2447
-            $search_term = '%' . $search_term . '%';
2448
-            $_where['OR']  = [
2449
-                'Registration.Event.EVT_name'         => ['LIKE', $search_term],
2450
-                'Registration.Event.EVT_desc'         => ['LIKE', $search_term],
2451
-                'Registration.Event.EVT_short_desc'   => ['LIKE', $search_term],
2452
-                'Registration.Attendee.ATT_full_name' => ['LIKE', $search_term],
2453
-                'Registration.Attendee.ATT_fname'     => ['LIKE', $search_term],
2454
-                'Registration.Attendee.ATT_lname'     => ['LIKE', $search_term],
2455
-                'Registration.Attendee.ATT_short_bio' => ['LIKE', $search_term],
2456
-                'Registration.Attendee.ATT_email'     => ['LIKE', $search_term],
2457
-                'Registration.Attendee.ATT_address'   => ['LIKE', $search_term],
2458
-                'Registration.Attendee.ATT_address2'  => ['LIKE', $search_term],
2459
-                'Registration.Attendee.ATT_city'      => ['LIKE', $search_term],
2460
-                'Registration.REG_final_price'        => ['LIKE', $search_term],
2461
-                'Registration.REG_code'               => ['LIKE', $search_term],
2462
-                'Registration.REG_count'              => ['LIKE', $search_term],
2463
-                'Registration.REG_group_size'         => ['LIKE', $search_term],
2464
-                'Registration.Ticket.TKT_name'        => ['LIKE', $search_term],
2465
-                'Registration.Ticket.TKT_description' => ['LIKE', $search_term],
2466
-                'Payment.PAY_source'                  => ['LIKE', $search_term],
2467
-                'Payment.Payment_Method.PMD_name'     => ['LIKE', $search_term],
2468
-                'TXN_session_data'                    => ['LIKE', $search_term],
2469
-                'Payment.PAY_txn_id_chq_nmbr'         => ['LIKE', $search_term],
2470
-            ];
2471
-        }
2472
-
2473
-        $status = $this->request->getRequestParam('status');
2474
-        // failed transactions
2475
-        $failed     = (! empty($status) && $status === 'failed' && ! $count) || ($count && $view === 'failed');
2476
-        $abandoned  = (! empty($status) && $status === 'abandoned' && ! $count) || ($count && $view === 'abandoned');
2477
-        $incomplete = (! empty($status) && $status === 'incomplete' && ! $count) || ($count && $view === 'incomplete');
2478
-
2479
-        if ($failed) {
2480
-            $_where['STS_ID'] = EEM_Transaction::failed_status_code;
2481
-        } elseif ($abandoned) {
2482
-            $_where['STS_ID'] = EEM_Transaction::abandoned_status_code;
2483
-        } elseif ($incomplete) {
2484
-            $_where['STS_ID'] = EEM_Transaction::incomplete_status_code;
2485
-        } else {
2486
-            $_where['STS_ID']  = ['!=', EEM_Transaction::failed_status_code];
2487
-            $_where['STS_ID*'] = ['!=', EEM_Transaction::abandoned_status_code];
2488
-        }
2489
-
2490
-        $query_params = apply_filters(
2491
-            'FHEE__Transactions_Admin_Page___get_transactions_query_params',
2492
-            [
2493
-                $_where,
2494
-                'order_by'                 => [$orderby => $sort],
2495
-                'limit'                    => $limit,
2496
-                'default_where_conditions' => EEM_Base::default_where_conditions_this_only,
2497
-            ],
2498
-            $this->request->requestParams(),
2499
-            $view,
2500
-            $count
2501
-        );
2502
-
2503
-        return $count
2504
-            ? EEM_Transaction::instance()->count([$query_params[0]], 'TXN_ID', true)
2505
-            : EEM_Transaction::instance()->get_all($query_params);
2506
-    }
2507
-
2508
-
2509
-    /**
2510
-     * @throws EE_Error
2511
-     * @throws InvalidArgumentException
2512
-     * @throws InvalidDataTypeException
2513
-     * @throws InvalidInterfaceException
2514
-     * @throws ReflectionException
2515
-     * @throws RuntimeException
2516
-     * @since 4.9.79.p
2517
-     */
2518
-    public function recalculateLineItems()
2519
-    {
2520
-        $TXN_ID = $this->request->getRequestParam('TXN_ID', 0, 'int');
2521
-        /** @var EE_Transaction $transaction */
2522
-        $transaction     = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
2523
-        $success         = $transaction->recalculateLineItems();
2524
-        $redirect_to = $this->request->getRequestParam('redirect_to');
2525
-        $query_args = $redirect_to ? ['action' => $redirect_to, 'TXN_ID' => $TXN_ID,] : [];
2526
-        $this->_redirect_after_action(
2527
-            $success,
2528
-            esc_html__('Transaction taxes and totals', 'event_espresso'),
2529
-            esc_html__('recalculated', 'event_espresso'),
2530
-            $query_args,
2531
-            true
2532
-        );
2533
-    }
16
+	/**
17
+	 * @var EE_Transaction
18
+	 */
19
+	private $_transaction;
20
+
21
+	/**
22
+	 * @var EE_Session
23
+	 */
24
+	private $_session;
25
+
26
+	/**
27
+	 * @var array $_txn_status
28
+	 */
29
+	private static $_txn_status;
30
+
31
+	/**
32
+	 * @var array $_pay_status
33
+	 */
34
+	private static $_pay_status;
35
+
36
+	/**
37
+	 * @var array $_existing_reg_payment_REG_IDs
38
+	 */
39
+	protected $_existing_reg_payment_REG_IDs;
40
+
41
+
42
+	/**
43
+	 *    _init_page_props
44
+	 *
45
+	 * @return void
46
+	 */
47
+	protected function _init_page_props()
48
+	{
49
+		$this->page_slug        = TXN_PG_SLUG;
50
+		$this->page_label       = esc_html__('Transactions', 'event_espresso');
51
+		$this->_admin_base_url  = TXN_ADMIN_URL;
52
+		$this->_admin_base_path = TXN_ADMIN;
53
+	}
54
+
55
+
56
+	/**
57
+	 *    _ajax_hooks
58
+	 *
59
+	 * @return void
60
+	 */
61
+	protected function _ajax_hooks()
62
+	{
63
+		// add_action('wp_ajax_espresso_apply_payment', [$this, 'apply_payments_or_refunds']);
64
+		// add_action('wp_ajax_espresso_apply_refund', [$this, 'apply_payments_or_refunds']);
65
+		// add_action('wp_ajax_espresso_delete_payment', [$this, 'delete_payment']);
66
+	}
67
+
68
+
69
+	/**
70
+	 *    _define_page_props
71
+	 *
72
+	 * @return void
73
+	 */
74
+	protected function _define_page_props()
75
+	{
76
+		$this->_admin_page_title = $this->page_label;
77
+		$this->_labels           = [
78
+			'buttons' => [
79
+				'add'    => esc_html__('Add New Transaction', 'event_espresso'),
80
+				'edit'   => esc_html__('Edit Transaction', 'event_espresso'),
81
+				'delete' => esc_html__('Delete Transaction', 'event_espresso'),
82
+			],
83
+		];
84
+	}
85
+
86
+
87
+	/**
88
+	 *        grab url requests and route them
89
+	 *
90
+	 * @access private
91
+	 * @return void
92
+	 * @throws EE_Error
93
+	 * @throws InvalidArgumentException
94
+	 * @throws InvalidDataTypeException
95
+	 * @throws InvalidInterfaceException
96
+	 */
97
+	public function _set_page_routes()
98
+	{
99
+
100
+		$this->_set_transaction_status_array();
101
+		$TXN_ID = $this->request->getRequestParam('TXN_ID', 0, 'int');
102
+
103
+		$this->_page_routes = [
104
+
105
+			'default' => [
106
+				'func'       => '_transactions_overview_list_table',
107
+				'capability' => 'ee_read_transactions',
108
+			],
109
+
110
+			'view_transaction' => [
111
+				'func'       => '_transaction_details',
112
+				'capability' => 'ee_read_transaction',
113
+				'obj_id'     => $TXN_ID,
114
+			],
115
+
116
+			'send_payment_reminder' => [
117
+				'func'       => '_send_payment_reminder',
118
+				'noheader'   => true,
119
+				'capability' => 'ee_send_message',
120
+			],
121
+
122
+			'espresso_apply_payment' => [
123
+				'func'       => 'apply_payments_or_refunds',
124
+				'noheader'   => true,
125
+				'capability' => 'ee_edit_payments',
126
+			],
127
+
128
+			'espresso_apply_refund' => [
129
+				'func'       => 'apply_payments_or_refunds',
130
+				'noheader'   => true,
131
+				'capability' => 'ee_edit_payments',
132
+			],
133
+
134
+			'espresso_delete_payment' => [
135
+				'func'       => [$this, 'delete_payment'],
136
+				'noheader'   => true,
137
+				'capability' => 'ee_delete_payments',
138
+			],
139
+
140
+			'espresso_recalculate_line_items' => [
141
+				'func'       => 'recalculateLineItems',
142
+				'noheader'   => true,
143
+				'capability' => 'ee_edit_payments',
144
+			],
145
+
146
+		];
147
+	}
148
+
149
+
150
+	protected function _set_page_config()
151
+	{
152
+		$TXN_ID = $this->request->getRequestParam('TXN_ID', 0, 'int');
153
+		$this->_page_config = [
154
+			'default'          => [
155
+				'nav'           => [
156
+					'label' => esc_html__('Overview', 'event_espresso'),
157
+					'icon' => 'dashicons-list-view',
158
+					'order' => 10,
159
+				],
160
+				'list_table'    => 'EE_Admin_Transactions_List_Table',
161
+				'help_tabs'     => [
162
+					'transactions_overview_help_tab'                       => [
163
+						'title'    => esc_html__('Transactions Overview', 'event_espresso'),
164
+						'filename' => 'transactions_overview',
165
+					],
166
+					'transactions_overview_table_column_headings_help_tab' => [
167
+						'title'    => esc_html__('Transactions Table Column Headings', 'event_espresso'),
168
+						'filename' => 'transactions_overview_table_column_headings',
169
+					],
170
+					'transactions_overview_views_filters_help_tab'         => [
171
+						'title'    => esc_html__('Transaction Views & Filters & Search', 'event_espresso'),
172
+						'filename' => 'transactions_overview_views_filters_search',
173
+					],
174
+				],
175
+				'require_nonce' => false,
176
+			],
177
+			'view_transaction' => [
178
+				'nav'       => [
179
+					'label'      => esc_html__('View Transaction', 'event_espresso'),
180
+					'icon' => 'dashicons-cart',
181
+					'order'      => 5,
182
+					'url'        => $TXN_ID
183
+						? add_query_arg(['TXN_ID' => $TXN_ID], $this->_current_page_view_url)
184
+						: $this->_admin_base_url,
185
+					'persistent' => false,
186
+				],
187
+				'help_tabs' => [
188
+					'transactions_view_transaction_help_tab'                                              => [
189
+						'title'    => esc_html__('View Transaction', 'event_espresso'),
190
+						'filename' => 'transactions_view_transaction',
191
+					],
192
+					'transactions_view_transaction_transaction_details_table_help_tab'                    => [
193
+						'title'    => esc_html__('Transaction Details Table', 'event_espresso'),
194
+						'filename' => 'transactions_view_transaction_transaction_details_table',
195
+					],
196
+					'transactions_view_transaction_attendees_registered_help_tab'                         => [
197
+						'title'    => esc_html__('Attendees Registered', 'event_espresso'),
198
+						'filename' => 'transactions_view_transaction_attendees_registered',
199
+					],
200
+					'transactions_view_transaction_views_primary_registrant_billing_information_help_tab' => [
201
+						'title'    => esc_html__('Primary Registrant & Billing Information', 'event_espresso'),
202
+						'filename' => 'transactions_view_transaction_primary_registrant_billing_information',
203
+					],
204
+				],
205
+				'qtips'     => ['Transaction_Details_Tips'],
206
+				'metaboxes' => ['_transaction_details_metaboxes'],
207
+
208
+				'require_nonce' => false,
209
+			],
210
+		];
211
+	}
212
+
213
+
214
+	/**
215
+	 * The below methods aren't used by this class currently
216
+	 */
217
+	protected function _add_screen_options()
218
+	{
219
+		// noop
220
+	}
221
+
222
+
223
+	protected function _add_feature_pointers()
224
+	{
225
+		// noop
226
+	}
227
+
228
+
229
+	public function admin_init()
230
+	{
231
+		$EVT_ID = $this->request->getRequestParam('EVT_ID', 0, 'int');
232
+		$event_name = $this->request->getRequestParam('event_name');
233
+		$redirect_from = $this->request->getRequestParam('redirect_from', '', 'url');
234
+		// IF a registration was JUST added via the admin...
235
+		if ($EVT_ID && $event_name && $redirect_from) {
236
+			// then set a cookie so that we can block any attempts to use
237
+			// the back button as a way to enter another registration.
238
+			setcookie('ee_registration_added', $EVT_ID, time() + WEEK_IN_SECONDS, '/');
239
+			// and update the global
240
+			$_COOKIE['ee_registration_added'] = $EVT_ID;
241
+		}
242
+		EE_Registry::$i18n_js_strings['invalid_server_response'] = esc_html__(
243
+			'An error occurred! Your request may have been processed, but a valid response from the server was not received. Please refresh the page and try again.',
244
+			'event_espresso'
245
+		);
246
+		EE_Registry::$i18n_js_strings['error_occurred']          = esc_html__(
247
+			'An error occurred! Please refresh the page and try again.',
248
+			'event_espresso'
249
+		);
250
+		EE_Registry::$i18n_js_strings['txn_status_array']        = self::$_txn_status;
251
+		EE_Registry::$i18n_js_strings['pay_status_array']        = self::$_pay_status;
252
+		EE_Registry::$i18n_js_strings['payments_total']          = esc_html__('Payments Total', 'event_espresso');
253
+		EE_Registry::$i18n_js_strings['transaction_overpaid']    = esc_html__(
254
+			'This transaction has been overpaid ! Payments Total',
255
+			'event_espresso'
256
+		);
257
+	}
258
+
259
+
260
+	public function admin_notices()
261
+	{
262
+		// noop
263
+	}
264
+
265
+
266
+	public function admin_footer_scripts()
267
+	{
268
+		// noop
269
+	}
270
+
271
+
272
+	/**
273
+	 * _set_transaction_status_array
274
+	 * sets list of transaction statuses
275
+	 *
276
+	 * @access private
277
+	 * @return void
278
+	 * @throws EE_Error
279
+	 * @throws InvalidArgumentException
280
+	 * @throws InvalidDataTypeException
281
+	 * @throws InvalidInterfaceException
282
+	 */
283
+	private function _set_transaction_status_array()
284
+	{
285
+		self::$_txn_status = EEM_Transaction::instance()->status_array(true);
286
+	}
287
+
288
+
289
+	/**
290
+	 * get_transaction_status_array
291
+	 * return the transaction status array for wp_list_table
292
+	 *
293
+	 * @access public
294
+	 * @return array
295
+	 */
296
+	public function get_transaction_status_array()
297
+	{
298
+		return self::$_txn_status;
299
+	}
300
+
301
+
302
+	/**
303
+	 *    get list of payment statuses
304
+	 *
305
+	 * @access private
306
+	 * @return void
307
+	 * @throws EE_Error
308
+	 * @throws InvalidArgumentException
309
+	 * @throws InvalidDataTypeException
310
+	 * @throws InvalidInterfaceException
311
+	 */
312
+	private function _get_payment_status_array()
313
+	{
314
+		self::$_pay_status                      = EEM_Payment::instance()->status_array(true);
315
+		$this->_template_args['payment_status'] = self::$_pay_status;
316
+	}
317
+
318
+
319
+	/**
320
+	 *    _add_screen_options_default
321
+	 *
322
+	 * @access protected
323
+	 * @return void
324
+	 * @throws InvalidArgumentException
325
+	 * @throws InvalidDataTypeException
326
+	 * @throws InvalidInterfaceException
327
+	 */
328
+	protected function _add_screen_options_default()
329
+	{
330
+		$this->_per_page_screen_option();
331
+	}
332
+
333
+
334
+	/**
335
+	 * load_scripts_styles
336
+	 *
337
+	 * @access public
338
+	 * @return void
339
+	 */
340
+	public function load_scripts_styles()
341
+	{
342
+		// enqueue style
343
+		wp_register_style(
344
+			'espresso_txn',
345
+			TXN_ASSETS_URL . 'espresso_transactions_admin.css',
346
+			[],
347
+			EVENT_ESPRESSO_VERSION
348
+		);
349
+		wp_enqueue_style('espresso_txn');
350
+		// scripts
351
+		wp_register_script(
352
+			'espresso_txn',
353
+			TXN_ASSETS_URL . 'espresso_transactions_admin.js',
354
+			[
355
+				'ee_admin_js',
356
+				'ee-datepicker',
357
+				'jquery-ui-datepicker',
358
+				'jquery-ui-draggable',
359
+				'ee-dialog',
360
+				'ee-accounting',
361
+				'ee-serialize-full-array',
362
+			],
363
+			EVENT_ESPRESSO_VERSION,
364
+			true
365
+		);
366
+		wp_enqueue_script('espresso_txn');
367
+	}
368
+
369
+
370
+	/**
371
+	 *    load_scripts_styles_view_transaction
372
+	 *
373
+	 * @access public
374
+	 * @return void
375
+	 */
376
+	public function load_scripts_styles_view_transaction()
377
+	{
378
+		// styles
379
+		wp_enqueue_style('espresso-ui-theme');
380
+	}
381
+
382
+
383
+	/**
384
+	 *    load_scripts_styles_default
385
+	 *
386
+	 * @access public
387
+	 * @return void
388
+	 */
389
+	public function load_scripts_styles_default()
390
+	{
391
+		// styles
392
+		wp_enqueue_style('espresso-ui-theme');
393
+	}
394
+
395
+
396
+	/**
397
+	 *    _set_list_table_views_default
398
+	 *
399
+	 * @access protected
400
+	 * @return void
401
+	 */
402
+	protected function _set_list_table_views_default()
403
+	{
404
+		$this->_views = [
405
+			'all'        => [
406
+				'slug'  => 'all',
407
+				'label' => esc_html__('View All Transactions', 'event_espresso'),
408
+				'count' => 0,
409
+			],
410
+			'abandoned'  => [
411
+				'slug'  => 'abandoned',
412
+				'label' => esc_html__('Abandoned Transactions', 'event_espresso'),
413
+				'count' => 0,
414
+			],
415
+			'incomplete' => [
416
+				'slug'  => 'incomplete',
417
+				'label' => esc_html__('Incomplete Transactions', 'event_espresso'),
418
+				'count' => 0,
419
+			],
420
+		];
421
+		if (
422
+			/**
423
+			 * Filters whether a link to the "Failed Transactions" list table
424
+			 * appears on the Transactions Admin Page list table.
425
+			 * List display can be turned back on via the following:
426
+			 * add_filter(
427
+			 *     'FHEE__Transactions_Admin_Page___set_list_table_views_default__display_failed_txns_list',
428
+			 *     '__return_true'
429
+			 * );
430
+			 *
431
+			 * @param boolean                 $display_failed_txns_list
432
+			 * @param Transactions_Admin_Page $this
433
+			 * @since 4.9.70.p
434
+			 */
435
+			apply_filters(
436
+				'FHEE__Transactions_Admin_Page___set_list_table_views_default__display_failed_txns_list',
437
+				false,
438
+				$this
439
+			)
440
+		) {
441
+			$this->_views['failed'] = [
442
+				'slug'  => 'failed',
443
+				'label' => esc_html__('Failed Transactions', 'event_espresso'),
444
+				'count' => 0,
445
+			];
446
+		}
447
+	}
448
+
449
+
450
+	/**
451
+	 * _set_transaction_object
452
+	 * This sets the _transaction property for the transaction details screen
453
+	 *
454
+	 * @access private
455
+	 * @return void
456
+	 * @throws EE_Error
457
+	 * @throws InvalidArgumentException
458
+	 * @throws RuntimeException
459
+	 * @throws InvalidDataTypeException
460
+	 * @throws InvalidInterfaceException
461
+	 * @throws ReflectionException
462
+	 */
463
+	private function _set_transaction_object()
464
+	{
465
+		if ($this->_transaction instanceof EE_Transaction) {
466
+			return;
467
+		} //get out we've already set the object
468
+
469
+		$TXN_ID = $this->request->getRequestParam('TXN_ID', 0, 'int');
470
+
471
+		// get transaction object
472
+		$this->_transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
473
+		$this->_session     = $this->_transaction instanceof EE_Transaction
474
+			? $this->_transaction->session_data()
475
+			: null;
476
+		if ($this->_transaction instanceof EE_Transaction) {
477
+			$this->_transaction->verify_abandoned_transaction_status();
478
+		}
479
+
480
+		if (! $this->_transaction instanceof EE_Transaction) {
481
+			$error_msg = sprintf(
482
+				esc_html__(
483
+					'An error occurred and the details for the transaction with the ID # %d could not be retrieved.',
484
+					'event_espresso'
485
+				),
486
+				$TXN_ID
487
+			);
488
+			EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
489
+		}
490
+	}
491
+
492
+
493
+	/**
494
+	 *    _transaction_legend_items
495
+	 *
496
+	 * @access protected
497
+	 * @return array
498
+	 * @throws EE_Error
499
+	 * @throws InvalidArgumentException
500
+	 * @throws ReflectionException
501
+	 * @throws InvalidDataTypeException
502
+	 * @throws InvalidInterfaceException
503
+	 */
504
+	protected function _transaction_legend_items()
505
+	{
506
+		EE_Registry::instance()->load_helper('MSG_Template');
507
+		$items = [];
508
+
509
+		if (
510
+			EE_Registry::instance()->CAP->current_user_can(
511
+				'ee_read_global_messages',
512
+				'view_filtered_messages'
513
+			)
514
+		) {
515
+			$related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
516
+			if (
517
+				is_array($related_for_icon)
518
+				&& isset($related_for_icon['css_class'], $related_for_icon['label'])
519
+			) {
520
+				$items['view_related_messages'] = [
521
+					'class' => $related_for_icon['css_class'],
522
+					'desc'  => $related_for_icon['label'],
523
+				];
524
+			}
525
+		}
526
+
527
+		$items = apply_filters(
528
+			'FHEE__Transactions_Admin_Page___transaction_legend_items__items',
529
+			array_merge(
530
+				$items,
531
+				[
532
+					'view_details'          => [
533
+						'class' => 'dashicons dashicons-cart',
534
+						'desc'  => esc_html__('View Transaction Details', 'event_espresso'),
535
+					],
536
+					'view_invoice'          => [
537
+						'class' => 'dashicons dashicons-media-spreadsheet',
538
+						'desc'  => esc_html__('View Transaction Invoice', 'event_espresso'),
539
+					],
540
+					'view_receipt'          => [
541
+						'class' => 'dashicons dashicons-text-page',
542
+						'desc'  => esc_html__('View Transaction Receipt', 'event_espresso'),
543
+					],
544
+					'view_registration'     => [
545
+						'class' => 'dashicons dashicons-clipboard',
546
+						'desc'  => esc_html__('View Registration Details', 'event_espresso'),
547
+					],
548
+					'payment_overview_link' => [
549
+						'class' => 'dashicons dashicons-money',
550
+						'desc'  => esc_html__('Make Payment on Frontend', 'event_espresso'),
551
+					],
552
+				]
553
+			)
554
+		);
555
+
556
+		if (
557
+			EEH_MSG_Template::is_mt_active('payment_reminder')
558
+			&& EE_Registry::instance()->CAP->current_user_can(
559
+				'ee_send_message',
560
+				'espresso_transactions_send_payment_reminder'
561
+			)
562
+		) {
563
+			$items['send_payment_reminder'] = [
564
+				'class' => 'dashicons dashicons-email-alt',
565
+				'desc'  => esc_html__('Send Payment Reminder', 'event_espresso'),
566
+			];
567
+		} else {
568
+			$items['blank*'] = [
569
+				'class' => '',
570
+				'desc'  => '',
571
+			];
572
+		}
573
+		$more_items = apply_filters(
574
+			'FHEE__Transactions_Admin_Page___transaction_legend_items__more_items',
575
+			[
576
+				'overpaid'   => [
577
+					'class' => 'ee-status-legend ee-status-bg--' . EEM_Transaction::overpaid_status_code,
578
+					'desc'  => EEH_Template::pretty_status(
579
+						EEM_Transaction::overpaid_status_code,
580
+						false,
581
+						'sentence'
582
+					),
583
+				],
584
+				'complete'   => [
585
+					'class' => 'ee-status-legend ee-status-bg--' . EEM_Transaction::complete_status_code,
586
+					'desc'  => EEH_Template::pretty_status(
587
+						EEM_Transaction::complete_status_code,
588
+						false,
589
+						'sentence'
590
+					),
591
+				],
592
+				'incomplete' => [
593
+					'class' => 'ee-status-legend ee-status-bg--' . EEM_Transaction::incomplete_status_code,
594
+					'desc'  => EEH_Template::pretty_status(
595
+						EEM_Transaction::incomplete_status_code,
596
+						false,
597
+						'sentence'
598
+					),
599
+				],
600
+				'abandoned'  => [
601
+					'class' => 'ee-status-legend ee-status-bg--' . EEM_Transaction::abandoned_status_code,
602
+					'desc'  => EEH_Template::pretty_status(
603
+						EEM_Transaction::abandoned_status_code,
604
+						false,
605
+						'sentence'
606
+					),
607
+				],
608
+				'failed'     => [
609
+					'class' => 'ee-status-legend ee-status-bg--' . EEM_Transaction::failed_status_code,
610
+					'desc'  => EEH_Template::pretty_status(
611
+						EEM_Transaction::failed_status_code,
612
+						false,
613
+						'sentence'
614
+					),
615
+				],
616
+			]
617
+		);
618
+
619
+		return array_merge($items, $more_items);
620
+	}
621
+
622
+
623
+	/**
624
+	 *    _transactions_overview_list_table
625
+	 *
626
+	 * @access protected
627
+	 * @return void
628
+	 * @throws DomainException
629
+	 * @throws EE_Error
630
+	 * @throws InvalidArgumentException
631
+	 * @throws InvalidDataTypeException
632
+	 * @throws InvalidInterfaceException
633
+	 * @throws ReflectionException
634
+	 */
635
+	protected function _transactions_overview_list_table()
636
+	{
637
+		$this->_admin_page_title = esc_html__('Transactions', 'event_espresso');
638
+
639
+		$EVT_ID = $this->request->getRequestParam('EVT_ID', 0, 'int');
640
+		$event = EEM_Event::instance()->get_one_by_ID($EVT_ID);
641
+		$this->_template_args['admin_page_header'] = $event instanceof EE_Event
642
+			? sprintf(
643
+				esc_html__('%sViewing Transactions for the Event: %s%s', 'event_espresso'),
644
+				'<h3>',
645
+				'<a href="'
646
+				. EE_Admin_Page::add_query_args_and_nonce(
647
+					['action' => 'edit', 'post' => $event->ID()],
648
+					EVENTS_ADMIN_URL
649
+				)
650
+				. '" title="'
651
+				. esc_attr__('Click to Edit event', 'event_espresso')
652
+				. '">' . $event->name() . '</a>',
653
+				'</h3>'
654
+			)
655
+			: '';
656
+		$this->_template_args['after_list_table']  = $this->_display_legend($this->_transaction_legend_items());
657
+		$this->display_admin_list_table_page_with_no_sidebar();
658
+	}
659
+
660
+
661
+	/**
662
+	 *    _transaction_details
663
+	 * generates HTML for the View Transaction Details Admin page
664
+	 *
665
+	 * @access protected
666
+	 * @return void
667
+	 * @throws DomainException
668
+	 * @throws EE_Error
669
+	 * @throws InvalidArgumentException
670
+	 * @throws InvalidDataTypeException
671
+	 * @throws InvalidInterfaceException
672
+	 * @throws RuntimeException
673
+	 * @throws ReflectionException
674
+	 */
675
+	protected function _transaction_details()
676
+	{
677
+		do_action('AHEE__Transactions_Admin_Page__transaction_details__start', $this->_transaction);
678
+
679
+		$this->_set_transaction_status_array();
680
+
681
+		$this->_template_args                      = [];
682
+		$this->_template_args['transactions_page'] = $this->_wp_page_slug;
683
+
684
+		$this->_set_transaction_object();
685
+
686
+		if (! $this->_transaction instanceof EE_Transaction) {
687
+			return;
688
+		}
689
+
690
+		$this->_template_args['txn_nmbr']['value'] = $this->_transaction->ID();
691
+		$this->_template_args['txn_nmbr']['label'] = esc_html__('Transaction Number', 'event_espresso');
692
+
693
+		$this->_template_args['txn_datetime']['value'] = $this->_transaction->get_i18n_datetime('TXN_timestamp');
694
+		$this->_template_args['txn_datetime']['label'] = esc_html__('Date', 'event_espresso');
695
+
696
+		$this->_template_args['txn_status']['value'] = self::$_txn_status[ $this->_transaction->status_ID() ];
697
+		$this->_template_args['txn_status']['label'] = esc_html__('Transaction Status', 'event_espresso');
698
+		$this->_template_args['txn_status']['class'] = $this->_transaction->status_ID();
699
+
700
+		$txn_total  = $this->_transaction->total();
701
+		$total_paid = $this->_transaction->paid();
702
+		$amount_due = $txn_total - $total_paid;
703
+
704
+		$this->_template_args['grand_total'] = $txn_total;
705
+		$this->_template_args['total_paid']  = $total_paid;
706
+
707
+		$this->_template_args['amount_due'] = EEH_Template::format_currency($amount_due, false, false);
708
+
709
+		$this->_template_args['amount_due_class'] = '';
710
+
711
+		if ($txn_total === (float) 0) {
712
+			// free event
713
+			$this->_template_args['amount_due'] = false;
714
+		} elseif ($amount_due < (float) 0) {
715
+			// overpaid
716
+			$this->_template_args['amount_due_class'] = 'txn-overview-no-payment-spn';
717
+		} elseif ($amount_due > (float) 0) {
718
+			// monies owing
719
+			$this->_template_args['amount_due_class'] = 'txn-overview-part-payment-spn ee-txn-amount-owing';
720
+		} elseif ($total_paid === (float) 0) {
721
+			// no payments made yet
722
+			$this->_template_args['amount_due_class'] = 'txn-overview-no-payment-spn';
723
+		}
724
+
725
+		$payment_method = $this->_transaction->payment_method();
726
+
727
+		$this->_template_args['method_of_payment_name'] = $payment_method instanceof EE_Payment_Method
728
+			? $payment_method->admin_name()
729
+			: esc_html__('Unknown', 'event_espresso');
730
+
731
+		$this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
732
+		// link back to overview
733
+		$this->_template_args['txn_overview_url'] = $this->request->getServerParam(
734
+			'HTTP_REFERER',
735
+			TXN_ADMIN_URL
736
+		);
737
+
738
+
739
+		// next link
740
+		$next_txn                                 = $this->_transaction->next(
741
+			null,
742
+			[['STS_ID' => ['!=', EEM_Transaction::failed_status_code]]],
743
+			'TXN_ID'
744
+		);
745
+		$this->_template_args['next_transaction'] = $next_txn
746
+			? $this->_next_link(
747
+				EE_Admin_Page::add_query_args_and_nonce(
748
+					['action' => 'view_transaction', 'TXN_ID' => $next_txn['TXN_ID']],
749
+					TXN_ADMIN_URL
750
+				),
751
+				'dashicons dashicons-arrow-right ee-icon-size-22'
752
+			)
753
+			: '';
754
+		// previous link
755
+		$previous_txn                                 = $this->_transaction->previous(
756
+			null,
757
+			[['STS_ID' => ['!=', EEM_Transaction::failed_status_code]]],
758
+			'TXN_ID'
759
+		);
760
+		$this->_template_args['previous_transaction'] = $previous_txn
761
+			? $this->_previous_link(
762
+				EE_Admin_Page::add_query_args_and_nonce(
763
+					['action' => 'view_transaction', 'TXN_ID' => $previous_txn['TXN_ID']],
764
+					TXN_ADMIN_URL
765
+				),
766
+				'dashicons dashicons-arrow-left ee-icon-size-22'
767
+			)
768
+			: '';
769
+
770
+		$EVT_ID        = $this->request->getRequestParam('EVT_ID', 0, 'int');
771
+		$event_name    = $this->request->getRequestParam('event_name');
772
+		$redirect_from = $this->request->getRequestParam('redirect_from', '', 'url');
773
+
774
+		// were we just redirected here after adding a new registration ???
775
+		if ($EVT_ID && $event_name && $redirect_from) {
776
+			if (
777
+				EE_Registry::instance()->CAP->current_user_can(
778
+					'ee_edit_registrations',
779
+					'espresso_registrations_new_registration',
780
+					$EVT_ID
781
+				)
782
+			) {
783
+				$this->_admin_page_title .= '<a id="add-new-registration" class="add-new-h2 button--primary" href="';
784
+				$this->_admin_page_title .= EE_Admin_Page::add_query_args_and_nonce(
785
+					[
786
+						'page'     => 'espresso_registrations',
787
+						'action'   => 'new_registration',
788
+						'return'   => 'default',
789
+						'TXN_ID'   => $this->_transaction->ID(),
790
+						'event_id' => $EVT_ID,
791
+					],
792
+					REG_ADMIN_URL
793
+				);
794
+				$this->_admin_page_title .= '">';
795
+
796
+				$this->_admin_page_title .= sprintf(
797
+					esc_html__('Add Another New Registration to Event: "%1$s" ?', 'event_espresso'),
798
+					htmlentities(urldecode($event_name), ENT_QUOTES, 'UTF-8')
799
+				);
800
+				$this->_admin_page_title .= '</a>';
801
+			}
802
+			EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
803
+		}
804
+		// grab messages at the last second
805
+		$this->_template_args['notices'] = EE_Error::get_notices();
806
+		// path to template
807
+		$template_path                             = TXN_TEMPLATE_PATH . 'txn_admin_details_header.template.php';
808
+		$this->_template_args['admin_page_header'] = EEH_Template::display_template(
809
+			$template_path,
810
+			$this->_template_args,
811
+			true
812
+		);
813
+
814
+		// the details template wrapper
815
+		$this->display_admin_page_with_sidebar();
816
+	}
817
+
818
+
819
+	/**
820
+	 *        _transaction_details_metaboxes
821
+	 *
822
+	 * @access protected
823
+	 * @return void
824
+	 * @throws EE_Error
825
+	 * @throws InvalidArgumentException
826
+	 * @throws InvalidDataTypeException
827
+	 * @throws InvalidInterfaceException
828
+	 * @throws RuntimeException
829
+	 * @throws ReflectionException
830
+	 */
831
+	protected function _transaction_details_metaboxes()
832
+	{
833
+
834
+		$this->_set_transaction_object();
835
+
836
+		if (! $this->_transaction instanceof EE_Transaction) {
837
+			return;
838
+		}
839
+		$this->addMetaBox(
840
+			'edit-txn-details-mbox',
841
+			'<span>' . esc_html__('Transaction Details', 'event_espresso')
842
+			. '&nbsp;<span class="dashicons dashicons-cart" ></span></span>',
843
+			[$this, 'txn_details_meta_box'],
844
+			$this->_wp_page_slug
845
+		);
846
+		$this->addMetaBox(
847
+			'edit-txn-attendees-mbox',
848
+			'<span>' . esc_html__('Attendees Registered in this Transaction', 'event_espresso')
849
+			. '&nbsp;<span class="dashicons dashicons-groups" ></span></span>',
850
+			[$this, 'txn_attendees_meta_box'],
851
+			$this->_wp_page_slug,
852
+			'normal',
853
+			'high',
854
+			['TXN_ID' => $this->_transaction->ID()]
855
+		);
856
+		$this->addMetaBox(
857
+			'edit-txn-registrant-mbox',
858
+			esc_html__('Primary Contact', 'event_espresso'),
859
+			[$this, 'txn_registrant_side_meta_box'],
860
+			$this->_wp_page_slug,
861
+			'side'
862
+		);
863
+		$this->addMetaBox(
864
+			'edit-txn-billing-info-mbox',
865
+			esc_html__('Billing Information', 'event_espresso'),
866
+			[$this, 'txn_billing_info_side_meta_box'],
867
+			$this->_wp_page_slug,
868
+			'side'
869
+		);
870
+	}
871
+
872
+
873
+	/**
874
+	 * Callback for transaction actions metabox.
875
+	 *
876
+	 * @param EE_Transaction|null $transaction
877
+	 * @return string
878
+	 * @throws DomainException
879
+	 * @throws EE_Error
880
+	 * @throws InvalidArgumentException
881
+	 * @throws InvalidDataTypeException
882
+	 * @throws InvalidInterfaceException
883
+	 * @throws ReflectionException
884
+	 * @throws RuntimeException
885
+	 */
886
+	public function getActionButtons(EE_Transaction $transaction = null)
887
+	{
888
+		$content = '';
889
+		$actions = [];
890
+		if (! $transaction instanceof EE_Transaction) {
891
+			return $content;
892
+		}
893
+		/** @var EE_Registration $primary_registration */
894
+		$primary_registration = $transaction->primary_registration();
895
+		$attendee             = $primary_registration instanceof EE_Registration
896
+			? $primary_registration->attendee()
897
+			: null;
898
+
899
+		if (
900
+			$attendee instanceof EE_Attendee
901
+			&& EE_Registry::instance()->CAP->current_user_can(
902
+				'ee_send_message',
903
+				'espresso_transactions_send_payment_reminder'
904
+			)
905
+		) {
906
+			$actions['payment_reminder'] =
907
+				EEH_MSG_Template::is_mt_active('payment_reminder')
908
+				&& $this->_transaction->status_ID() !== EEM_Transaction::complete_status_code
909
+				&& $this->_transaction->status_ID() !== EEM_Transaction::overpaid_status_code
910
+					? EEH_Template::get_button_or_link(
911
+						EE_Admin_Page::add_query_args_and_nonce(
912
+							[
913
+							'action'      => 'send_payment_reminder',
914
+							'TXN_ID'      => $this->_transaction->ID(),
915
+							'redirect_to' => 'view_transaction',
916
+							],
917
+							TXN_ADMIN_URL
918
+						),
919
+						esc_html__(' Send Payment Reminder', 'event_espresso'),
920
+						'button button--secondary',
921
+						'dashicons dashicons-email-alt'
922
+					)
923
+					: '';
924
+		}
925
+
926
+		if (
927
+			EE_Registry::instance()->CAP->current_user_can(
928
+				'ee_edit_payments',
929
+				'espresso_transactions_recalculate_line_items'
930
+			)
931
+		) {
932
+			$actions['recalculate_line_items'] = EEH_Template::get_button_or_link(
933
+				EE_Admin_Page::add_query_args_and_nonce(
934
+					[
935
+						'action'      => 'espresso_recalculate_line_items',
936
+						'TXN_ID'      => $this->_transaction->ID(),
937
+						'redirect_to' => 'view_transaction',
938
+					],
939
+					TXN_ADMIN_URL
940
+				),
941
+				esc_html__(' Recalculate Taxes and Total', 'event_espresso'),
942
+				'button button--secondary',
943
+				'dashicons dashicons-update'
944
+			);
945
+		}
946
+
947
+		if (
948
+			$primary_registration instanceof EE_Registration
949
+			&& EEH_MSG_Template::is_mt_active('receipt')
950
+		) {
951
+			$actions['receipt'] = EEH_Template::get_button_or_link(
952
+				$primary_registration->receipt_url(),
953
+				esc_html__('View Receipt', 'event_espresso'),
954
+				'button button--secondary',
955
+				'dashicons dashicons-text-page'
956
+			);
957
+		}
958
+
959
+		if (
960
+			$primary_registration instanceof EE_Registration
961
+			&& EEH_MSG_Template::is_mt_active('invoice')
962
+		) {
963
+			$actions['invoice'] = EEH_Template::get_button_or_link(
964
+				$primary_registration->invoice_url(),
965
+				esc_html__('View Invoice', 'event_espresso'),
966
+				'button button--secondary',
967
+				'dashicons dashicons-media-spreadsheet'
968
+			);
969
+		}
970
+		$actions = array_filter(
971
+			apply_filters('FHEE__Transactions_Admin_Page__getActionButtons__actions', $actions, $transaction)
972
+		);
973
+		if ($actions) {
974
+			$content .= implode('', $actions);
975
+		}
976
+		return $content;
977
+	}
978
+
979
+
980
+	/**
981
+	 * txn_details_meta_box
982
+	 * generates HTML for the Transaction main meta box
983
+	 *
984
+	 * @return void
985
+	 * @throws DomainException
986
+	 * @throws EE_Error
987
+	 * @throws InvalidArgumentException
988
+	 * @throws InvalidDataTypeException
989
+	 * @throws InvalidInterfaceException
990
+	 * @throws RuntimeException
991
+	 * @throws ReflectionException
992
+	 */
993
+	public function txn_details_meta_box()
994
+	{
995
+		$this->_set_transaction_object();
996
+		$this->_template_args['TXN_ID']              = $this->_transaction->ID();
997
+		$this->_template_args['attendee']            =
998
+			$this->_transaction->primary_registration() instanceof EE_Registration
999
+				? $this->_transaction->primary_registration()->attendee()
1000
+				: null;
1001
+		$this->_template_args['can_edit_payments']   = EE_Registry::instance()->CAP->current_user_can(
1002
+			'ee_edit_payments',
1003
+			'apply_payment_or_refund_from_registration_details'
1004
+		);
1005
+		$this->_template_args['can_delete_payments'] = EE_Registry::instance()->CAP->current_user_can(
1006
+			'ee_delete_payments',
1007
+			'delete_payment_from_registration_details'
1008
+		);
1009
+
1010
+		// get line table
1011
+		EEH_Autoloader::register_line_item_display_autoloaders();
1012
+		$Line_Item_Display                       = new EE_Line_Item_Display(
1013
+			'admin_table',
1014
+			'EE_Admin_Table_Line_Item_Display_Strategy'
1015
+		);
1016
+		$this->_template_args['line_item_table'] = $Line_Item_Display->display_line_item(
1017
+			$this->_transaction->total_line_item()
1018
+		);
1019
+		$this->_template_args['REG_code']        =
1020
+			$this->_transaction->primary_registration() instanceof EE_Registration
1021
+				? $this->_transaction->primary_registration()->reg_code()
1022
+				: null;
1023
+		// process taxes
1024
+		$taxes                         = $this->_transaction->line_items([['LIN_type' => EEM_Line_Item::type_tax]]);
1025
+		$this->_template_args['taxes'] = ! empty($taxes) ? $taxes : false;
1026
+
1027
+		$this->_template_args['grand_total']     = EEH_Template::format_currency(
1028
+			$this->_transaction->total(),
1029
+			false,
1030
+			false
1031
+		);
1032
+		$this->_template_args['grand_raw_total'] = $this->_transaction->total();
1033
+		$this->_template_args['TXN_status']      = $this->_transaction->status_ID();
1034
+
1035
+		// process payment details
1036
+		$payments = $this->_transaction->payments();
1037
+		if (! empty($payments)) {
1038
+			$this->_template_args['payments']              = $payments;
1039
+			$this->_template_args['existing_reg_payments'] = $this->_get_registration_payment_IDs($payments);
1040
+		} else {
1041
+			$this->_template_args['payments']              = false;
1042
+			$this->_template_args['existing_reg_payments'] = [];
1043
+		}
1044
+
1045
+		$this->_template_args['edit_payment_url']   = add_query_arg(['action' => 'edit_payment'], TXN_ADMIN_URL);
1046
+		$this->_template_args['delete_payment_url'] = add_query_arg(
1047
+			['action' => 'espresso_delete_payment'],
1048
+			TXN_ADMIN_URL
1049
+		);
1050
+
1051
+		if (isset($txn_details['invoice_number'])) {
1052
+			$this->_template_args['txn_details']['invoice_number']['value'] = $this->_template_args['REG_code'];
1053
+			$this->_template_args['txn_details']['invoice_number']['label'] = esc_html__(
1054
+				'Invoice Number',
1055
+				'event_espresso'
1056
+			);
1057
+		}
1058
+
1059
+		$this->_template_args['txn_details']['registration_session']['value'] =
1060
+			$this->_transaction->primary_registration() instanceof EE_Registration
1061
+				? $this->_transaction->primary_registration()->session_ID()
1062
+				: null;
1063
+		$this->_template_args['txn_details']['registration_session']['label'] = esc_html__(
1064
+			'Registration Session',
1065
+			'event_espresso'
1066
+		);
1067
+
1068
+		$this->_template_args['txn_details']['ip_address']['value'] = $this->_session['ip_address'] ?? '';
1069
+		$this->_template_args['txn_details']['ip_address']['label'] = esc_html__(
1070
+			'Transaction placed from IP',
1071
+			'event_espresso'
1072
+		);
1073
+
1074
+		$this->_template_args['txn_details']['user_agent']['value'] = $this->_session['user_agent'] ?? '';
1075
+		$this->_template_args['txn_details']['user_agent']['label'] = esc_html__(
1076
+			'Registrant User Agent',
1077
+			'event_espresso'
1078
+		);
1079
+
1080
+		$reg_steps = '<div class="ee-txn-reg-step-status-steps ee-layout-row">';
1081
+		foreach ($this->_transaction->reg_steps() as $reg_step => $reg_step_status) {
1082
+			if ($reg_step_status === true) {
1083
+				$reg_steps .= '<div class="ee-status-pill ee-status-bg--success">'
1084
+							  . sprintf(
1085
+								  esc_html__('%1$s : Completed', 'event_espresso'),
1086
+								  ucwords(str_replace('_', ' ', $reg_step))
1087
+							  )
1088
+							  . '</div>';
1089
+			} elseif ($reg_step_status !== false && is_numeric($reg_step_status)) {
1090
+				$reg_steps .= '<div class="ee-status-pill ee-status-bg--attention">'
1091
+							  . sprintf(
1092
+								  esc_html__('%1$s : Initiated %2$s', 'event_espresso'),
1093
+								  ucwords(str_replace('_', ' ', $reg_step)),
1094
+								  date(
1095
+									  get_option('date_format') . ' ' . get_option('time_format'),
1096
+									  $reg_step_status + (get_option('gmt_offset') * HOUR_IN_SECONDS)
1097
+								  )
1098
+							  )
1099
+							  . '</div>';
1100
+			} else {
1101
+				$reg_steps .= '<div class="ee-status-pill ee-status-bg--error">'
1102
+							  . sprintf(
1103
+								  esc_html__('%1$s : Never Initiated', 'event_espresso'),
1104
+								  ucwords(str_replace('_', ' ', $reg_step))
1105
+							  )
1106
+							  . '</div>';
1107
+			}
1108
+		}
1109
+		$reg_steps                                                 .= '</ul>';
1110
+		$this->_template_args['txn_details']['reg_steps']['value'] = $reg_steps;
1111
+		$this->_template_args['txn_details']['reg_steps']['label'] = esc_html__(
1112
+			'Registration Step Progress',
1113
+			'event_espresso'
1114
+		);
1115
+
1116
+
1117
+		$this->_get_registrations_to_apply_payment_to();
1118
+		$this->_get_payment_methods($payments);
1119
+		$this->_get_payment_status_array();
1120
+		$this->_get_reg_status_selection(); // sets up the template args for the reg status array for the transaction.
1121
+
1122
+		$this->_template_args['transaction_form_url']    = add_query_arg(
1123
+			[
1124
+				'action'  => 'edit_transaction',
1125
+				'process' => 'transaction',
1126
+			],
1127
+			TXN_ADMIN_URL
1128
+		);
1129
+		$this->_template_args['apply_payment_form_url']  = add_query_arg(
1130
+			[
1131
+				'page'   => 'espresso_transactions',
1132
+				'action' => 'espresso_apply_payment',
1133
+			],
1134
+			TXN_ADMIN_URL
1135
+		);
1136
+		$this->_template_args['delete_payment_form_url'] = add_query_arg(
1137
+			[
1138
+				'page'   => 'espresso_transactions',
1139
+				'action' => 'espresso_delete_payment',
1140
+			],
1141
+			TXN_ADMIN_URL
1142
+		);
1143
+
1144
+		$this->_template_args['action_buttons'] = $this->getActionButtons($this->_transaction);
1145
+
1146
+		// 'espresso_delete_payment_nonce'
1147
+
1148
+		$template_path = TXN_TEMPLATE_PATH . 'txn_admin_details_main_meta_box_txn_details.template.php';
1149
+		echo EEH_Template::display_template($template_path, $this->_template_args, true);
1150
+	}
1151
+
1152
+
1153
+	/**
1154
+	 * _get_registration_payment_IDs
1155
+	 *    generates an array of Payment IDs and their corresponding Registration IDs
1156
+	 *
1157
+	 * @access protected
1158
+	 * @param EE_Payment[] $payments
1159
+	 * @return array
1160
+	 * @throws EE_Error
1161
+	 * @throws InvalidArgumentException
1162
+	 * @throws InvalidDataTypeException
1163
+	 * @throws InvalidInterfaceException
1164
+	 * @throws ReflectionException
1165
+	 */
1166
+	protected function _get_registration_payment_IDs($payments = [])
1167
+	{
1168
+		$existing_reg_payments = [];
1169
+		// get all reg payments for these payments
1170
+		$reg_payments = EEM_Registration_Payment::instance()->get_all(
1171
+			[
1172
+				[
1173
+					'PAY_ID' => [
1174
+						'IN',
1175
+						array_keys($payments),
1176
+					],
1177
+				],
1178
+			]
1179
+		);
1180
+		if (! empty($reg_payments)) {
1181
+			foreach ($payments as $payment) {
1182
+				if (! $payment instanceof EE_Payment) {
1183
+					continue;
1184
+				} elseif (! isset($existing_reg_payments[ $payment->ID() ])) {
1185
+					$existing_reg_payments[ $payment->ID() ] = [];
1186
+				}
1187
+				foreach ($reg_payments as $reg_payment) {
1188
+					if (
1189
+						$reg_payment instanceof EE_Registration_Payment
1190
+						&& $reg_payment->payment_ID() === $payment->ID()
1191
+					) {
1192
+						$existing_reg_payments[ $payment->ID() ][] = $reg_payment->registration_ID();
1193
+					}
1194
+				}
1195
+			}
1196
+		}
1197
+
1198
+		return $existing_reg_payments;
1199
+	}
1200
+
1201
+
1202
+	/**
1203
+	 * _get_registrations_to_apply_payment_to
1204
+	 *    generates HTML for displaying a series of checkboxes in the admin payment modal window
1205
+	 * which allows the admin to only apply the payment to the specific registrations
1206
+	 *
1207
+	 * @access protected
1208
+	 * @return void
1209
+	 * @throws EE_Error
1210
+	 * @throws InvalidArgumentException
1211
+	 * @throws InvalidDataTypeException
1212
+	 * @throws InvalidInterfaceException
1213
+	 * @throws ReflectionException
1214
+	 */
1215
+	protected function _get_registrations_to_apply_payment_to()
1216
+	{
1217
+		// we want any registration with an active status (ie: not deleted or cancelled)
1218
+		$query_params                      = [
1219
+			[
1220
+				'STS_ID' => [
1221
+					'IN',
1222
+					[
1223
+						EEM_Registration::status_id_approved,
1224
+						EEM_Registration::status_id_pending_payment,
1225
+						EEM_Registration::status_id_not_approved,
1226
+					],
1227
+				],
1228
+			],
1229
+		];
1230
+		$registrations_to_apply_payment_to = EEH_HTML::br() . EEH_HTML::div(
1231
+			'',
1232
+			'txn-admin-apply-payment-to-registrations-dv',
1233
+			'',
1234
+			'clear: both; margin: 1.5em 0 0; display: none;'
1235
+		);
1236
+		$registrations_to_apply_payment_to .= EEH_HTML::br() . EEH_HTML::div('', '', 'admin-primary-mbox-tbl-wrap');
1237
+		$registrations_to_apply_payment_to .= EEH_HTML::table('', '', 'admin-primary-mbox-tbl striped');
1238
+		$registrations_to_apply_payment_to .= EEH_HTML::thead(
1239
+			EEH_HTML::tr(
1240
+				EEH_HTML::th(esc_html__('ID', 'event_espresso')) .
1241
+				EEH_HTML::th(esc_html__('Registrant', 'event_espresso')) .
1242
+				EEH_HTML::th(esc_html__('Ticket', 'event_espresso')) .
1243
+				EEH_HTML::th(esc_html__('Event', 'event_espresso')) .
1244
+				EEH_HTML::th(esc_html__('Paid', 'event_espresso'), '', 'txn-admin-payment-paid-td jst-cntr') .
1245
+				EEH_HTML::th(esc_html__('Owing', 'event_espresso'), '', 'txn-admin-payment-owing-td jst-cntr') .
1246
+				EEH_HTML::th(esc_html__('Apply', 'event_espresso'), '', 'jst-cntr')
1247
+			)
1248
+		);
1249
+		$registrations_to_apply_payment_to .= EEH_HTML::tbody();
1250
+		// get registrations for TXN
1251
+		$registrations         = $this->_transaction->registrations($query_params);
1252
+		$existing_reg_payments = $this->_template_args['existing_reg_payments'];
1253
+		foreach ($registrations as $registration) {
1254
+			if ($registration instanceof EE_Registration) {
1255
+				$attendee_name                     = $registration->attendee() instanceof EE_Attendee
1256
+					? $registration->attendee()->full_name()
1257
+					: esc_html__('Unknown Attendee', 'event_espresso');
1258
+				$owing                             = $registration->final_price() - $registration->paid();
1259
+				$taxable                           = $registration->ticket()->taxable()
1260
+					? ' <span class="smaller-text lt-grey-text"> ' . esc_html__('+ tax', 'event_espresso') . '</span>'
1261
+					: '';
1262
+				$checked                           = empty($existing_reg_payments)
1263
+													 || in_array($registration->ID(), $existing_reg_payments, true)
1264
+					? ' checked'
1265
+					: '';
1266
+				$disabled                          = $registration->final_price() > 0 ? '' : ' disabled';
1267
+				$registrations_to_apply_payment_to .= EEH_HTML::tr(
1268
+					EEH_HTML::td($registration->ID()) .
1269
+					EEH_HTML::td($attendee_name) .
1270
+					EEH_HTML::td(
1271
+						$registration->ticket()->name() . ' : ' . $registration->ticket()->pretty_price() . $taxable
1272
+					) .
1273
+					EEH_HTML::td($registration->event_name()) .
1274
+					EEH_HTML::td($registration->pretty_paid(), '', 'txn-admin-payment-paid-td jst-cntr') .
1275
+					EEH_HTML::td(
1276
+						EEH_Template::format_currency($owing),
1277
+						'',
1278
+						'txn-admin-payment-owing-td jst-cntr'
1279
+					) .
1280
+					EEH_HTML::td(
1281
+						'<input type="checkbox" value="' . $registration->ID()
1282
+						. '" name="txn_admin_payment[registrations]"'
1283
+						. $checked . $disabled . '>',
1284
+						'',
1285
+						'jst-cntr'
1286
+					),
1287
+					'apply-payment-registration-row-' . $registration->ID()
1288
+				);
1289
+			}
1290
+		}
1291
+		$registrations_to_apply_payment_to                         .= EEH_HTML::tbodyx();
1292
+		$registrations_to_apply_payment_to                         .= EEH_HTML::tablex();
1293
+		$registrations_to_apply_payment_to                         .= EEH_HTML::divx();
1294
+		$registrations_to_apply_payment_to                         .= EEH_HTML::p(
1295
+			esc_html__(
1296
+				'The payment will only be applied to the registrations that have a check mark in their corresponding check box. Checkboxes for free registrations have been disabled.',
1297
+				'event_espresso'
1298
+			),
1299
+			'',
1300
+			'clear description'
1301
+		);
1302
+		$registrations_to_apply_payment_to                         .= EEH_HTML::divx();
1303
+		$this->_template_args['registrations_to_apply_payment_to'] = $registrations_to_apply_payment_to;
1304
+	}
1305
+
1306
+
1307
+	/**
1308
+	 * _get_reg_status_selection
1309
+	 *
1310
+	 * @return void
1311
+	 * @throws EE_Error
1312
+	 * @todo   this will need to be adjusted either once MER comes along OR we move default reg status to tickets
1313
+	 *         instead of events.
1314
+	 * @access protected
1315
+	 */
1316
+	protected function _get_reg_status_selection()
1317
+	{
1318
+		// first get all possible statuses
1319
+		$statuses = EEM_Registration::reg_status_array([], true);
1320
+		// let's add a "don't change" option.
1321
+		$status_array['NAN']                                 = esc_html__('Leave the Same', 'event_espresso');
1322
+		$status_array                                        = array_merge($status_array, $statuses);
1323
+		$this->_template_args['status_change_select']        = EEH_Form_Fields::select_input(
1324
+			'txn_reg_status_change[reg_status]',
1325
+			$status_array,
1326
+			'NAN',
1327
+			'id="txn-admin-payment-reg-status-inp"',
1328
+			'txn-reg-status-change-reg-status'
1329
+		);
1330
+		$this->_template_args['delete_status_change_select'] = EEH_Form_Fields::select_input(
1331
+			'delete_txn_reg_status_change[reg_status]',
1332
+			$status_array,
1333
+			'NAN',
1334
+			'delete-txn-admin-payment-reg-status-inp',
1335
+			'delete-txn-reg-status-change-reg-status'
1336
+		);
1337
+	}
1338
+
1339
+
1340
+	/**
1341
+	 *    _get_payment_methods
1342
+	 * Gets all the payment methods available generally, or the ones that are already
1343
+	 * selected on these payments (in case their payment methods are no longer active).
1344
+	 * Has the side-effect of updating the template args' payment_methods item
1345
+	 *
1346
+	 * @access private
1347
+	 * @param EE_Payment[] to show on this page
1348
+	 * @return void
1349
+	 * @throws EE_Error
1350
+	 * @throws InvalidArgumentException
1351
+	 * @throws InvalidDataTypeException
1352
+	 * @throws InvalidInterfaceException
1353
+	 * @throws ReflectionException
1354
+	 */
1355
+	private function _get_payment_methods($payments = [])
1356
+	{
1357
+		$payment_methods_of_payments = [];
1358
+		foreach ($payments as $payment) {
1359
+			if ($payment instanceof EE_Payment) {
1360
+				$payment_methods_of_payments[] = $payment->ID();
1361
+			}
1362
+		}
1363
+		if ($payment_methods_of_payments) {
1364
+			$query_args = [
1365
+				[
1366
+					'OR*payment_method_for_payment' => [
1367
+						'PMD_ID'    => ['IN', $payment_methods_of_payments],
1368
+						'PMD_scope' => ['LIKE', '%' . EEM_Payment_Method::scope_admin . '%'],
1369
+					],
1370
+				],
1371
+			];
1372
+		} else {
1373
+			$query_args = [['PMD_scope' => ['LIKE', '%' . EEM_Payment_Method::scope_admin . '%']]];
1374
+		}
1375
+		$this->_template_args['payment_methods'] = EEM_Payment_Method::instance()->get_all($query_args);
1376
+	}
1377
+
1378
+
1379
+	/**
1380
+	 * txn_attendees_meta_box
1381
+	 *    generates HTML for the Attendees Transaction main meta box
1382
+	 *
1383
+	 * @access public
1384
+	 * @param WP_Post $post
1385
+	 * @param array   $metabox
1386
+	 * @return void
1387
+	 * @throws DomainException
1388
+	 * @throws EE_Error
1389
+	 * @throws InvalidArgumentException
1390
+	 * @throws InvalidDataTypeException
1391
+	 * @throws InvalidInterfaceException
1392
+	 * @throws ReflectionException
1393
+	 */
1394
+	public function txn_attendees_meta_box($post, $metabox = ['args' => []])
1395
+	{
1396
+
1397
+		/** @noinspection NonSecureExtractUsageInspection */
1398
+		extract($metabox['args']);
1399
+		$this->_template_args['post']            = $post;
1400
+		$this->_template_args['event_attendees'] = [];
1401
+		// process items in cart
1402
+		$line_items = $this->_transaction->get_many_related(
1403
+			'Line_Item',
1404
+			[['LIN_type' => 'line-item']]
1405
+		);
1406
+		if (! empty($line_items)) {
1407
+			foreach ($line_items as $item) {
1408
+				if ($item instanceof EE_Line_Item) {
1409
+					switch ($item->OBJ_type()) {
1410
+						case 'Event':
1411
+							break;
1412
+						case 'Ticket':
1413
+							$ticket = $item->ticket();
1414
+							// right now we're only handling tickets here.
1415
+							// Cause its expected that only tickets will have attendees right?
1416
+							if (! $ticket instanceof EE_Ticket) {
1417
+								break;
1418
+							}
1419
+							try {
1420
+								$event_name = $ticket->get_event_name();
1421
+							} catch (Exception $e) {
1422
+								EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1423
+								$event_name = esc_html__('Unknown Event', 'event_espresso');
1424
+							}
1425
+							$event_name   .= ' - ' . $item->name();
1426
+							$ticket_price = EEH_Template::format_currency($item->unit_price());
1427
+							// now get all of the registrations for this transaction that use this ticket
1428
+							$registrations = $ticket->registrations(
1429
+								[['TXN_ID' => $this->_transaction->ID()]]
1430
+							);
1431
+							foreach ($registrations as $registration) {
1432
+								if (! $registration instanceof EE_Registration) {
1433
+									break;
1434
+								}
1435
+								$this->_template_args['event_attendees'][ $registration->ID() ]['STS_ID']
1436
+									= $registration->status_ID();
1437
+								$this->_template_args['event_attendees'][ $registration->ID() ]['att_num']
1438
+									= $registration->count();
1439
+								$this->_template_args['event_attendees'][ $registration->ID() ]['event_ticket_name']
1440
+									= $event_name;
1441
+								$this->_template_args['event_attendees'][ $registration->ID() ]['ticket_price']
1442
+									= $ticket_price;
1443
+								// attendee info
1444
+								$attendee = $registration->get_first_related('Attendee');
1445
+								if ($attendee instanceof EE_Attendee) {
1446
+									$this->_template_args['event_attendees'][ $registration->ID() ]['att_id']
1447
+										= $attendee->ID();
1448
+									$this->_template_args['event_attendees'][ $registration->ID() ]['attendee']
1449
+										= $attendee->full_name();
1450
+									$this->_template_args['event_attendees'][ $registration->ID() ]['email']
1451
+										= '<a href="mailto:' . $attendee->email() . '?subject=' . $event_name
1452
+										  . esc_html__(
1453
+											  ' Event',
1454
+											  'event_espresso'
1455
+										  )
1456
+										  . '">' . $attendee->email() . '</a>';
1457
+									$this->_template_args['event_attendees'][ $registration->ID() ]['address']
1458
+										= EEH_Address::format($attendee, 'inline', false, false);
1459
+								} else {
1460
+									$this->_template_args['event_attendees'][ $registration->ID() ]['att_id']   = '';
1461
+									$this->_template_args['event_attendees'][ $registration->ID() ]['attendee'] = '';
1462
+									$this->_template_args['event_attendees'][ $registration->ID() ]['email']    = '';
1463
+									$this->_template_args['event_attendees'][ $registration->ID() ]['address']  = '';
1464
+								}
1465
+							}
1466
+							break;
1467
+					}
1468
+				}
1469
+			}
1470
+
1471
+			$this->_template_args['transaction_form_url'] = add_query_arg(
1472
+				[
1473
+					'action'  => 'edit_transaction',
1474
+					'process' => 'attendees',
1475
+				],
1476
+				TXN_ADMIN_URL
1477
+			);
1478
+			echo EEH_Template::display_template(
1479
+				TXN_TEMPLATE_PATH . 'txn_admin_details_main_meta_box_attendees.template.php',
1480
+				$this->_template_args,
1481
+				true
1482
+			);
1483
+		} else {
1484
+			printf(
1485
+				esc_html__(
1486
+					'%1$sFor some reason, there are no attendees registered for this transaction. Likely the registration was abandoned in process.%2$s',
1487
+					'event_espresso'
1488
+				),
1489
+				'<p class="important-notice">',
1490
+				'</p>'
1491
+			);
1492
+		}
1493
+	}
1494
+
1495
+
1496
+	/**
1497
+	 * txn_registrant_side_meta_box
1498
+	 * generates HTML for the Edit Transaction side meta box
1499
+	 *
1500
+	 * @access public
1501
+	 * @return void
1502
+	 * @throws DomainException
1503
+	 * @throws EE_Error
1504
+	 * @throws InvalidArgumentException
1505
+	 * @throws InvalidDataTypeException
1506
+	 * @throws InvalidInterfaceException
1507
+	 * @throws ReflectionException
1508
+	 */
1509
+	public function txn_registrant_side_meta_box()
1510
+	{
1511
+		$primary_att = $this->_transaction->primary_registration() instanceof EE_Registration
1512
+			? $this->_transaction->primary_registration()->get_first_related('Attendee')
1513
+			: null;
1514
+		if (! $primary_att instanceof EE_Attendee) {
1515
+			$this->_template_args['no_attendee_message'] = esc_html__(
1516
+				'There is no attached contact for this transaction.  The transaction either failed due to an error or was abandoned.',
1517
+				'event_espresso'
1518
+			);
1519
+			$primary_att                           = EEM_Attendee::instance()->create_default_object();
1520
+		}
1521
+		$this->_template_args['ATT_ID']            = $primary_att->ID();
1522
+		$this->_template_args['prime_reg_fname']   = $primary_att->fname();
1523
+		$this->_template_args['prime_reg_lname']   = $primary_att->lname();
1524
+		$this->_template_args['prime_reg_email']   = $primary_att->email();
1525
+		$this->_template_args['prime_reg_phone']   = $primary_att->phone();
1526
+		$this->_template_args['edit_attendee_url'] = EE_Admin_Page::add_query_args_and_nonce(
1527
+			[
1528
+				'action' => 'edit_attendee',
1529
+				'post'   => $primary_att->ID(),
1530
+			],
1531
+			REG_ADMIN_URL
1532
+		);
1533
+		// get formatted address for registrant
1534
+		$formatted_address = EEH_Address::format($primary_att);
1535
+		$formatted_address = $formatted_address !== '<div class="espresso-address-dv"><div></div></div>'
1536
+			? $formatted_address
1537
+			: '';
1538
+		$this->_template_args['formatted_address'] = $formatted_address;
1539
+		echo EEH_Template::display_template(
1540
+			TXN_TEMPLATE_PATH . 'txn_admin_details_side_meta_box_registrant.template.php',
1541
+			$this->_template_args,
1542
+			true
1543
+		);
1544
+	}
1545
+
1546
+
1547
+	/**
1548
+	 * txn_billing_info_side_meta_box
1549
+	 *    generates HTML for the Edit Transaction side meta box
1550
+	 *
1551
+	 * @access public
1552
+	 * @return void
1553
+	 * @throws DomainException
1554
+	 * @throws EE_Error
1555
+	 * @throws ReflectionException
1556
+	 */
1557
+	public function txn_billing_info_side_meta_box()
1558
+	{
1559
+
1560
+		$this->_template_args['billing_form']     = $this->_transaction->billing_info();
1561
+		$this->_template_args['billing_form_url'] = add_query_arg(
1562
+			['action' => 'edit_transaction', 'process' => 'billing'],
1563
+			TXN_ADMIN_URL
1564
+		);
1565
+
1566
+		$template_path = TXN_TEMPLATE_PATH . 'txn_admin_details_side_meta_box_billing_info.template.php';
1567
+		echo EEH_Template::display_template($template_path, $this->_template_args, true);
1568
+	}
1569
+
1570
+
1571
+	/**
1572
+	 * apply_payments_or_refunds
1573
+	 *    registers a payment or refund made towards a transaction
1574
+	 *
1575
+	 * @access public
1576
+	 * @return void
1577
+	 * @throws EE_Error
1578
+	 * @throws InvalidArgumentException
1579
+	 * @throws ReflectionException
1580
+	 * @throws RuntimeException
1581
+	 * @throws InvalidDataTypeException
1582
+	 * @throws InvalidInterfaceException
1583
+	 */
1584
+	public function apply_payments_or_refunds()
1585
+	{
1586
+		$valid_data         = $this->_validate_payment_request_data();
1587
+		$has_access         = EE_Registry::instance()->CAP->current_user_can(
1588
+			'ee_edit_payments',
1589
+			'apply_payment_or_refund_from_registration_details'
1590
+		);
1591
+		$TXD_ID = $this->request->getRequestParam('txn_admin_payment[TXN_ID]', 0, 'int');
1592
+		$amount = 0;
1593
+		if (! empty($valid_data) && $has_access) {
1594
+			$PAY_ID = $valid_data['PAY_ID'];
1595
+			// save  the new payment
1596
+			$payment = $this->_create_payment_from_request_data($valid_data);
1597
+			$amount = $payment->amount();
1598
+			// get the TXN for this payment
1599
+			$transaction = $payment->transaction();
1600
+			// verify transaction
1601
+			if ($transaction instanceof EE_Transaction) {
1602
+				// calculate_total_payments_and_update_status
1603
+				$this->_process_transaction_payments($transaction);
1604
+				$REG_IDs = $this->_get_REG_IDs_to_apply_payment_to($payment);
1605
+				$this->_remove_existing_registration_payments($payment, $PAY_ID);
1606
+				// apply payment to registrations (if applicable)
1607
+				if (! empty($REG_IDs)) {
1608
+					$this->_update_registration_payments($transaction, $payment, $REG_IDs);
1609
+					$this->_maybe_send_notifications();
1610
+					// now process status changes for the same registrations
1611
+					$this->_process_registration_status_change($transaction, $REG_IDs);
1612
+				}
1613
+				$this->_maybe_send_notifications($payment);
1614
+				// prepare to render page
1615
+				do_action(
1616
+					'AHEE__Transactions_Admin_Page__apply_payments_or_refund__after_recording',
1617
+					$transaction,
1618
+					$payment
1619
+				);
1620
+			} else {
1621
+				EE_Error::add_error(
1622
+					esc_html__(
1623
+						'A valid Transaction for this payment could not be retrieved.',
1624
+						'event_espresso'
1625
+					),
1626
+					__FILE__,
1627
+					__FUNCTION__,
1628
+					__LINE__
1629
+				);
1630
+			}
1631
+		} elseif ($has_access) {
1632
+			EE_Error::add_error(
1633
+				esc_html__(
1634
+					'The payment form data could not be processed. Please try again.',
1635
+					'event_espresso'
1636
+				),
1637
+				__FILE__,
1638
+				__FUNCTION__,
1639
+				__LINE__
1640
+			);
1641
+		} else {
1642
+			EE_Error::add_error(
1643
+				esc_html__(
1644
+					'You do not have access to apply payments or refunds to a registration.',
1645
+					'event_espresso'
1646
+				),
1647
+				__FILE__,
1648
+				__FUNCTION__,
1649
+				__LINE__
1650
+			);
1651
+		}
1652
+		$query_args = [
1653
+			'page' => 'espresso_transactions',
1654
+			 'action' => 'view_transaction',
1655
+			 'TXN_ID' => $TXD_ID
1656
+		];
1657
+
1658
+		$this->_redirect_after_action(
1659
+			! EE_Error::has_error(),
1660
+			$amount > 0
1661
+				? esc_html__('payment', 'event_espresso')
1662
+				: esc_html__('refund', 'event_espresso'),
1663
+			esc_html__('processed', 'event_espresso'),
1664
+			$query_args
1665
+		);
1666
+	}
1667
+
1668
+
1669
+	/**
1670
+	 * _validate_payment_request_data
1671
+	 *
1672
+	 * @return array
1673
+	 * @throws EE_Error
1674
+	 * @throws InvalidArgumentException
1675
+	 * @throws InvalidDataTypeException
1676
+	 * @throws InvalidInterfaceException
1677
+	 */
1678
+	protected function _validate_payment_request_data()
1679
+	{
1680
+		if (! $this->request->requestParamIsSet('txn_admin_payment')) {
1681
+			return [];
1682
+		}
1683
+		$payment_form = $this->_generate_payment_form_section();
1684
+		try {
1685
+			if ($payment_form->was_submitted()) {
1686
+				$payment_form->receive_form_submission();
1687
+				if (! $payment_form->is_valid()) {
1688
+					$submission_error_messages = [];
1689
+					foreach ($payment_form->get_validation_errors_accumulated() as $validation_error) {
1690
+						if ($validation_error instanceof EE_Validation_Error) {
1691
+							$form_input = $validation_error->get_form_section();
1692
+							$submission_error_messages[] = sprintf(
1693
+								_x('%s : %s', 'Form Section Name : Form Validation Error', 'event_espresso'),
1694
+								$form_input instanceof EE_Form_Input_Base ? $form_input->html_label_text() : '',
1695
+								$validation_error->getMessage()
1696
+							);
1697
+						}
1698
+					}
1699
+					EE_Error::add_error(
1700
+						implode('<br />', $submission_error_messages),
1701
+						__FILE__,
1702
+						__FUNCTION__,
1703
+						__LINE__
1704
+					);
1705
+					return [];
1706
+				}
1707
+			}
1708
+		} catch (EE_Error $e) {
1709
+			EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1710
+			return [];
1711
+		}
1712
+
1713
+		return $payment_form->valid_data();
1714
+	}
1715
+
1716
+
1717
+	/**
1718
+	 * _generate_payment_form_section
1719
+	 *
1720
+	 * @return EE_Form_Section_Proper
1721
+	 * @throws EE_Error
1722
+	 */
1723
+	protected function _generate_payment_form_section()
1724
+	{
1725
+		return new EE_Form_Section_Proper(
1726
+			[
1727
+				'name'        => 'txn_admin_payment',
1728
+				'subsections' => [
1729
+					'PAY_ID'          => new EE_Text_Input(
1730
+						[
1731
+							'default'               => 0,
1732
+							'required'              => false,
1733
+							'html_label_text'       => esc_html__('Payment ID', 'event_espresso'),
1734
+							'validation_strategies' => [new EE_Int_Normalization()],
1735
+						]
1736
+					),
1737
+					'TXN_ID'          => new EE_Text_Input(
1738
+						[
1739
+							'default'               => 0,
1740
+							'required'              => true,
1741
+							'html_label_text'       => esc_html__('Transaction ID', 'event_espresso'),
1742
+							'validation_strategies' => [new EE_Int_Normalization()],
1743
+						]
1744
+					),
1745
+					'type'            => new EE_Text_Input(
1746
+						[
1747
+							'default'               => 1,
1748
+							'required'              => true,
1749
+							'html_label_text'       => esc_html__('Payment or Refund', 'event_espresso'),
1750
+							'validation_strategies' => [new EE_Int_Normalization()],
1751
+						]
1752
+					),
1753
+					'amount'          => new EE_Text_Input(
1754
+						[
1755
+							'default'               => 0,
1756
+							'required'              => true,
1757
+							'html_label_text'       => esc_html__('Payment amount', 'event_espresso'),
1758
+							'validation_strategies' => [new EE_Float_Normalization()],
1759
+						]
1760
+					),
1761
+					'status'          => new EE_Text_Input(
1762
+						[
1763
+							'default'         => EEM_Payment::status_id_approved,
1764
+							'required'        => true,
1765
+							'html_label_text' => esc_html__('Payment status', 'event_espresso'),
1766
+						]
1767
+					),
1768
+					'PMD_ID'          => new EE_Text_Input(
1769
+						[
1770
+							'default'               => 2,
1771
+							'required'              => true,
1772
+							'html_label_text'       => esc_html__('Payment Method', 'event_espresso'),
1773
+							'validation_strategies' => [new EE_Int_Normalization()],
1774
+						]
1775
+					),
1776
+					'date'            => new EE_Text_Input(
1777
+						[
1778
+							'default'         => time(),
1779
+							'required'        => true,
1780
+							'html_label_text' => esc_html__('Payment date', 'event_espresso'),
1781
+						]
1782
+					),
1783
+					'txn_id_chq_nmbr' => new EE_Text_Input(
1784
+						[
1785
+							'default'               => '',
1786
+							'required'              => false,
1787
+							'html_label_text'       => esc_html__('Transaction or Cheque Number', 'event_espresso'),
1788
+							'validation_strategies' => [
1789
+								new EE_Max_Length_Validation_Strategy(
1790
+									esc_html__('Input too long', 'event_espresso'),
1791
+									100
1792
+								),
1793
+							],
1794
+						]
1795
+					),
1796
+					'po_number'       => new EE_Text_Input(
1797
+						[
1798
+							'default'               => '',
1799
+							'required'              => false,
1800
+							'html_label_text'       => esc_html__('Purchase Order Number', 'event_espresso'),
1801
+							'validation_strategies' => [
1802
+								new EE_Max_Length_Validation_Strategy(
1803
+									esc_html__('Input too long', 'event_espresso'),
1804
+									100
1805
+								),
1806
+							],
1807
+						]
1808
+					),
1809
+					'accounting'      => new EE_Text_Input(
1810
+						[
1811
+							'default'               => '',
1812
+							'required'              => false,
1813
+							'html_label_text'       => esc_html__('Extra Field for Accounting', 'event_espresso'),
1814
+							'validation_strategies' => [
1815
+								new EE_Max_Length_Validation_Strategy(
1816
+									esc_html__('Input too long', 'event_espresso'),
1817
+									100
1818
+								),
1819
+							],
1820
+						]
1821
+					),
1822
+				],
1823
+			]
1824
+		);
1825
+	}
1826
+
1827
+
1828
+	/**
1829
+	 * _create_payment_from_request_data
1830
+	 *
1831
+	 * @param array $valid_data
1832
+	 * @return EE_Payment
1833
+	 * @throws EE_Error
1834
+	 * @throws InvalidArgumentException
1835
+	 * @throws InvalidDataTypeException
1836
+	 * @throws InvalidInterfaceException
1837
+	 * @throws ReflectionException
1838
+	 */
1839
+	protected function _create_payment_from_request_data($valid_data)
1840
+	{
1841
+		$PAY_ID = $valid_data['PAY_ID'];
1842
+		// get payment amount
1843
+		$amount = $valid_data['amount'] ? abs($valid_data['amount']) : 0;
1844
+		// payments have a type value of 1 and refunds have a type value of -1
1845
+		// so multiplying amount by type will give a positive value for payments, and negative values for refunds
1846
+		$amount = $valid_data['type'] < 0 ? $amount * -1 : $amount;
1847
+		// for some reason the date string coming in has extra spaces between the date and time.  This fixes that.
1848
+		$date    = $valid_data['date']
1849
+			? preg_replace('/\s+/', ' ', $valid_data['date'])
1850
+			: date('Y-m-d g:i a', current_time('timestamp'));
1851
+		$payment = EE_Payment::new_instance(
1852
+			[
1853
+				'TXN_ID'              => $valid_data['TXN_ID'],
1854
+				'STS_ID'              => $valid_data['status'],
1855
+				'PAY_timestamp'       => $date,
1856
+				'PAY_source'          => EEM_Payment_Method::scope_admin,
1857
+				'PMD_ID'              => $valid_data['PMD_ID'],
1858
+				'PAY_amount'          => $amount,
1859
+				'PAY_txn_id_chq_nmbr' => $valid_data['txn_id_chq_nmbr'],
1860
+				'PAY_po_number'       => $valid_data['po_number'],
1861
+				'PAY_extra_accntng'   => $valid_data['accounting'],
1862
+				'PAY_details'         => $valid_data,
1863
+				'PAY_ID'              => $PAY_ID,
1864
+			],
1865
+			'',
1866
+			['Y-m-d', 'g:i a']
1867
+		);
1868
+
1869
+		if (! $payment->save()) {
1870
+			EE_Error::add_error(
1871
+				sprintf(
1872
+					esc_html__('Payment %1$d has not been successfully saved to the database.', 'event_espresso'),
1873
+					$payment->ID()
1874
+				),
1875
+				__FILE__,
1876
+				__FUNCTION__,
1877
+				__LINE__
1878
+			);
1879
+		}
1880
+
1881
+		return $payment;
1882
+	}
1883
+
1884
+
1885
+	/**
1886
+	 * _process_transaction_payments
1887
+	 *
1888
+	 * @param EE_Transaction $transaction
1889
+	 * @return void
1890
+	 * @throws EE_Error
1891
+	 * @throws InvalidArgumentException
1892
+	 * @throws ReflectionException
1893
+	 * @throws InvalidDataTypeException
1894
+	 * @throws InvalidInterfaceException
1895
+	 */
1896
+	protected function _process_transaction_payments(EE_Transaction $transaction)
1897
+	{
1898
+		/** @type EE_Transaction_Payments $transaction_payments */
1899
+		$transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
1900
+		// update the transaction with this payment
1901
+		if ($transaction_payments->calculate_total_payments_and_update_status($transaction)) {
1902
+			EE_Error::add_success(
1903
+				esc_html__(
1904
+					'The payment has been processed successfully.',
1905
+					'event_espresso'
1906
+				),
1907
+				__FILE__,
1908
+				__FUNCTION__,
1909
+				__LINE__
1910
+			);
1911
+		} else {
1912
+			EE_Error::add_error(
1913
+				esc_html__(
1914
+					'The payment was processed successfully but the amount paid for the transaction was not updated.',
1915
+					'event_espresso'
1916
+				),
1917
+				__FILE__,
1918
+				__FUNCTION__,
1919
+				__LINE__
1920
+			);
1921
+		}
1922
+	}
1923
+
1924
+
1925
+	/**
1926
+	 * _get_REG_IDs_to_apply_payment_to
1927
+	 * returns a list of registration IDs that the payment will apply to
1928
+	 *
1929
+	 * @param EE_Payment $payment
1930
+	 * @return array
1931
+	 * @throws EE_Error
1932
+	 * @throws InvalidArgumentException
1933
+	 * @throws InvalidDataTypeException
1934
+	 * @throws InvalidInterfaceException
1935
+	 * @throws ReflectionException
1936
+	 */
1937
+	protected function _get_REG_IDs_to_apply_payment_to(EE_Payment $payment)
1938
+	{
1939
+		// grab array of IDs for specific registrations to apply changes to
1940
+		$apply_to_all = $this->request->getRequestParam(
1941
+			'txn_admin_payment[apply_to_all_registrations]',
1942
+			false,
1943
+			DataType::BOOL
1944
+		);
1945
+		$REG_IDs = ! $apply_to_all
1946
+			? $this->request->getRequestParam(
1947
+				'txn_admin_payment[registrations]',
1948
+				[],
1949
+				DataType::INT,
1950
+				true
1951
+			)
1952
+			: [];
1953
+		// nothing specified ? then get all reg IDs
1954
+		if ($apply_to_all || empty($REG_IDs)) {
1955
+			$registrations = $payment->transaction()->registrations();
1956
+			$REG_IDs       = ! empty($registrations)
1957
+				? array_keys($registrations)
1958
+				: $this->_get_existing_reg_payment_REG_IDs($payment);
1959
+		}
1960
+		// ensure that REG_IDs are integers and NOT strings
1961
+		return array_map('absint', $REG_IDs);
1962
+	}
1963
+
1964
+
1965
+	/**
1966
+	 * @return array
1967
+	 */
1968
+	public function existing_reg_payment_REG_IDs()
1969
+	{
1970
+		return $this->_existing_reg_payment_REG_IDs;
1971
+	}
1972
+
1973
+
1974
+	/**
1975
+	 * @param array $existing_reg_payment_REG_IDs
1976
+	 */
1977
+	public function set_existing_reg_payment_REG_IDs($existing_reg_payment_REG_IDs = null)
1978
+	{
1979
+		$this->_existing_reg_payment_REG_IDs = $existing_reg_payment_REG_IDs;
1980
+	}
1981
+
1982
+
1983
+	/**
1984
+	 * _get_existing_reg_payment_REG_IDs
1985
+	 * returns a list of registration IDs that the payment is currently related to
1986
+	 * as recorded in the database
1987
+	 *
1988
+	 * @param EE_Payment $payment
1989
+	 * @return array
1990
+	 * @throws EE_Error
1991
+	 * @throws InvalidArgumentException
1992
+	 * @throws InvalidDataTypeException
1993
+	 * @throws InvalidInterfaceException
1994
+	 * @throws ReflectionException
1995
+	 */
1996
+	protected function _get_existing_reg_payment_REG_IDs(EE_Payment $payment)
1997
+	{
1998
+		if ($this->existing_reg_payment_REG_IDs() === null) {
1999
+			// let's get any existing reg payment records for this payment
2000
+			$existing_reg_payment_REG_IDs = $payment->get_many_related('Registration');
2001
+			// but we only want the REG IDs, so grab the array keys
2002
+			$existing_reg_payment_REG_IDs = ! empty($existing_reg_payment_REG_IDs)
2003
+				? array_keys($existing_reg_payment_REG_IDs)
2004
+				: [];
2005
+			$this->set_existing_reg_payment_REG_IDs($existing_reg_payment_REG_IDs);
2006
+		}
2007
+
2008
+		return $this->existing_reg_payment_REG_IDs();
2009
+	}
2010
+
2011
+
2012
+	/**
2013
+	 * _remove_existing_registration_payments
2014
+	 * this calculates the difference between existing relations
2015
+	 * to the supplied payment and the new list registration IDs,
2016
+	 * removes any related registrations that no longer apply,
2017
+	 * and then updates the registration paid fields
2018
+	 *
2019
+	 * @param EE_Payment $payment
2020
+	 * @param int        $PAY_ID
2021
+	 * @return bool;
2022
+	 * @throws EE_Error
2023
+	 * @throws InvalidArgumentException
2024
+	 * @throws ReflectionException
2025
+	 * @throws InvalidDataTypeException
2026
+	 * @throws InvalidInterfaceException
2027
+	 */
2028
+	protected function _remove_existing_registration_payments(EE_Payment $payment, $PAY_ID = 0)
2029
+	{
2030
+		// newly created payments will have nothing recorded for $PAY_ID
2031
+		if (absint($PAY_ID) === 0) {
2032
+			return false;
2033
+		}
2034
+		$existing_reg_payment_REG_IDs = $this->_get_existing_reg_payment_REG_IDs($payment);
2035
+		if (empty($existing_reg_payment_REG_IDs)) {
2036
+			return false;
2037
+		}
2038
+		/** @type EE_Transaction_Payments $transaction_payments */
2039
+		$transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
2040
+
2041
+		return $transaction_payments->delete_registration_payments_and_update_registrations(
2042
+			$payment,
2043
+			[
2044
+				[
2045
+					'PAY_ID' => $payment->ID(),
2046
+					'REG_ID' => ['IN', $existing_reg_payment_REG_IDs],
2047
+				],
2048
+			]
2049
+		);
2050
+	}
2051
+
2052
+
2053
+	/**
2054
+	 * _update_registration_payments
2055
+	 * this applies the payments to the selected registrations
2056
+	 * but only if they have not already been paid for
2057
+	 *
2058
+	 * @param EE_Transaction $transaction
2059
+	 * @param EE_Payment     $payment
2060
+	 * @param array          $REG_IDs
2061
+	 * @return void
2062
+	 * @throws EE_Error
2063
+	 * @throws InvalidArgumentException
2064
+	 * @throws ReflectionException
2065
+	 * @throws RuntimeException
2066
+	 * @throws InvalidDataTypeException
2067
+	 * @throws InvalidInterfaceException
2068
+	 */
2069
+	protected function _update_registration_payments(
2070
+		EE_Transaction $transaction,
2071
+		EE_Payment $payment,
2072
+		$REG_IDs = []
2073
+	) {
2074
+		// we can pass our own custom set of registrations to EE_Payment_Processor::process_registration_payments()
2075
+		// so let's do that using our set of REG_IDs from the form
2076
+		$registration_query_where_params = [
2077
+			'REG_ID' => ['IN', $REG_IDs],
2078
+		];
2079
+		// but add in some conditions regarding payment,
2080
+		// so that we don't apply payments to registrations that are free or have already been paid for
2081
+		// but ONLY if the payment is NOT a refund ( ie: the payment amount is not negative )
2082
+		if (! $payment->is_a_refund()) {
2083
+			$registration_query_where_params['REG_final_price']  = ['!=', 0];
2084
+			$registration_query_where_params['REG_final_price*'] = ['!=', 'REG_paid', true];
2085
+		}
2086
+		$registrations = $transaction->registrations([$registration_query_where_params]);
2087
+		if (! empty($registrations)) {
2088
+			/** @type EE_Payment_Processor $payment_processor */
2089
+			$payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
2090
+			$payment_processor->process_registration_payments($transaction, $payment, $registrations);
2091
+		}
2092
+	}
2093
+
2094
+
2095
+	/**
2096
+	 * _process_registration_status_change
2097
+	 * This processes requested registration status changes for all the registrations
2098
+	 * on a given transaction and (optionally) sends out notifications for the changes.
2099
+	 *
2100
+	 * @param EE_Transaction $transaction
2101
+	 * @param array          $REG_IDs
2102
+	 * @return bool
2103
+	 * @throws EE_Error
2104
+	 * @throws InvalidArgumentException
2105
+	 * @throws ReflectionException
2106
+	 * @throws InvalidDataTypeException
2107
+	 * @throws InvalidInterfaceException
2108
+	 */
2109
+	protected function _process_registration_status_change(EE_Transaction $transaction, $REG_IDs = [], $reg_status = '')
2110
+	{
2111
+		// first if there is no change in status then we get out.
2112
+		$reg_status = $reg_status ?: $this->request->getRequestParam('txn_reg_status_change[reg_status]', 'NAN');
2113
+		if ($reg_status === 'NAN') {
2114
+			// no error message, no change requested, just nothing to do man.
2115
+			return false;
2116
+		}
2117
+		/** @type EE_Transaction_Processor $transaction_processor */
2118
+		$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
2119
+
2120
+		// made it here dude?  Oh WOW.  K, let's take care of changing the statuses
2121
+		return $transaction_processor->manually_update_registration_statuses(
2122
+			$transaction,
2123
+			$reg_status,
2124
+			[['REG_ID' => ['IN', $REG_IDs]]]
2125
+		);
2126
+	}
2127
+
2128
+
2129
+	/**
2130
+	 * _build_payment_json_response
2131
+	 *
2132
+	 * @access public
2133
+	 * @param EE_Payment  $payment
2134
+	 * @param array       $REG_IDs
2135
+	 * @param bool | null $delete_txn_reg_status_change
2136
+	 * @return array
2137
+	 * @throws EE_Error
2138
+	 * @throws InvalidArgumentException
2139
+	 * @throws InvalidDataTypeException
2140
+	 * @throws InvalidInterfaceException
2141
+	 * @throws ReflectionException
2142
+	 */
2143
+	protected function _build_payment_json_response(
2144
+		EE_Payment $payment,
2145
+		$REG_IDs = [],
2146
+		$delete_txn_reg_status_change = null
2147
+	) {
2148
+		// was the payment deleted ?
2149
+		if (is_bool($delete_txn_reg_status_change)) {
2150
+			return [
2151
+				'PAY_ID'                       => $payment->ID(),
2152
+				'amount'                       => $payment->amount(),
2153
+				'total_paid'                   => $payment->transaction()->paid(),
2154
+				'txn_status'                   => $payment->transaction()->status_ID(),
2155
+				'pay_status'                   => $payment->STS_ID(),
2156
+				'registrations'                => $this->_registration_payment_data_array($REG_IDs),
2157
+				'delete_txn_reg_status_change' => $delete_txn_reg_status_change,
2158
+			];
2159
+		}
2160
+
2161
+		$this->_get_payment_status_array();
2162
+		return [
2163
+			'amount'           => $payment->amount(),
2164
+			'total_paid'       => $payment->transaction()->paid(),
2165
+			'txn_status'       => $payment->transaction()->status_ID(),
2166
+			'pay_status'       => $payment->STS_ID(),
2167
+			'PAY_ID'           => $payment->ID(),
2168
+			'STS_ID'           => $payment->STS_ID(),
2169
+			'status'           => self::$_pay_status[ $payment->STS_ID() ],
2170
+			'date'             => $payment->timestamp('Y-m-d', 'h:i a'),
2171
+			'method'           => strtoupper($payment->source()),
2172
+			'PM_ID'            => $payment->payment_method() ? $payment->payment_method()->ID() : 1,
2173
+			'gateway'          => $payment->payment_method()
2174
+				? $payment->payment_method()->admin_name()
2175
+				: esc_html__('Unknown', 'event_espresso'),
2176
+			'gateway_response' => $payment->gateway_response(),
2177
+			'txn_id_chq_nmbr'  => $payment->txn_id_chq_nmbr(),
2178
+			'po_number'        => $payment->po_number(),
2179
+			'extra_accntng'    => $payment->extra_accntng(),
2180
+			'registrations'    => $this->_registration_payment_data_array($REG_IDs),
2181
+		];
2182
+	}
2183
+
2184
+
2185
+	/**
2186
+	 * delete_payment
2187
+	 *    delete a payment or refund made towards a transaction
2188
+	 *
2189
+	 * @access public
2190
+	 * @return void
2191
+	 * @throws EE_Error
2192
+	 * @throws InvalidArgumentException
2193
+	 * @throws ReflectionException
2194
+	 * @throws InvalidDataTypeException
2195
+	 * @throws InvalidInterfaceException
2196
+	 */
2197
+	public function delete_payment()
2198
+	{
2199
+		$TXD_ID = $this->request->getRequestParam('delete_txn_admin_payment[TXN_ID]', 0, 'int');
2200
+		// $json_response_data = ['return_data' => false];
2201
+		$PAY_ID = $this->request->getRequestParam('delete_txn_admin_payment[PAY_ID]', 0, 'int');
2202
+		$amount = 0;
2203
+		$can_delete         = EE_Registry::instance()->CAP->current_user_can(
2204
+			'ee_delete_payments',
2205
+			'delete_payment_from_registration_details'
2206
+		);
2207
+		if ($PAY_ID && $can_delete) {
2208
+			$delete_txn_reg_status_change = $this->request->getRequestParam('delete_txn_reg_status_change[reg_status]');
2209
+			$payment = EEM_Payment::instance()->get_one_by_ID($PAY_ID);
2210
+			if ($payment instanceof EE_Payment) {
2211
+				$amount = $payment->amount();
2212
+				$REG_IDs = $this->_get_existing_reg_payment_REG_IDs($payment);
2213
+				/** @type EE_Transaction_Payments $transaction_payments */
2214
+				$transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
2215
+				if ($transaction_payments->delete_payment_and_update_transaction($payment)) {
2216
+					if ($delete_txn_reg_status_change) {
2217
+						$this->_maybe_send_notifications();
2218
+						$this->_process_registration_status_change(
2219
+							$payment->transaction(),
2220
+							$REG_IDs,
2221
+							$delete_txn_reg_status_change
2222
+						);
2223
+					}
2224
+				}
2225
+			} else {
2226
+				EE_Error::add_error(
2227
+					esc_html__('Valid Payment data could not be retrieved from the database.', 'event_espresso'),
2228
+					__FILE__,
2229
+					__FUNCTION__,
2230
+					__LINE__
2231
+				);
2232
+			}
2233
+		} elseif ($can_delete) {
2234
+			EE_Error::add_error(
2235
+				esc_html__(
2236
+					'A valid Payment ID was not received, therefore payment form data could not be loaded.',
2237
+					'event_espresso'
2238
+				),
2239
+				__FILE__,
2240
+				__FUNCTION__,
2241
+				__LINE__
2242
+			);
2243
+		} else {
2244
+			EE_Error::add_error(
2245
+				esc_html__(
2246
+					'You do not have access to delete a payment.',
2247
+					'event_espresso'
2248
+				),
2249
+				__FILE__,
2250
+				__FUNCTION__,
2251
+				__LINE__
2252
+			);
2253
+		}
2254
+		$query_args = [
2255
+			'page'   => 'espresso_transactions',
2256
+			'action' => 'view_transaction',
2257
+			'TXN_ID' => $TXD_ID
2258
+		];
2259
+		$this->_redirect_after_action(
2260
+			! EE_Error::has_error(),
2261
+			$amount > 0
2262
+				? esc_html__('payment', 'event_espresso')
2263
+				: esc_html__('refund', 'event_espresso'),
2264
+			esc_html__('deleted', 'event_espresso'),
2265
+			$query_args
2266
+		);
2267
+	}
2268
+
2269
+
2270
+	/**
2271
+	 * _registration_payment_data_array
2272
+	 * adds info for 'owing' and 'paid' for each registration to the json response
2273
+	 *
2274
+	 * @access protected
2275
+	 * @param array $REG_IDs
2276
+	 * @return array
2277
+	 * @throws EE_Error
2278
+	 * @throws InvalidArgumentException
2279
+	 * @throws InvalidDataTypeException
2280
+	 * @throws InvalidInterfaceException
2281
+	 * @throws ReflectionException
2282
+	 */
2283
+	protected function _registration_payment_data_array($REG_IDs)
2284
+	{
2285
+		$registration_payment_data = [];
2286
+		// if non empty reg_ids lets get an array of registrations and update the values for the apply_payment/refund rows.
2287
+		if (! empty($REG_IDs)) {
2288
+			$registrations = EEM_Registration::instance()->get_all([['REG_ID' => ['IN', $REG_IDs]]]);
2289
+			foreach ($registrations as $registration) {
2290
+				if ($registration instanceof EE_Registration) {
2291
+					$registration_payment_data[ $registration->ID() ] = [
2292
+						'paid'  => $registration->pretty_paid(),
2293
+						'owing' => EEH_Template::format_currency($registration->final_price() - $registration->paid()),
2294
+					];
2295
+				}
2296
+			}
2297
+		}
2298
+
2299
+		return $registration_payment_data;
2300
+	}
2301
+
2302
+
2303
+	/**
2304
+	 * _maybe_send_notifications
2305
+	 * determines whether or not the admin has indicated that notifications should be sent.
2306
+	 * If so, will toggle a filter switch for delivering registration notices.
2307
+	 * If passed an EE_Payment object, then it will trigger payment notifications instead.
2308
+	 *
2309
+	 * @access protected
2310
+	 * @param EE_Payment | null $payment
2311
+	 */
2312
+	protected function _maybe_send_notifications($payment = null)
2313
+	{
2314
+		switch ($payment instanceof EE_Payment) {
2315
+			// payment notifications
2316
+			case true:
2317
+				if ($this->request->getRequestParam('txn_payments[send_notifications]', false, 'bool')) {
2318
+					$this->_process_payment_notification($payment);
2319
+				}
2320
+				break;
2321
+			// registration notifications
2322
+			case false:
2323
+				if ($this->request->getRequestParam('txn_reg_status_change[send_notifications]', false, 'bool')) {
2324
+					add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true');
2325
+				}
2326
+				break;
2327
+		}
2328
+	}
2329
+
2330
+
2331
+	/**
2332
+	 * _send_payment_reminder
2333
+	 *    generates HTML for the View Transaction Details Admin page
2334
+	 *
2335
+	 * @access protected
2336
+	 * @return void
2337
+	 * @throws EE_Error
2338
+	 * @throws InvalidArgumentException
2339
+	 * @throws InvalidDataTypeException
2340
+	 * @throws InvalidInterfaceException
2341
+	 */
2342
+	protected function _send_payment_reminder()
2343
+	{
2344
+		$TXN_ID = $this->request->getRequestParam('TXN_ID', 0, 'int');
2345
+		$transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
2346
+		$redirect_to = $this->request->getRequestParam('redirect_to');
2347
+		$query_args  = $redirect_to ? ['action' => $redirect_to, 'TXN_ID' => $TXN_ID,] : [];
2348
+		do_action(
2349
+			'AHEE__Transactions_Admin_Page___send_payment_reminder__process_admin_payment_reminder',
2350
+			$transaction
2351
+		);
2352
+		$this->_redirect_after_action(
2353
+			false,
2354
+			esc_html__('payment reminder', 'event_espresso'),
2355
+			esc_html__('sent', 'event_espresso'),
2356
+			$query_args,
2357
+			true
2358
+		);
2359
+	}
2360
+
2361
+
2362
+	/**
2363
+	 *  get_transactions
2364
+	 *    get transactions for given parameters (used by list table)
2365
+	 *
2366
+	 * @param int     $per_page how many transactions displayed per page
2367
+	 * @param boolean $count   return the count or objects
2368
+	 * @param string  $view
2369
+	 * @return EE_Transaction[]|int int = count || array of transaction objects
2370
+	 * @throws EE_Error
2371
+	 * @throws InvalidArgumentException
2372
+	 * @throws InvalidDataTypeException
2373
+	 * @throws InvalidInterfaceException
2374
+	 */
2375
+	public function get_transactions($per_page, $count = false, $view = '')
2376
+	{
2377
+		$start_date = wp_strip_all_tags(
2378
+			$this->request->getRequestParam('txn-filter-start-date', date('m/d/Y', strtotime('-10 year')))
2379
+		);
2380
+		$end_date = wp_strip_all_tags(
2381
+			$this->request->getRequestParam('txn-filter-end-date', date('m/d/Y'))
2382
+		);
2383
+
2384
+		// make sure our timestamps start and end right at the boundaries for each day
2385
+		$start_date = date('Y-m-d', strtotime($start_date)) . ' 00:00:00';
2386
+		$end_date   = date('Y-m-d', strtotime($end_date)) . ' 23:59:59';
2387
+
2388
+
2389
+		// convert to timestamps
2390
+		$start_date = strtotime($start_date);
2391
+		$end_date   = strtotime($end_date);
2392
+
2393
+		// makes sure start date is the lowest value and vice versa
2394
+		$start_date = min($start_date, $end_date);
2395
+		$end_date   = max($start_date, $end_date);
2396
+
2397
+		// convert to correct format for query
2398
+		$start_date = EEM_Transaction::instance()->convert_datetime_for_query(
2399
+			'TXN_timestamp',
2400
+			date('Y-m-d H:i:s', $start_date),
2401
+			'Y-m-d H:i:s'
2402
+		);
2403
+		$end_date   = EEM_Transaction::instance()->convert_datetime_for_query(
2404
+			'TXN_timestamp',
2405
+			date('Y-m-d H:i:s', $end_date),
2406
+			'Y-m-d H:i:s'
2407
+		);
2408
+
2409
+
2410
+		// set orderby
2411
+		$orderby = $this->request->getRequestParam('orderby');
2412
+
2413
+		switch ($orderby) {
2414
+			case 'TXN_ID':
2415
+				break;
2416
+			case 'ATT_fname':
2417
+				$orderby = 'Registration.Attendee.ATT_fname';
2418
+				break;
2419
+			case 'event_name':
2420
+				$orderby = 'Registration.Event.EVT_name';
2421
+				break;
2422
+			default: // 'TXN_timestamp'
2423
+				$orderby = 'TXN_timestamp';
2424
+		}
2425
+
2426
+		$sort         = $this->request->getRequestParam('order', 'DESC');
2427
+		$current_page = $this->request->getRequestParam('paged', 1, 'int');
2428
+
2429
+		$per_page = absint($per_page) ? $per_page : 10;
2430
+		$per_page = $this->request->getRequestParam('perpage', $per_page, 'int');
2431
+
2432
+		$offset = ($current_page - 1) * $per_page;
2433
+		$limit  = [$offset, $per_page];
2434
+
2435
+		$_where = [
2436
+			'TXN_timestamp'          => ['BETWEEN', [$start_date, $end_date]],
2437
+			'Registration.REG_count' => 1,
2438
+		];
2439
+
2440
+		$EVT_ID = $this->request->getRequestParam('EVT_ID', 0, 'int');
2441
+		if ($EVT_ID) {
2442
+			$_where['Registration.EVT_ID'] = $EVT_ID;
2443
+		}
2444
+
2445
+		$search_term = $this->request->getRequestParam('s');
2446
+		if ($search_term) {
2447
+			$search_term = '%' . $search_term . '%';
2448
+			$_where['OR']  = [
2449
+				'Registration.Event.EVT_name'         => ['LIKE', $search_term],
2450
+				'Registration.Event.EVT_desc'         => ['LIKE', $search_term],
2451
+				'Registration.Event.EVT_short_desc'   => ['LIKE', $search_term],
2452
+				'Registration.Attendee.ATT_full_name' => ['LIKE', $search_term],
2453
+				'Registration.Attendee.ATT_fname'     => ['LIKE', $search_term],
2454
+				'Registration.Attendee.ATT_lname'     => ['LIKE', $search_term],
2455
+				'Registration.Attendee.ATT_short_bio' => ['LIKE', $search_term],
2456
+				'Registration.Attendee.ATT_email'     => ['LIKE', $search_term],
2457
+				'Registration.Attendee.ATT_address'   => ['LIKE', $search_term],
2458
+				'Registration.Attendee.ATT_address2'  => ['LIKE', $search_term],
2459
+				'Registration.Attendee.ATT_city'      => ['LIKE', $search_term],
2460
+				'Registration.REG_final_price'        => ['LIKE', $search_term],
2461
+				'Registration.REG_code'               => ['LIKE', $search_term],
2462
+				'Registration.REG_count'              => ['LIKE', $search_term],
2463
+				'Registration.REG_group_size'         => ['LIKE', $search_term],
2464
+				'Registration.Ticket.TKT_name'        => ['LIKE', $search_term],
2465
+				'Registration.Ticket.TKT_description' => ['LIKE', $search_term],
2466
+				'Payment.PAY_source'                  => ['LIKE', $search_term],
2467
+				'Payment.Payment_Method.PMD_name'     => ['LIKE', $search_term],
2468
+				'TXN_session_data'                    => ['LIKE', $search_term],
2469
+				'Payment.PAY_txn_id_chq_nmbr'         => ['LIKE', $search_term],
2470
+			];
2471
+		}
2472
+
2473
+		$status = $this->request->getRequestParam('status');
2474
+		// failed transactions
2475
+		$failed     = (! empty($status) && $status === 'failed' && ! $count) || ($count && $view === 'failed');
2476
+		$abandoned  = (! empty($status) && $status === 'abandoned' && ! $count) || ($count && $view === 'abandoned');
2477
+		$incomplete = (! empty($status) && $status === 'incomplete' && ! $count) || ($count && $view === 'incomplete');
2478
+
2479
+		if ($failed) {
2480
+			$_where['STS_ID'] = EEM_Transaction::failed_status_code;
2481
+		} elseif ($abandoned) {
2482
+			$_where['STS_ID'] = EEM_Transaction::abandoned_status_code;
2483
+		} elseif ($incomplete) {
2484
+			$_where['STS_ID'] = EEM_Transaction::incomplete_status_code;
2485
+		} else {
2486
+			$_where['STS_ID']  = ['!=', EEM_Transaction::failed_status_code];
2487
+			$_where['STS_ID*'] = ['!=', EEM_Transaction::abandoned_status_code];
2488
+		}
2489
+
2490
+		$query_params = apply_filters(
2491
+			'FHEE__Transactions_Admin_Page___get_transactions_query_params',
2492
+			[
2493
+				$_where,
2494
+				'order_by'                 => [$orderby => $sort],
2495
+				'limit'                    => $limit,
2496
+				'default_where_conditions' => EEM_Base::default_where_conditions_this_only,
2497
+			],
2498
+			$this->request->requestParams(),
2499
+			$view,
2500
+			$count
2501
+		);
2502
+
2503
+		return $count
2504
+			? EEM_Transaction::instance()->count([$query_params[0]], 'TXN_ID', true)
2505
+			: EEM_Transaction::instance()->get_all($query_params);
2506
+	}
2507
+
2508
+
2509
+	/**
2510
+	 * @throws EE_Error
2511
+	 * @throws InvalidArgumentException
2512
+	 * @throws InvalidDataTypeException
2513
+	 * @throws InvalidInterfaceException
2514
+	 * @throws ReflectionException
2515
+	 * @throws RuntimeException
2516
+	 * @since 4.9.79.p
2517
+	 */
2518
+	public function recalculateLineItems()
2519
+	{
2520
+		$TXN_ID = $this->request->getRequestParam('TXN_ID', 0, 'int');
2521
+		/** @var EE_Transaction $transaction */
2522
+		$transaction     = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
2523
+		$success         = $transaction->recalculateLineItems();
2524
+		$redirect_to = $this->request->getRequestParam('redirect_to');
2525
+		$query_args = $redirect_to ? ['action' => $redirect_to, 'TXN_ID' => $TXN_ID,] : [];
2526
+		$this->_redirect_after_action(
2527
+			$success,
2528
+			esc_html__('Transaction taxes and totals', 'event_espresso'),
2529
+			esc_html__('recalculated', 'event_espresso'),
2530
+			$query_args,
2531
+			true
2532
+		);
2533
+	}
2534 2534
 }
Please login to merge, or discard this patch.
admin_pages/registration_form/Registration_Form_Admin_Page.core.php 1 patch
Indentation   +756 added lines, -756 removed lines patch added patch discarded remove patch
@@ -15,699 +15,699 @@  discard block
 block discarded – undo
15 15
  */
16 16
 class Registration_Form_Admin_Page extends EE_Admin_Page
17 17
 {
18
-    /**
19
-     * holds the specific question object for the question details screen
20
-     *
21
-     * @var EE_Question $_question
22
-     */
23
-    protected $_question;
24
-
25
-    /**
26
-     * holds the specific question group object for the question group details screen
27
-     *
28
-     * @var EE_Question_Group $_question_group
29
-     */
30
-    protected $_question_group;
31
-
32
-    /**
33
-     *_question_model EEM_Question model instance (for queries)
34
-     *
35
-     * @var EEM_Question $_question_model ;
36
-     */
37
-    protected $_question_model;
38
-
39
-    /**
40
-     * _question_group_model EEM_Question_group instance (for queries)
41
-     *
42
-     * @var EEM_Question_Group $_question_group_model
43
-     */
44
-    protected $_question_group_model;
45
-
46
-
47
-    /**
48
-     * @Constructor
49
-     * @param bool $routing indicate whether we want to just load the object and handle routing or just load the object.
50
-     * @throws EE_Error
51
-     * @throws ReflectionException
52
-     */
53
-    public function __construct($routing = true)
54
-    {
55
-        require_once(EE_MODELS . 'EEM_Question.model.php');
56
-        require_once(EE_MODELS . 'EEM_Question_Group.model.php');
57
-        $this->_question_model       = EEM_Question::instance();
58
-        $this->_question_group_model = EEM_Question_Group::instance();
59
-        parent::__construct($routing);
60
-    }
61
-
62
-
63
-    protected function _init_page_props()
64
-    {
65
-        $this->page_slug        = REGISTRATION_FORM_PG_SLUG;
66
-        $this->page_label       = esc_html__('Registration Form', 'event_espresso');
67
-        $this->_admin_base_url  = REGISTRATION_FORM_ADMIN_URL;
68
-        $this->_admin_base_path = REGISTRATION_FORM_ADMIN;
69
-    }
70
-
71
-
72
-    protected function _ajax_hooks()
73
-    {
74
-    }
75
-
76
-
77
-    protected function _define_page_props()
78
-    {
79
-        $this->_admin_page_title = esc_html__('Registration Form', 'event_espresso');
80
-        $this->_labels           = [
81
-            'buttons' => [
82
-                'edit_question' => esc_html__('Edit Question', 'event_espresso'),
83
-            ],
84
-        ];
85
-    }
86
-
87
-
88
-    /**
89
-     *_set_page_routes
90
-     */
91
-    protected function _set_page_routes()
92
-    {
93
-        $qst_id             =
94
-            ! empty($this->_req_data['QST_ID'])
95
-                ? $this->_req_data['QST_ID']
96
-                : 0;
97
-        $this->_page_routes = [
98
-            'default' => [
99
-                'func'       => '_questions_overview_list_table',
100
-                'capability' => 'ee_read_questions',
101
-            ],
102
-
103
-            'edit_question' => [
104
-                'func'       => '_edit_question',
105
-                'capability' => 'ee_edit_question',
106
-                'obj_id'     => $qst_id,
107
-                'args'       => ['edit'],
108
-            ],
109
-
110
-            'question_groups' => [
111
-                'func'       => '_questions_groups_preview',
112
-                'capability' => 'ee_read_question_groups',
113
-            ],
114
-
115
-            'update_question' => [
116
-                'func'       => '_insert_or_update_question',
117
-                'args'       => ['new_question' => false],
118
-                'capability' => 'ee_edit_question',
119
-                'obj_id'     => $qst_id,
120
-                'noheader'   => true,
121
-            ],
122
-        ];
123
-    }
124
-
125
-
126
-    protected function _set_page_config()
127
-    {
128
-        $this->_page_config = [
129
-            'default' => [
130
-                'nav'           => [
131
-                    'label' =>  esc_html__('Questions', 'event_espresso'),
132
-                    'icon' => 'dashicons-editor-help',
133
-                    'order' => 10,
134
-                ],
135
-                'list_table'    => 'Registration_Form_Questions_Admin_List_Table',
136
-                'metaboxes'     => $this->_default_espresso_metaboxes,
137
-                'help_tabs'     => [
138
-                    'registration_form_questions_overview_help_tab'                           => [
139
-                        'title'    => esc_html__('Questions Overview', 'event_espresso'),
140
-                        'filename' => 'registration_form_questions_overview',
141
-                    ],
142
-                    'registration_form_questions_overview_table_column_headings_help_tab'     => [
143
-                        'title'    => esc_html__('Questions Overview Table Column Headings', 'event_espresso'),
144
-                        'filename' => 'registration_form_questions_overview_table_column_headings',
145
-                    ],
146
-                    'registration_form_questions_overview_views_bulk_actions_search_help_tab' => [
147
-                        'title'    => esc_html__('Question Overview Views & Bulk Actions & Search', 'event_espresso'),
148
-                        'filename' => 'registration_form_questions_overview_views_bulk_actions_search',
149
-                    ],
150
-                ],
151
-                'require_nonce' => false,
152
-            ],
153
-
154
-            'question_groups' => [
155
-                'nav'           => [
156
-                    'label' =>  esc_html__('Question Groups', 'event_espresso'),
157
-                    'icon' => 'dashicons-forms',
158
-                    'order' => 20,
159
-                ],
160
-                'metaboxes'     => $this->_default_espresso_metaboxes,
161
-                'help_tabs'     => [
162
-                    'registration_form_question_groups_help_tab' => [
163
-                        'title'    => esc_html__('Question Groups', 'event_espresso'),
164
-                        'filename' => 'registration_form_question_groups',
165
-                    ],
166
-                ],
167
-                'require_nonce' => false,
168
-            ],
169
-
170
-            'edit_question' => [
171
-                'nav'           => [
172
-                    'label'      => esc_html__('Edit Question', 'event_espresso'),
173
-                    'icon' => 'dashicons-edit-large',
174
-                    'order'      => 15,
175
-                    'persistent' => false,
176
-                    'url'        => isset($this->_req_data['question_id'])
177
-                        ? add_query_arg(
178
-                            ['question_id' => $this->_req_data['question_id']],
179
-                            $this->_current_page_view_url
180
-                        )
181
-                        : $this->_admin_base_url,
182
-                ],
183
-                'metaboxes'     => array_merge($this->_default_espresso_metaboxes, ['_publish_post_box']),
184
-                'help_tabs'     => [
185
-                    'registration_form_edit_question_group_help_tab' => [
186
-                        'title'    => esc_html__('Edit Question', 'event_espresso'),
187
-                        'filename' => 'registration_form_edit_question',
188
-                    ],
189
-                ],
190
-                'require_nonce' => false,
191
-            ],
192
-        ];
193
-    }
194
-
195
-
196
-    protected function _add_screen_options()
197
-    {
198
-        // todo
199
-    }
200
-
201
-
202
-    protected function _add_screen_options_default()
203
-    {
204
-        $page_title              = $this->_admin_page_title;
205
-        $this->_admin_page_title = esc_html__('Questions', 'event_espresso');
206
-        $this->_per_page_screen_option();
207
-        $this->_admin_page_title = $page_title;
208
-    }
209
-
210
-
211
-    protected function _add_screen_options_question_groups()
212
-    {
213
-        $page_title              = $this->_admin_page_title;
214
-        $this->_admin_page_title = esc_html__('Question Groups', 'event_espresso');
215
-        $this->_per_page_screen_option();
216
-        $this->_admin_page_title = $page_title;
217
-    }
218
-
219
-
220
-    // none of the below group are currently used for Event Categories
221
-    protected function _add_feature_pointers()
222
-    {
223
-    }
224
-
225
-
226
-    public function load_scripts_styles()
227
-    {
228
-        wp_register_style(
229
-            'espresso_registration',
230
-            REGISTRATION_FORM_ASSETS_URL . 'espresso_registration_form_admin.css',
231
-            [],
232
-            EVENT_ESPRESSO_VERSION
233
-        );
234
-        wp_enqueue_style('espresso_registration');
235
-    }
236
-
237
-
238
-    public function admin_init()
239
-    {
240
-    }
241
-
242
-
243
-    public function admin_notices()
244
-    {
245
-    }
246
-
247
-
248
-    public function admin_footer_scripts()
249
-    {
250
-    }
251
-
252
-
253
-    public function load_scripts_styles_default()
254
-    {
255
-    }
256
-
257
-
258
-    /**
259
-     * @throws EE_Error
260
-     */
261
-    public function load_scripts_styles_add_question()
262
-    {
263
-        $this->load_scripts_styles_question_details();
264
-    }
265
-
266
-
267
-    /**
268
-     * @throws EE_Error
269
-     */
270
-    public function load_scripts_styles_edit_question()
271
-    {
272
-        $this->load_scripts_styles_question_details();
273
-    }
274
-
275
-
276
-    /**
277
-     * Loads the JS required for adding or editing a question
278
-     *
279
-     * @throws EE_Error
280
-     * @throws EE_Error
281
-     */
282
-    protected function load_scripts_styles_question_details()
283
-    {
284
-        $this->load_scripts_styles_forms();
285
-        wp_register_script(
286
-            'espresso_registration_form_single',
287
-            REGISTRATION_FORM_ASSETS_URL . 'espresso_registration_form_admin.js',
288
-            ['jquery-ui-sortable'],
289
-            EVENT_ESPRESSO_VERSION,
290
-            true
291
-        );
292
-        wp_enqueue_script('espresso_registration_form_single');
293
-        wp_localize_script(
294
-            'espresso_registration_form_single',
295
-            'ee_question_data',
296
-            [
297
-                'question_types_with_max'    => EEM_Question::instance()->questionTypesWithMaxLength(),
298
-                'question_type_with_options' => EEM_Question::instance()->question_types_with_options(),
299
-            ]
300
-        );
301
-    }
302
-
303
-
304
-    public function recaptcha_info_help_tab()
305
-    {
306
-        $template = REGISTRATION_FORM_TEMPLATE_PATH . 'recaptcha_info_help_tab.template.php';
307
-        EEH_Template::display_template($template, []);
308
-    }
309
-
310
-
311
-    public function load_scripts_styles_forms()
312
-    {
313
-        // styles
314
-        wp_enqueue_style('espresso-ui-theme');
315
-        // scripts
316
-        wp_enqueue_script('ee_admin_js');
317
-    }
318
-
319
-
320
-    protected function _set_list_table_views_default()
321
-    {
322
-        $this->_views = [
323
-            'all' => [
324
-                'slug'  => 'all',
325
-                'label' => esc_html__('View All Questions', 'event_espresso'),
326
-                'count' => 0,
327
-            ],
328
-        ];
329
-
330
-        if (
331
-            EE_Registry::instance()->CAP->current_user_can(
332
-                'ee_delete_questions',
333
-                'espresso_registration_form_trash_questions'
334
-            )
335
-        ) {
336
-            $this->_views['trash'] = [
337
-                'slug'  => 'trash',
338
-                'label' => esc_html__('Trash', 'event_espresso'),
339
-                'count' => 0,
340
-            ];
341
-        }
342
-    }
343
-
344
-
345
-    /**
346
-     * This just previews the question groups tab that comes in caffeinated.
347
-     *
348
-     * @return void html
349
-     * @throws EE_Error
350
-     */
351
-    protected function _questions_groups_preview()
352
-    {
353
-        $this->_admin_page_title              = esc_html__('Question Groups (Preview)', 'event_espresso');
354
-        $this->_template_args['preview_img']  =
355
-            '<img src="' . REGISTRATION_FORM_ASSETS_URL . 'caf_reg_form_preview.jpg" alt="'
356
-            . esc_attr__(
357
-                'Preview Question Groups Overview List Table screenshot',
358
-                'event_espresso'
359
-            ) . '" />';
360
-        $this->_template_args['preview_text'] = '<strong>'
361
-                                                . esc_html__(
362
-                                                    'Question Groups is a feature that is only available in the premium version of Event Espresso 4 which is available with a support license purchase on EventEspresso.com. With the Question Groups feature you are able to create new question groups, edit existing question groups, and create and edit new questions and add them to question groups.',
363
-                                                    'event_espresso'
364
-                                                ) . '</strong>';
365
-        $this->display_admin_caf_preview_page('question_groups_tab');
366
-    }
367
-
368
-
369
-    /**
370
-     * Extracts the question field's values from the POST request to update or insert them
371
-     *
372
-     * @param EEM_Base $model
373
-     * @return array where each key is the name of a model's field/db column, and each value is its value.
374
-     * @throws EE_Error
375
-     */
376
-    protected function _set_column_values_for(EEM_Base $model)
377
-    {
378
-        $question_model = EEM_Question::instance();
379
-        $set_column_values = [];
380
-
381
-        // some initial checks for proper values.
382
-        // if QST_admin_only, then no matter what QST_required is we disable.
383
-        if (! empty($this->_req_data['QST_admin_only'])) {
384
-            $this->_req_data['QST_required'] = 0;
385
-        }
386
-        // if the question shouldn't have a max length, don't let them set one
387
-        if (
388
-            ! isset(
389
-                $this->_req_data['QST_type'],
390
-                $this->_req_data['QST_max']
391
-            )
392
-            || ! in_array(
393
-                $this->_req_data['QST_type'],
394
-                $question_model->questionTypesWithMaxLength(),
395
-                true
396
-            )
397
-        ) {
398
-            // they're not allowed to set the max
399
-            $this->_req_data['QST_max'] = null;
400
-        }
401
-        foreach ($model->field_settings() as $fieldName => $settings) {
402
-            // basically if QSG_identifier is empty or not set
403
-            if (
404
-                $fieldName === 'QSG_identifier'
405
-                && (isset($this->_req_data['QSG_identifier']) && empty($this->_req_data['QSG_identifier']))
406
-            ) {
407
-                $QSG_name = $this->_req_data['QSG_name'] ?? '';
408
-                $set_column_values[ $fieldName ] = sanitize_title($QSG_name) . '-' . uniqid('', true);
409
-            } elseif (
410
-                $fieldName === 'QST_admin_label'
411
-                && (isset($this->_req_data['QST_admin_label']) && empty($this->_req_data['QST_admin_label']))
412
-            ) {
413
-                // the admin label is blank, use a slug version of the question text
414
-                $QST_text = $this->_req_data['QST_display_text'] ?? '';
415
-                $set_column_values[ $fieldName ] = sanitize_title(wp_trim_words($QST_text, 10));
416
-            } elseif ($fieldName === 'QST_admin_only' && (! isset($this->_req_data['QST_admin_only']))) {
417
-                $set_column_values[ $fieldName ] = 0;
418
-            } elseif ($fieldName === 'QST_max') {
419
-                $qst_system = $question_model->get_var(
420
-                    [
421
-                        [
422
-                            'QST_ID' => $this->_req_data['QST_ID'] ?? 0,
423
-                        ],
424
-                    ],
425
-                    'QST_system'
426
-                );
427
-                $max_max    = $question_model->absolute_max_for_system_question((string) $qst_system);
428
-                if (empty($this->_req_data['QST_max']) || $this->_req_data['QST_max'] > $max_max) {
429
-                    $set_column_values[ $fieldName ] = $max_max;
430
-                }
431
-            }
432
-
433
-
434
-            // only add a property to the array if it's not null (otherwise the model should just use the default value)
435
-            if (
436
-                ! isset($set_column_values[ $fieldName ]) && isset($this->_req_data[ $fieldName ])
437
-            ) {
438
-                $set_column_values[ $fieldName ] = $this->_req_data[ $fieldName ];
439
-            }
440
-        }
441
-        // validation fo this data to be performed by the model before insertion.
442
-        return $set_column_values;
443
-    }
444
-
445
-
446
-    /**
447
-     *_questions_overview_list_table
448
-     *
449
-     * @throws EE_Error
450
-     */
451
-    protected function _questions_overview_list_table()
452
-    {
453
-        $this->_search_btn_label = esc_html__('Questions', 'event_espresso');
454
-        $this->display_admin_list_table_page_with_sidebar();
455
-    }
456
-
457
-
458
-    /**
459
-     * _edit_question
460
-     *
461
-     * @throws EE_Error
462
-     * @throws ReflectionException
463
-     */
464
-    protected function _edit_question()
465
-    {
466
-        $ID = isset($this->_req_data['QST_ID']) && ! empty($this->_req_data['QST_ID'])
467
-            ? absint($this->_req_data['QST_ID'])
468
-            : false;
469
-
470
-        switch ($this->_req_action) {
471
-            case 'add_question':
472
-                $this->_admin_page_title = esc_html__('Add Question', 'event_espresso');
473
-                break;
474
-            case 'edit_question':
475
-                $this->_admin_page_title = esc_html__('Edit Question', 'event_espresso');
476
-                break;
477
-            default:
478
-                $this->_admin_page_title = ucwords(str_replace('_', ' ', $this->_req_action));
479
-        }
480
-
481
-        // add PRC_ID to title if editing
482
-        $this->_admin_page_title =
483
-            $ID
484
-                ? $this->_admin_page_title . ' # ' . $ID
485
-                : $this->_admin_page_title;
486
-        if ($ID) {
487
-            $question                 = $this->_question_model->get_one_by_ID($ID);
488
-            $additional_hidden_fields = ['QST_ID' => ['type' => 'hidden', 'value' => $ID]];
489
-            $this->_set_add_edit_form_tags('update_question', $additional_hidden_fields);
490
-        } else {
491
-            $question = EE_Question::new_instance();
492
-            $question->set_order_to_latest();
493
-            $this->_set_add_edit_form_tags('insert_question');
494
-        }
495
-        if ($question->system_ID() === EEM_Attendee::system_question_phone) {
496
-            $question_types = array_intersect_key(
497
-                EEM_Question::instance()->allowed_question_types(),
498
-                array_flip(
499
-                    [
500
-                        EEM_Question::QST_type_text,
501
-                        EEM_Question::QST_type_us_phone,
502
-                    ]
503
-                )
504
-            );
505
-        } else {
506
-            $question_types = $question->has_answers()
507
-                ? $this->_question_model->question_types_in_same_category($question->type())
508
-                : $this->_question_model->allowed_question_types();
509
-        }
510
-        $this->_template_args['QST_ID']                     = $ID;
511
-        $this->_template_args['question']                   = $question;
512
-        $this->_template_args['question_types']             = $question_types;
513
-        $this->_template_args['max_max']                    =
514
-            EEM_Question::instance()->absolute_max_for_system_question(
515
-                $question->system_ID()
516
-            );
517
-        $this->_template_args['question_type_descriptions'] = $this->_get_question_type_descriptions();
518
-        $this->_set_publish_post_box_vars('id', $ID);
519
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
520
-            REGISTRATION_FORM_TEMPLATE_PATH . 'questions_main_meta_box.template.php',
521
-            $this->_template_args,
522
-            true
523
-        );
524
-
525
-        // the details template wrapper
526
-        $this->display_admin_page_with_sidebar();
527
-    }
528
-
529
-
530
-    /**
531
-     * @return string
532
-     * @throws EE_Error
533
-     * @throws ReflectionException
534
-     */
535
-    protected function _get_question_type_descriptions()
536
-    {
537
-        EE_Registry::instance()->load_helper('HTML');
538
-        $descriptions               = '';
539
-        $question_type_descriptions = EEM_Question::instance()->question_descriptions();
540
-        foreach ($question_type_descriptions as $type => $question_type_description) {
541
-            if ($type == 'HTML_TEXTAREA') {
542
-                $html                      = new EE_Simple_HTML_Validation_Strategy();
543
-                $question_type_description .= sprintf(
544
-                    esc_html__('%1$s(allowed tags: %2$s)', 'event_espresso'),
545
-                    '<br/>',
546
-                    $html->get_list_of_allowed_tags()
547
-                );
548
-            }
549
-            $descriptions .= EEH_HTML::p(
550
-                $question_type_description,
551
-                'question_type_description-' . $type,
552
-                'question_type_description description',
553
-                'display:none;'
554
-            );
555
-        }
556
-        return $descriptions;
557
-    }
558
-
559
-
560
-    /**
561
-     * @param bool|true $new_question
562
-     * @throws EE_Error
563
-     * @throws ReflectionException
564
-     */
565
-    protected function _insert_or_update_question($new_question = true)
566
-    {
567
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
568
-        $set_column_values = $this->_set_column_values_for($this->_question_model);
569
-        if ($new_question) {
570
-            $question    = EE_Question::new_instance($set_column_values);
571
-            $action_desc = 'added';
572
-        } else {
573
-            $question = EEM_Question::instance()->get_one_by_ID(absint($this->_req_data['QST_ID']));
574
-            foreach ($set_column_values as $field => $new_value) {
575
-                $question->set($field, $new_value);
576
-            }
577
-            $action_desc = 'updated';
578
-        }
579
-        $success = $question->save();
580
-        $ID      = $question->ID();
581
-        if ($ID && $question->should_have_question_options()) {
582
-            // save the related options
583
-            // trash removed options, save old ones
584
-            // get list of all options
585
-            $options = $question->options();
586
-            if (! empty($options)) {
587
-                foreach ($options as $option_ID => $option) {
588
-                    $option_req_index = $this->_get_option_req_data_index($option_ID);
589
-                    if ($option_req_index !== false) {
590
-                        $option->save($this->_req_data['question_options'][ $option_req_index ]);
591
-                    } else {
592
-                        // not found, remove it
593
-                        $option->delete();
594
-                    }
595
-                }
596
-            }
597
-            // save new related options
598
-            foreach ($this->_req_data['question_options'] as $index => $option_req_data) {
599
-                // skip $index that is from our sample
600
-                if ($index === 'xxcountxx') {
601
-                    continue;
602
-                }
603
-                // note we allow saving blank options.
604
-                if (empty($option_req_data['QSO_ID'])) {
605
-                    // no ID! save it!
606
-                    $new_option = EE_Question_Option::new_instance(
607
-                        [
608
-                            'QSO_value' => $option_req_data['QSO_value'],
609
-                            'QSO_desc'  => $option_req_data['QSO_desc'],
610
-                            'QSO_order' => $option_req_data['QSO_order'],
611
-                            'QST_ID'    => $question->ID(),
612
-                        ]
613
-                    );
614
-                    $new_option->save();
615
-                }
616
-            }
617
-        }
618
-        $query_args = ['action' => 'edit_question', 'QST_ID' => $ID];
619
-        if ($success !== 0) {
620
-            $msg = $new_question
621
-                ? sprintf(
622
-                    esc_html__('The %s has been created', 'event_espresso'),
623
-                    $this->_question_model->item_name()
624
-                )
625
-                : sprintf(
626
-                    esc_html__('The %s has been updated', 'event_espresso'),
627
-                    $this->_question_model->item_name()
628
-                );
629
-            EE_Error::add_success($msg);
630
-        }
631
-
632
-        $this->_redirect_after_action(false, '', $action_desc, $query_args, true);
633
-    }
634
-
635
-
636
-    /**
637
-     * Upon saving a question, there should be an array of 'question_options'. This array is index numerically, but not
638
-     * by ID
639
-     * (this is done because new question options don't have an ID, but we may want to add multiple simultaneously).
640
-     * So, this function gets the index in that request data array called question_options. Returns FALSE if not found.
641
-     *
642
-     * @param int $ID of the question option to find
643
-     * @return int index in question_options array if successful, FALSE if unsuccessful
644
-     */
645
-    protected function _get_option_req_data_index($ID)
646
-    {
647
-        $req_data_for_question_options = $this->_req_data['question_options'];
648
-        foreach ($req_data_for_question_options as $num => $option_data) {
649
-            if (array_key_exists('QSO_ID', $option_data) && (int) $option_data['QSO_ID'] === $ID) {
650
-                return $num;
651
-            }
652
-        }
653
-        return false;
654
-    }
655
-
656
-
657
-
658
-
659
-    /***********/
660
-    /* QUERIES */
661
-    /**
662
-     * For internal use in getting all the query parameters
663
-     * (because it's pretty well the same between question, question groups,
664
-     * and for both when searching for trashed and untrashed ones)
665
-     *
666
-     * @param EEM_Base $model either EEM_Question or EEM_Question_Group
667
-     * @param int      $per_page
668
-     * @param int      $current_page
669
-     * @return array model query params, @see
670
-     *               https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
671
-     */
672
-    protected function get_query_params($model, $per_page = 10, $current_page = 10)
673
-    {
674
-        $query_params             = [];
675
-        $offset                   = ($current_page - 1) * $per_page;
676
-        $query_params['limit']    = [$offset, $per_page];
677
-        $order                    =
678
-            (isset($this->_req_data['order']) && ! empty($this->_req_data['order']))
679
-                ? $this->_req_data['order']
680
-                : 'ASC';
681
-        $orderby_field            =
682
-            $model instanceof EEM_Question
683
-                ? 'QST_ID'
684
-                : 'QSG_order';
685
-        $field_to_order_by        =
686
-            empty($this->_req_data['orderby'])
687
-                ? $orderby_field
688
-                : $this->_req_data['orderby'];
689
-        $query_params['order_by'] = [$field_to_order_by => $order];
690
-        $search_string            =
691
-            array_key_exists('s', $this->_req_data)
692
-                ? $this->_req_data['s']
693
-                : null;
694
-        if (! empty($search_string)) {
695
-            if ($model instanceof EEM_Question_Group) {
696
-                $query_params[0] = [
697
-                    'OR' => [
698
-                        'QSG_name' => ['LIKE', "%$search_string%"],
699
-                        'QSG_desc' => ['LIKE', "%$search_string%"],
700
-                    ],
701
-                ];
702
-            } else {
703
-                $query_params[0] = [
704
-                    'QST_display_text' => ['LIKE', "%$search_string%"],
705
-                ];
706
-            }
707
-        }
708
-
709
-        // capability checks (just leaving this commented out for reference because it illustrates some complicated query params that could be useful when fully implemented)
710
-        /*if ( $model instanceof EEM_Question_Group ) {
18
+	/**
19
+	 * holds the specific question object for the question details screen
20
+	 *
21
+	 * @var EE_Question $_question
22
+	 */
23
+	protected $_question;
24
+
25
+	/**
26
+	 * holds the specific question group object for the question group details screen
27
+	 *
28
+	 * @var EE_Question_Group $_question_group
29
+	 */
30
+	protected $_question_group;
31
+
32
+	/**
33
+	 *_question_model EEM_Question model instance (for queries)
34
+	 *
35
+	 * @var EEM_Question $_question_model ;
36
+	 */
37
+	protected $_question_model;
38
+
39
+	/**
40
+	 * _question_group_model EEM_Question_group instance (for queries)
41
+	 *
42
+	 * @var EEM_Question_Group $_question_group_model
43
+	 */
44
+	protected $_question_group_model;
45
+
46
+
47
+	/**
48
+	 * @Constructor
49
+	 * @param bool $routing indicate whether we want to just load the object and handle routing or just load the object.
50
+	 * @throws EE_Error
51
+	 * @throws ReflectionException
52
+	 */
53
+	public function __construct($routing = true)
54
+	{
55
+		require_once(EE_MODELS . 'EEM_Question.model.php');
56
+		require_once(EE_MODELS . 'EEM_Question_Group.model.php');
57
+		$this->_question_model       = EEM_Question::instance();
58
+		$this->_question_group_model = EEM_Question_Group::instance();
59
+		parent::__construct($routing);
60
+	}
61
+
62
+
63
+	protected function _init_page_props()
64
+	{
65
+		$this->page_slug        = REGISTRATION_FORM_PG_SLUG;
66
+		$this->page_label       = esc_html__('Registration Form', 'event_espresso');
67
+		$this->_admin_base_url  = REGISTRATION_FORM_ADMIN_URL;
68
+		$this->_admin_base_path = REGISTRATION_FORM_ADMIN;
69
+	}
70
+
71
+
72
+	protected function _ajax_hooks()
73
+	{
74
+	}
75
+
76
+
77
+	protected function _define_page_props()
78
+	{
79
+		$this->_admin_page_title = esc_html__('Registration Form', 'event_espresso');
80
+		$this->_labels           = [
81
+			'buttons' => [
82
+				'edit_question' => esc_html__('Edit Question', 'event_espresso'),
83
+			],
84
+		];
85
+	}
86
+
87
+
88
+	/**
89
+	 *_set_page_routes
90
+	 */
91
+	protected function _set_page_routes()
92
+	{
93
+		$qst_id             =
94
+			! empty($this->_req_data['QST_ID'])
95
+				? $this->_req_data['QST_ID']
96
+				: 0;
97
+		$this->_page_routes = [
98
+			'default' => [
99
+				'func'       => '_questions_overview_list_table',
100
+				'capability' => 'ee_read_questions',
101
+			],
102
+
103
+			'edit_question' => [
104
+				'func'       => '_edit_question',
105
+				'capability' => 'ee_edit_question',
106
+				'obj_id'     => $qst_id,
107
+				'args'       => ['edit'],
108
+			],
109
+
110
+			'question_groups' => [
111
+				'func'       => '_questions_groups_preview',
112
+				'capability' => 'ee_read_question_groups',
113
+			],
114
+
115
+			'update_question' => [
116
+				'func'       => '_insert_or_update_question',
117
+				'args'       => ['new_question' => false],
118
+				'capability' => 'ee_edit_question',
119
+				'obj_id'     => $qst_id,
120
+				'noheader'   => true,
121
+			],
122
+		];
123
+	}
124
+
125
+
126
+	protected function _set_page_config()
127
+	{
128
+		$this->_page_config = [
129
+			'default' => [
130
+				'nav'           => [
131
+					'label' =>  esc_html__('Questions', 'event_espresso'),
132
+					'icon' => 'dashicons-editor-help',
133
+					'order' => 10,
134
+				],
135
+				'list_table'    => 'Registration_Form_Questions_Admin_List_Table',
136
+				'metaboxes'     => $this->_default_espresso_metaboxes,
137
+				'help_tabs'     => [
138
+					'registration_form_questions_overview_help_tab'                           => [
139
+						'title'    => esc_html__('Questions Overview', 'event_espresso'),
140
+						'filename' => 'registration_form_questions_overview',
141
+					],
142
+					'registration_form_questions_overview_table_column_headings_help_tab'     => [
143
+						'title'    => esc_html__('Questions Overview Table Column Headings', 'event_espresso'),
144
+						'filename' => 'registration_form_questions_overview_table_column_headings',
145
+					],
146
+					'registration_form_questions_overview_views_bulk_actions_search_help_tab' => [
147
+						'title'    => esc_html__('Question Overview Views & Bulk Actions & Search', 'event_espresso'),
148
+						'filename' => 'registration_form_questions_overview_views_bulk_actions_search',
149
+					],
150
+				],
151
+				'require_nonce' => false,
152
+			],
153
+
154
+			'question_groups' => [
155
+				'nav'           => [
156
+					'label' =>  esc_html__('Question Groups', 'event_espresso'),
157
+					'icon' => 'dashicons-forms',
158
+					'order' => 20,
159
+				],
160
+				'metaboxes'     => $this->_default_espresso_metaboxes,
161
+				'help_tabs'     => [
162
+					'registration_form_question_groups_help_tab' => [
163
+						'title'    => esc_html__('Question Groups', 'event_espresso'),
164
+						'filename' => 'registration_form_question_groups',
165
+					],
166
+				],
167
+				'require_nonce' => false,
168
+			],
169
+
170
+			'edit_question' => [
171
+				'nav'           => [
172
+					'label'      => esc_html__('Edit Question', 'event_espresso'),
173
+					'icon' => 'dashicons-edit-large',
174
+					'order'      => 15,
175
+					'persistent' => false,
176
+					'url'        => isset($this->_req_data['question_id'])
177
+						? add_query_arg(
178
+							['question_id' => $this->_req_data['question_id']],
179
+							$this->_current_page_view_url
180
+						)
181
+						: $this->_admin_base_url,
182
+				],
183
+				'metaboxes'     => array_merge($this->_default_espresso_metaboxes, ['_publish_post_box']),
184
+				'help_tabs'     => [
185
+					'registration_form_edit_question_group_help_tab' => [
186
+						'title'    => esc_html__('Edit Question', 'event_espresso'),
187
+						'filename' => 'registration_form_edit_question',
188
+					],
189
+				],
190
+				'require_nonce' => false,
191
+			],
192
+		];
193
+	}
194
+
195
+
196
+	protected function _add_screen_options()
197
+	{
198
+		// todo
199
+	}
200
+
201
+
202
+	protected function _add_screen_options_default()
203
+	{
204
+		$page_title              = $this->_admin_page_title;
205
+		$this->_admin_page_title = esc_html__('Questions', 'event_espresso');
206
+		$this->_per_page_screen_option();
207
+		$this->_admin_page_title = $page_title;
208
+	}
209
+
210
+
211
+	protected function _add_screen_options_question_groups()
212
+	{
213
+		$page_title              = $this->_admin_page_title;
214
+		$this->_admin_page_title = esc_html__('Question Groups', 'event_espresso');
215
+		$this->_per_page_screen_option();
216
+		$this->_admin_page_title = $page_title;
217
+	}
218
+
219
+
220
+	// none of the below group are currently used for Event Categories
221
+	protected function _add_feature_pointers()
222
+	{
223
+	}
224
+
225
+
226
+	public function load_scripts_styles()
227
+	{
228
+		wp_register_style(
229
+			'espresso_registration',
230
+			REGISTRATION_FORM_ASSETS_URL . 'espresso_registration_form_admin.css',
231
+			[],
232
+			EVENT_ESPRESSO_VERSION
233
+		);
234
+		wp_enqueue_style('espresso_registration');
235
+	}
236
+
237
+
238
+	public function admin_init()
239
+	{
240
+	}
241
+
242
+
243
+	public function admin_notices()
244
+	{
245
+	}
246
+
247
+
248
+	public function admin_footer_scripts()
249
+	{
250
+	}
251
+
252
+
253
+	public function load_scripts_styles_default()
254
+	{
255
+	}
256
+
257
+
258
+	/**
259
+	 * @throws EE_Error
260
+	 */
261
+	public function load_scripts_styles_add_question()
262
+	{
263
+		$this->load_scripts_styles_question_details();
264
+	}
265
+
266
+
267
+	/**
268
+	 * @throws EE_Error
269
+	 */
270
+	public function load_scripts_styles_edit_question()
271
+	{
272
+		$this->load_scripts_styles_question_details();
273
+	}
274
+
275
+
276
+	/**
277
+	 * Loads the JS required for adding or editing a question
278
+	 *
279
+	 * @throws EE_Error
280
+	 * @throws EE_Error
281
+	 */
282
+	protected function load_scripts_styles_question_details()
283
+	{
284
+		$this->load_scripts_styles_forms();
285
+		wp_register_script(
286
+			'espresso_registration_form_single',
287
+			REGISTRATION_FORM_ASSETS_URL . 'espresso_registration_form_admin.js',
288
+			['jquery-ui-sortable'],
289
+			EVENT_ESPRESSO_VERSION,
290
+			true
291
+		);
292
+		wp_enqueue_script('espresso_registration_form_single');
293
+		wp_localize_script(
294
+			'espresso_registration_form_single',
295
+			'ee_question_data',
296
+			[
297
+				'question_types_with_max'    => EEM_Question::instance()->questionTypesWithMaxLength(),
298
+				'question_type_with_options' => EEM_Question::instance()->question_types_with_options(),
299
+			]
300
+		);
301
+	}
302
+
303
+
304
+	public function recaptcha_info_help_tab()
305
+	{
306
+		$template = REGISTRATION_FORM_TEMPLATE_PATH . 'recaptcha_info_help_tab.template.php';
307
+		EEH_Template::display_template($template, []);
308
+	}
309
+
310
+
311
+	public function load_scripts_styles_forms()
312
+	{
313
+		// styles
314
+		wp_enqueue_style('espresso-ui-theme');
315
+		// scripts
316
+		wp_enqueue_script('ee_admin_js');
317
+	}
318
+
319
+
320
+	protected function _set_list_table_views_default()
321
+	{
322
+		$this->_views = [
323
+			'all' => [
324
+				'slug'  => 'all',
325
+				'label' => esc_html__('View All Questions', 'event_espresso'),
326
+				'count' => 0,
327
+			],
328
+		];
329
+
330
+		if (
331
+			EE_Registry::instance()->CAP->current_user_can(
332
+				'ee_delete_questions',
333
+				'espresso_registration_form_trash_questions'
334
+			)
335
+		) {
336
+			$this->_views['trash'] = [
337
+				'slug'  => 'trash',
338
+				'label' => esc_html__('Trash', 'event_espresso'),
339
+				'count' => 0,
340
+			];
341
+		}
342
+	}
343
+
344
+
345
+	/**
346
+	 * This just previews the question groups tab that comes in caffeinated.
347
+	 *
348
+	 * @return void html
349
+	 * @throws EE_Error
350
+	 */
351
+	protected function _questions_groups_preview()
352
+	{
353
+		$this->_admin_page_title              = esc_html__('Question Groups (Preview)', 'event_espresso');
354
+		$this->_template_args['preview_img']  =
355
+			'<img src="' . REGISTRATION_FORM_ASSETS_URL . 'caf_reg_form_preview.jpg" alt="'
356
+			. esc_attr__(
357
+				'Preview Question Groups Overview List Table screenshot',
358
+				'event_espresso'
359
+			) . '" />';
360
+		$this->_template_args['preview_text'] = '<strong>'
361
+												. esc_html__(
362
+													'Question Groups is a feature that is only available in the premium version of Event Espresso 4 which is available with a support license purchase on EventEspresso.com. With the Question Groups feature you are able to create new question groups, edit existing question groups, and create and edit new questions and add them to question groups.',
363
+													'event_espresso'
364
+												) . '</strong>';
365
+		$this->display_admin_caf_preview_page('question_groups_tab');
366
+	}
367
+
368
+
369
+	/**
370
+	 * Extracts the question field's values from the POST request to update or insert them
371
+	 *
372
+	 * @param EEM_Base $model
373
+	 * @return array where each key is the name of a model's field/db column, and each value is its value.
374
+	 * @throws EE_Error
375
+	 */
376
+	protected function _set_column_values_for(EEM_Base $model)
377
+	{
378
+		$question_model = EEM_Question::instance();
379
+		$set_column_values = [];
380
+
381
+		// some initial checks for proper values.
382
+		// if QST_admin_only, then no matter what QST_required is we disable.
383
+		if (! empty($this->_req_data['QST_admin_only'])) {
384
+			$this->_req_data['QST_required'] = 0;
385
+		}
386
+		// if the question shouldn't have a max length, don't let them set one
387
+		if (
388
+			! isset(
389
+				$this->_req_data['QST_type'],
390
+				$this->_req_data['QST_max']
391
+			)
392
+			|| ! in_array(
393
+				$this->_req_data['QST_type'],
394
+				$question_model->questionTypesWithMaxLength(),
395
+				true
396
+			)
397
+		) {
398
+			// they're not allowed to set the max
399
+			$this->_req_data['QST_max'] = null;
400
+		}
401
+		foreach ($model->field_settings() as $fieldName => $settings) {
402
+			// basically if QSG_identifier is empty or not set
403
+			if (
404
+				$fieldName === 'QSG_identifier'
405
+				&& (isset($this->_req_data['QSG_identifier']) && empty($this->_req_data['QSG_identifier']))
406
+			) {
407
+				$QSG_name = $this->_req_data['QSG_name'] ?? '';
408
+				$set_column_values[ $fieldName ] = sanitize_title($QSG_name) . '-' . uniqid('', true);
409
+			} elseif (
410
+				$fieldName === 'QST_admin_label'
411
+				&& (isset($this->_req_data['QST_admin_label']) && empty($this->_req_data['QST_admin_label']))
412
+			) {
413
+				// the admin label is blank, use a slug version of the question text
414
+				$QST_text = $this->_req_data['QST_display_text'] ?? '';
415
+				$set_column_values[ $fieldName ] = sanitize_title(wp_trim_words($QST_text, 10));
416
+			} elseif ($fieldName === 'QST_admin_only' && (! isset($this->_req_data['QST_admin_only']))) {
417
+				$set_column_values[ $fieldName ] = 0;
418
+			} elseif ($fieldName === 'QST_max') {
419
+				$qst_system = $question_model->get_var(
420
+					[
421
+						[
422
+							'QST_ID' => $this->_req_data['QST_ID'] ?? 0,
423
+						],
424
+					],
425
+					'QST_system'
426
+				);
427
+				$max_max    = $question_model->absolute_max_for_system_question((string) $qst_system);
428
+				if (empty($this->_req_data['QST_max']) || $this->_req_data['QST_max'] > $max_max) {
429
+					$set_column_values[ $fieldName ] = $max_max;
430
+				}
431
+			}
432
+
433
+
434
+			// only add a property to the array if it's not null (otherwise the model should just use the default value)
435
+			if (
436
+				! isset($set_column_values[ $fieldName ]) && isset($this->_req_data[ $fieldName ])
437
+			) {
438
+				$set_column_values[ $fieldName ] = $this->_req_data[ $fieldName ];
439
+			}
440
+		}
441
+		// validation fo this data to be performed by the model before insertion.
442
+		return $set_column_values;
443
+	}
444
+
445
+
446
+	/**
447
+	 *_questions_overview_list_table
448
+	 *
449
+	 * @throws EE_Error
450
+	 */
451
+	protected function _questions_overview_list_table()
452
+	{
453
+		$this->_search_btn_label = esc_html__('Questions', 'event_espresso');
454
+		$this->display_admin_list_table_page_with_sidebar();
455
+	}
456
+
457
+
458
+	/**
459
+	 * _edit_question
460
+	 *
461
+	 * @throws EE_Error
462
+	 * @throws ReflectionException
463
+	 */
464
+	protected function _edit_question()
465
+	{
466
+		$ID = isset($this->_req_data['QST_ID']) && ! empty($this->_req_data['QST_ID'])
467
+			? absint($this->_req_data['QST_ID'])
468
+			: false;
469
+
470
+		switch ($this->_req_action) {
471
+			case 'add_question':
472
+				$this->_admin_page_title = esc_html__('Add Question', 'event_espresso');
473
+				break;
474
+			case 'edit_question':
475
+				$this->_admin_page_title = esc_html__('Edit Question', 'event_espresso');
476
+				break;
477
+			default:
478
+				$this->_admin_page_title = ucwords(str_replace('_', ' ', $this->_req_action));
479
+		}
480
+
481
+		// add PRC_ID to title if editing
482
+		$this->_admin_page_title =
483
+			$ID
484
+				? $this->_admin_page_title . ' # ' . $ID
485
+				: $this->_admin_page_title;
486
+		if ($ID) {
487
+			$question                 = $this->_question_model->get_one_by_ID($ID);
488
+			$additional_hidden_fields = ['QST_ID' => ['type' => 'hidden', 'value' => $ID]];
489
+			$this->_set_add_edit_form_tags('update_question', $additional_hidden_fields);
490
+		} else {
491
+			$question = EE_Question::new_instance();
492
+			$question->set_order_to_latest();
493
+			$this->_set_add_edit_form_tags('insert_question');
494
+		}
495
+		if ($question->system_ID() === EEM_Attendee::system_question_phone) {
496
+			$question_types = array_intersect_key(
497
+				EEM_Question::instance()->allowed_question_types(),
498
+				array_flip(
499
+					[
500
+						EEM_Question::QST_type_text,
501
+						EEM_Question::QST_type_us_phone,
502
+					]
503
+				)
504
+			);
505
+		} else {
506
+			$question_types = $question->has_answers()
507
+				? $this->_question_model->question_types_in_same_category($question->type())
508
+				: $this->_question_model->allowed_question_types();
509
+		}
510
+		$this->_template_args['QST_ID']                     = $ID;
511
+		$this->_template_args['question']                   = $question;
512
+		$this->_template_args['question_types']             = $question_types;
513
+		$this->_template_args['max_max']                    =
514
+			EEM_Question::instance()->absolute_max_for_system_question(
515
+				$question->system_ID()
516
+			);
517
+		$this->_template_args['question_type_descriptions'] = $this->_get_question_type_descriptions();
518
+		$this->_set_publish_post_box_vars('id', $ID);
519
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
520
+			REGISTRATION_FORM_TEMPLATE_PATH . 'questions_main_meta_box.template.php',
521
+			$this->_template_args,
522
+			true
523
+		);
524
+
525
+		// the details template wrapper
526
+		$this->display_admin_page_with_sidebar();
527
+	}
528
+
529
+
530
+	/**
531
+	 * @return string
532
+	 * @throws EE_Error
533
+	 * @throws ReflectionException
534
+	 */
535
+	protected function _get_question_type_descriptions()
536
+	{
537
+		EE_Registry::instance()->load_helper('HTML');
538
+		$descriptions               = '';
539
+		$question_type_descriptions = EEM_Question::instance()->question_descriptions();
540
+		foreach ($question_type_descriptions as $type => $question_type_description) {
541
+			if ($type == 'HTML_TEXTAREA') {
542
+				$html                      = new EE_Simple_HTML_Validation_Strategy();
543
+				$question_type_description .= sprintf(
544
+					esc_html__('%1$s(allowed tags: %2$s)', 'event_espresso'),
545
+					'<br/>',
546
+					$html->get_list_of_allowed_tags()
547
+				);
548
+			}
549
+			$descriptions .= EEH_HTML::p(
550
+				$question_type_description,
551
+				'question_type_description-' . $type,
552
+				'question_type_description description',
553
+				'display:none;'
554
+			);
555
+		}
556
+		return $descriptions;
557
+	}
558
+
559
+
560
+	/**
561
+	 * @param bool|true $new_question
562
+	 * @throws EE_Error
563
+	 * @throws ReflectionException
564
+	 */
565
+	protected function _insert_or_update_question($new_question = true)
566
+	{
567
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
568
+		$set_column_values = $this->_set_column_values_for($this->_question_model);
569
+		if ($new_question) {
570
+			$question    = EE_Question::new_instance($set_column_values);
571
+			$action_desc = 'added';
572
+		} else {
573
+			$question = EEM_Question::instance()->get_one_by_ID(absint($this->_req_data['QST_ID']));
574
+			foreach ($set_column_values as $field => $new_value) {
575
+				$question->set($field, $new_value);
576
+			}
577
+			$action_desc = 'updated';
578
+		}
579
+		$success = $question->save();
580
+		$ID      = $question->ID();
581
+		if ($ID && $question->should_have_question_options()) {
582
+			// save the related options
583
+			// trash removed options, save old ones
584
+			// get list of all options
585
+			$options = $question->options();
586
+			if (! empty($options)) {
587
+				foreach ($options as $option_ID => $option) {
588
+					$option_req_index = $this->_get_option_req_data_index($option_ID);
589
+					if ($option_req_index !== false) {
590
+						$option->save($this->_req_data['question_options'][ $option_req_index ]);
591
+					} else {
592
+						// not found, remove it
593
+						$option->delete();
594
+					}
595
+				}
596
+			}
597
+			// save new related options
598
+			foreach ($this->_req_data['question_options'] as $index => $option_req_data) {
599
+				// skip $index that is from our sample
600
+				if ($index === 'xxcountxx') {
601
+					continue;
602
+				}
603
+				// note we allow saving blank options.
604
+				if (empty($option_req_data['QSO_ID'])) {
605
+					// no ID! save it!
606
+					$new_option = EE_Question_Option::new_instance(
607
+						[
608
+							'QSO_value' => $option_req_data['QSO_value'],
609
+							'QSO_desc'  => $option_req_data['QSO_desc'],
610
+							'QSO_order' => $option_req_data['QSO_order'],
611
+							'QST_ID'    => $question->ID(),
612
+						]
613
+					);
614
+					$new_option->save();
615
+				}
616
+			}
617
+		}
618
+		$query_args = ['action' => 'edit_question', 'QST_ID' => $ID];
619
+		if ($success !== 0) {
620
+			$msg = $new_question
621
+				? sprintf(
622
+					esc_html__('The %s has been created', 'event_espresso'),
623
+					$this->_question_model->item_name()
624
+				)
625
+				: sprintf(
626
+					esc_html__('The %s has been updated', 'event_espresso'),
627
+					$this->_question_model->item_name()
628
+				);
629
+			EE_Error::add_success($msg);
630
+		}
631
+
632
+		$this->_redirect_after_action(false, '', $action_desc, $query_args, true);
633
+	}
634
+
635
+
636
+	/**
637
+	 * Upon saving a question, there should be an array of 'question_options'. This array is index numerically, but not
638
+	 * by ID
639
+	 * (this is done because new question options don't have an ID, but we may want to add multiple simultaneously).
640
+	 * So, this function gets the index in that request data array called question_options. Returns FALSE if not found.
641
+	 *
642
+	 * @param int $ID of the question option to find
643
+	 * @return int index in question_options array if successful, FALSE if unsuccessful
644
+	 */
645
+	protected function _get_option_req_data_index($ID)
646
+	{
647
+		$req_data_for_question_options = $this->_req_data['question_options'];
648
+		foreach ($req_data_for_question_options as $num => $option_data) {
649
+			if (array_key_exists('QSO_ID', $option_data) && (int) $option_data['QSO_ID'] === $ID) {
650
+				return $num;
651
+			}
652
+		}
653
+		return false;
654
+	}
655
+
656
+
657
+
658
+
659
+	/***********/
660
+	/* QUERIES */
661
+	/**
662
+	 * For internal use in getting all the query parameters
663
+	 * (because it's pretty well the same between question, question groups,
664
+	 * and for both when searching for trashed and untrashed ones)
665
+	 *
666
+	 * @param EEM_Base $model either EEM_Question or EEM_Question_Group
667
+	 * @param int      $per_page
668
+	 * @param int      $current_page
669
+	 * @return array model query params, @see
670
+	 *               https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
671
+	 */
672
+	protected function get_query_params($model, $per_page = 10, $current_page = 10)
673
+	{
674
+		$query_params             = [];
675
+		$offset                   = ($current_page - 1) * $per_page;
676
+		$query_params['limit']    = [$offset, $per_page];
677
+		$order                    =
678
+			(isset($this->_req_data['order']) && ! empty($this->_req_data['order']))
679
+				? $this->_req_data['order']
680
+				: 'ASC';
681
+		$orderby_field            =
682
+			$model instanceof EEM_Question
683
+				? 'QST_ID'
684
+				: 'QSG_order';
685
+		$field_to_order_by        =
686
+			empty($this->_req_data['orderby'])
687
+				? $orderby_field
688
+				: $this->_req_data['orderby'];
689
+		$query_params['order_by'] = [$field_to_order_by => $order];
690
+		$search_string            =
691
+			array_key_exists('s', $this->_req_data)
692
+				? $this->_req_data['s']
693
+				: null;
694
+		if (! empty($search_string)) {
695
+			if ($model instanceof EEM_Question_Group) {
696
+				$query_params[0] = [
697
+					'OR' => [
698
+						'QSG_name' => ['LIKE', "%$search_string%"],
699
+						'QSG_desc' => ['LIKE', "%$search_string%"],
700
+					],
701
+				];
702
+			} else {
703
+				$query_params[0] = [
704
+					'QST_display_text' => ['LIKE', "%$search_string%"],
705
+				];
706
+			}
707
+		}
708
+
709
+		// capability checks (just leaving this commented out for reference because it illustrates some complicated query params that could be useful when fully implemented)
710
+		/*if ( $model instanceof EEM_Question_Group ) {
711 711
             if ( ! EE_Registry::instance()->CAP->current_user_can( 'edit_others_question_groups', 'espresso_registration_form_edit_question_group' ) ) {
712 712
                 $query_params[0] = array(
713 713
                     'AND' => array(
@@ -737,67 +737,67 @@  discard block
 block discarded – undo
737 737
             }
738 738
         }/**/
739 739
 
740
-        return $query_params;
741
-    }
742
-
743
-
744
-    /**
745
-     * @param int        $per_page
746
-     * @param int        $current_page
747
-     * @param bool|false $count
748
-     * @return EE_Base_Class[]|EE_Question_Group[]|EE_Soft_Delete_Base_Class[]|int
749
-     * @throws EE_Error
750
-     */
751
-    public function get_questions($per_page = 10, $current_page = 1, $count = false)
752
-    {
753
-        $QST          = EEM_Question::instance();
754
-        $query_params = $this->get_query_params($QST, $per_page, $current_page);
755
-        if ($count) {
756
-            $where   =
757
-                isset($query_params[0])
758
-                    ? [$query_params[0]]
759
-                    : [];
760
-            $results = $QST->count($where);
761
-        } else {
762
-            $results = $QST->get_all($query_params);
763
-        }
764
-        return $results;
765
-    }
766
-
767
-
768
-    /**
769
-     * @param            $per_page
770
-     * @param int        $current_page
771
-     * @param bool|false $count
772
-     * @return EE_Soft_Delete_Base_Class[]|int
773
-     * @throws EE_Error
774
-     */
775
-    public function get_trashed_questions($per_page, $current_page = 1, $count = false)
776
-    {
777
-        $query_params = $this->get_query_params(EEM_Question::instance(), $per_page, $current_page);
778
-        $where        =
779
-            isset($query_params[0])
780
-                ? [$query_params[0]]
781
-                : [];
782
-        return $count
783
-            ? EEM_Question::instance()->count_deleted($where)
784
-            : EEM_Question::instance()->get_all_deleted($query_params);
785
-    }
786
-
787
-
788
-    /**
789
-     * @param            $per_page
790
-     * @param int        $current_page
791
-     * @param bool|false $count
792
-     * @return EE_Base_Class[]|EE_Question_Group[]|EE_Soft_Delete_Base_Class[]
793
-     * @throws EE_Error
794
-     */
795
-    public function get_question_groups($per_page, $current_page = 1, $count = false)
796
-    {
797
-        $questionGroupModel = EEM_Question_Group::instance();
798
-        // note: this a subclass of EEM_Soft_Delete_Base, so this is actually only getting non-trashed items
799
-        return $questionGroupModel->get_all(
800
-            $this->get_query_params($questionGroupModel, $per_page, $current_page)
801
-        );
802
-    }
740
+		return $query_params;
741
+	}
742
+
743
+
744
+	/**
745
+	 * @param int        $per_page
746
+	 * @param int        $current_page
747
+	 * @param bool|false $count
748
+	 * @return EE_Base_Class[]|EE_Question_Group[]|EE_Soft_Delete_Base_Class[]|int
749
+	 * @throws EE_Error
750
+	 */
751
+	public function get_questions($per_page = 10, $current_page = 1, $count = false)
752
+	{
753
+		$QST          = EEM_Question::instance();
754
+		$query_params = $this->get_query_params($QST, $per_page, $current_page);
755
+		if ($count) {
756
+			$where   =
757
+				isset($query_params[0])
758
+					? [$query_params[0]]
759
+					: [];
760
+			$results = $QST->count($where);
761
+		} else {
762
+			$results = $QST->get_all($query_params);
763
+		}
764
+		return $results;
765
+	}
766
+
767
+
768
+	/**
769
+	 * @param            $per_page
770
+	 * @param int        $current_page
771
+	 * @param bool|false $count
772
+	 * @return EE_Soft_Delete_Base_Class[]|int
773
+	 * @throws EE_Error
774
+	 */
775
+	public function get_trashed_questions($per_page, $current_page = 1, $count = false)
776
+	{
777
+		$query_params = $this->get_query_params(EEM_Question::instance(), $per_page, $current_page);
778
+		$where        =
779
+			isset($query_params[0])
780
+				? [$query_params[0]]
781
+				: [];
782
+		return $count
783
+			? EEM_Question::instance()->count_deleted($where)
784
+			: EEM_Question::instance()->get_all_deleted($query_params);
785
+	}
786
+
787
+
788
+	/**
789
+	 * @param            $per_page
790
+	 * @param int        $current_page
791
+	 * @param bool|false $count
792
+	 * @return EE_Base_Class[]|EE_Question_Group[]|EE_Soft_Delete_Base_Class[]
793
+	 * @throws EE_Error
794
+	 */
795
+	public function get_question_groups($per_page, $current_page = 1, $count = false)
796
+	{
797
+		$questionGroupModel = EEM_Question_Group::instance();
798
+		// note: this a subclass of EEM_Soft_Delete_Base, so this is actually only getting non-trashed items
799
+		return $questionGroupModel->get_all(
800
+			$this->get_query_params($questionGroupModel, $per_page, $current_page)
801
+		);
802
+	}
803 803
 }
Please login to merge, or discard this patch.
admin_pages/events/Events_Admin_Page.core.php 2 patches
Indentation   +2916 added lines, -2916 removed lines patch added patch discarded remove patch
@@ -16,2923 +16,2923 @@
 block discarded – undo
16 16
  */
17 17
 class Events_Admin_Page extends EE_Admin_Page_CPT
18 18
 {
19
-    /**
20
-     * This will hold the event object for event_details screen.
19
+	/**
20
+	 * This will hold the event object for event_details screen.
21
+	 *
22
+	 * @var EE_Event $_event
23
+	 */
24
+	protected $_event;
25
+
26
+
27
+	/**
28
+	 * This will hold the category object for category_details screen.
29
+	 *
30
+	 * @var stdClass $_category
31
+	 */
32
+	protected $_category;
33
+
34
+
35
+	/**
36
+	 * This will hold the event model instance
37
+	 *
38
+	 * @var EEM_Event $_event_model
39
+	 */
40
+	protected $_event_model;
41
+
42
+
43
+	/**
44
+	 * @var EE_Event
45
+	 */
46
+	protected $_cpt_model_obj = false;
47
+
48
+
49
+	/**
50
+	 * @var NodeGroupDao
51
+	 */
52
+	protected $model_obj_node_group_persister;
53
+
54
+	/**
55
+	 * @var AdvancedEditorAdminFormSection
56
+	 */
57
+	protected $advanced_editor_admin_form;
58
+
59
+
60
+	/**
61
+	 * Initialize page props for this admin page group.
62
+	 */
63
+	protected function _init_page_props()
64
+	{
65
+		$this->page_slug        = EVENTS_PG_SLUG;
66
+		$this->page_label       = EVENTS_LABEL;
67
+		$this->_admin_base_url  = EVENTS_ADMIN_URL;
68
+		$this->_admin_base_path = EVENTS_ADMIN;
69
+		$this->_cpt_model_names = [
70
+			'create_new' => 'EEM_Event',
71
+			'edit'       => 'EEM_Event',
72
+		];
73
+		$this->_cpt_edit_routes = [
74
+			'espresso_events' => 'edit',
75
+		];
76
+		add_action(
77
+			'AHEE__EE_Admin_Page_CPT__set_model_object__after_set_object',
78
+			[$this, 'verify_event_edit'],
79
+			10,
80
+			2
81
+		);
82
+	}
83
+
84
+
85
+	/**
86
+	 * Sets the ajax hooks used for this admin page group.
87
+	 */
88
+	protected function _ajax_hooks()
89
+	{
90
+		add_action('wp_ajax_ee_save_timezone_setting', [$this, 'saveTimezoneString']);
91
+	}
92
+
93
+
94
+	/**
95
+	 * Sets the page properties for this admin page group.
96
+	 */
97
+	protected function _define_page_props()
98
+	{
99
+		$this->_admin_page_title = EVENTS_LABEL;
100
+		$this->_labels           = [
101
+			'buttons'      => [
102
+				'add'             => esc_html__('Add New Event', 'event_espresso'),
103
+				'edit'            => esc_html__('Edit Event', 'event_espresso'),
104
+				'delete'          => esc_html__('Delete Event', 'event_espresso'),
105
+				'add_category'    => esc_html__('Add New Category', 'event_espresso'),
106
+				'edit_category'   => esc_html__('Edit Category', 'event_espresso'),
107
+				'delete_category' => esc_html__('Delete Category', 'event_espresso'),
108
+			],
109
+			'editor_title' => [
110
+				'espresso_events' => esc_html__('Enter event title here', 'event_espresso'),
111
+			],
112
+			'publishbox'   => [
113
+				'create_new'        => esc_html__('Save New Event', 'event_espresso'),
114
+				'edit'              => esc_html__('Update Event', 'event_espresso'),
115
+				'add_category'      => esc_html__('Save New Category', 'event_espresso'),
116
+				'edit_category'     => esc_html__('Update Category', 'event_espresso'),
117
+				'template_settings' => esc_html__('Update Settings', 'event_espresso'),
118
+			],
119
+		];
120
+	}
121
+
122
+
123
+	/**
124
+	 * Sets the page routes property for this admin page group.
125
+	 */
126
+	protected function _set_page_routes()
127
+	{
128
+		// load formatter helper
129
+		// load field generator helper
130
+		// is there a evt_id in the request?
131
+		$EVT_ID = $this->request->getRequestParam('EVT_ID', 0, 'int');
132
+		$EVT_ID = $this->request->getRequestParam('post', $EVT_ID, 'int');
133
+
134
+		$this->_page_routes = [
135
+			'default'                       => [
136
+				'func'       => '_events_overview_list_table',
137
+				'capability' => 'ee_read_events',
138
+			],
139
+			'create_new'                    => [
140
+				'func'       => '_create_new_cpt_item',
141
+				'capability' => 'ee_edit_events',
142
+			],
143
+			'edit'                          => [
144
+				'func'       => '_edit_cpt_item',
145
+				'capability' => 'ee_edit_event',
146
+				'obj_id'     => $EVT_ID,
147
+			],
148
+			'copy_event'                    => [
149
+				'func'       => '_copy_events',
150
+				'capability' => 'ee_edit_event',
151
+				'obj_id'     => $EVT_ID,
152
+				'noheader'   => true,
153
+			],
154
+			'trash_event'                   => [
155
+				'func'       => '_trash_or_restore_event',
156
+				'args'       => ['event_status' => 'trash'],
157
+				'capability' => 'ee_delete_event',
158
+				'obj_id'     => $EVT_ID,
159
+				'noheader'   => true,
160
+			],
161
+			'trash_events'                  => [
162
+				'func'       => '_trash_or_restore_events',
163
+				'args'       => ['event_status' => 'trash'],
164
+				'capability' => 'ee_delete_events',
165
+				'noheader'   => true,
166
+			],
167
+			'restore_event'                 => [
168
+				'func'       => '_trash_or_restore_event',
169
+				'args'       => ['event_status' => 'draft'],
170
+				'capability' => 'ee_delete_event',
171
+				'obj_id'     => $EVT_ID,
172
+				'noheader'   => true,
173
+			],
174
+			'restore_events'                => [
175
+				'func'       => '_trash_or_restore_events',
176
+				'args'       => ['event_status' => 'draft'],
177
+				'capability' => 'ee_delete_events',
178
+				'noheader'   => true,
179
+			],
180
+			'delete_event'                  => [
181
+				'func'       => '_delete_event',
182
+				'capability' => 'ee_delete_event',
183
+				'obj_id'     => $EVT_ID,
184
+				'noheader'   => true,
185
+			],
186
+			'delete_events'                 => [
187
+				'func'       => '_delete_events',
188
+				'capability' => 'ee_delete_events',
189
+				'noheader'   => true,
190
+			],
191
+			'view_report'                   => [
192
+				'func'       => '_view_report',
193
+				'capability' => 'ee_edit_events',
194
+			],
195
+			'default_event_settings'        => [
196
+				'func'       => '_default_event_settings',
197
+				'capability' => 'manage_options',
198
+			],
199
+			'update_default_event_settings' => [
200
+				'func'       => '_update_default_event_settings',
201
+				'capability' => 'manage_options',
202
+				'noheader'   => true,
203
+			],
204
+			'template_settings'             => [
205
+				'func'       => '_template_settings',
206
+				'capability' => 'manage_options',
207
+			],
208
+			// event category tab related
209
+			'add_category'                  => [
210
+				'func'       => '_category_details',
211
+				'capability' => 'ee_edit_event_category',
212
+				'args'       => ['add'],
213
+			],
214
+			'edit_category'                 => [
215
+				'func'       => '_category_details',
216
+				'capability' => 'ee_edit_event_category',
217
+				'args'       => ['edit'],
218
+			],
219
+			'delete_categories'             => [
220
+				'func'       => '_delete_categories',
221
+				'capability' => 'ee_delete_event_category',
222
+				'noheader'   => true,
223
+			],
224
+			'delete_category'               => [
225
+				'func'       => '_delete_categories',
226
+				'capability' => 'ee_delete_event_category',
227
+				'noheader'   => true,
228
+			],
229
+			'insert_category'               => [
230
+				'func'       => '_insert_or_update_category',
231
+				'args'       => ['new_category' => true],
232
+				'capability' => 'ee_edit_event_category',
233
+				'noheader'   => true,
234
+			],
235
+			'update_category'               => [
236
+				'func'       => '_insert_or_update_category',
237
+				'args'       => ['new_category' => false],
238
+				'capability' => 'ee_edit_event_category',
239
+				'noheader'   => true,
240
+			],
241
+			'category_list'                 => [
242
+				'func'       => '_category_list_table',
243
+				'capability' => 'ee_manage_event_categories',
244
+			],
245
+			'preview_deletion'              => [
246
+				'func'       => 'previewDeletion',
247
+				'capability' => 'ee_delete_events',
248
+			],
249
+			'confirm_deletion'              => [
250
+				'func'       => 'confirmDeletion',
251
+				'capability' => 'ee_delete_events',
252
+				'noheader'   => true,
253
+			],
254
+		];
255
+	}
256
+
257
+
258
+	/**
259
+	 * Set the _page_config property for this admin page group.
260
+	 */
261
+	protected function _set_page_config()
262
+	{
263
+		$post_id            = $this->request->getRequestParam('post', 0, 'int');
264
+		$EVT_CAT_ID         = $this->request->getRequestParam('EVT_CAT_ID', 0, 'int');
265
+		$this->_page_config = [
266
+			'default'                => [
267
+				'nav'           => [
268
+					'label' => esc_html__('Overview', 'event_espresso'),
269
+					'icon' => 'dashicons-list-view',
270
+					'order' => 10,
271
+				],
272
+				'list_table'    => 'Events_Admin_List_Table',
273
+				'help_tabs'     => [
274
+					'events_overview_help_tab'                       => [
275
+						'title'    => esc_html__('Events Overview', 'event_espresso'),
276
+						'filename' => 'events_overview',
277
+					],
278
+					'events_overview_table_column_headings_help_tab' => [
279
+						'title'    => esc_html__('Events Overview Table Column Headings', 'event_espresso'),
280
+						'filename' => 'events_overview_table_column_headings',
281
+					],
282
+					'events_overview_filters_help_tab'               => [
283
+						'title'    => esc_html__('Events Overview Filters', 'event_espresso'),
284
+						'filename' => 'events_overview_filters',
285
+					],
286
+					'events_overview_view_help_tab'                  => [
287
+						'title'    => esc_html__('Events Overview Views', 'event_espresso'),
288
+						'filename' => 'events_overview_views',
289
+					],
290
+					'events_overview_other_help_tab'                 => [
291
+						'title'    => esc_html__('Events Overview Other', 'event_espresso'),
292
+						'filename' => 'events_overview_other',
293
+					],
294
+				],
295
+				'require_nonce' => false,
296
+			],
297
+			'create_new'             => [
298
+				'nav'           => [
299
+					'label'      => esc_html__('Add New Event', 'event_espresso'),
300
+					'icon' => 'dashicons-plus-alt',
301
+					'order'      => 5,
302
+					'persistent' => false,
303
+				],
304
+				'metaboxes'     => ['_register_event_editor_meta_boxes'],
305
+				'help_tabs'     => [
306
+					'event_editor_help_tab'                            => [
307
+						'title'    => esc_html__('Event Editor', 'event_espresso'),
308
+						'filename' => 'event_editor',
309
+					],
310
+					'event_editor_title_richtexteditor_help_tab'       => [
311
+						'title'    => esc_html__('Event Title & Rich Text Editor', 'event_espresso'),
312
+						'filename' => 'event_editor_title_richtexteditor',
313
+					],
314
+					'event_editor_venue_details_help_tab'              => [
315
+						'title'    => esc_html__('Event Venue Details', 'event_espresso'),
316
+						'filename' => 'event_editor_venue_details',
317
+					],
318
+					'event_editor_event_datetimes_help_tab'            => [
319
+						'title'    => esc_html__('Event Datetimes', 'event_espresso'),
320
+						'filename' => 'event_editor_event_datetimes',
321
+					],
322
+					'event_editor_event_tickets_help_tab'              => [
323
+						'title'    => esc_html__('Event Tickets', 'event_espresso'),
324
+						'filename' => 'event_editor_event_tickets',
325
+					],
326
+					'event_editor_event_registration_options_help_tab' => [
327
+						'title'    => esc_html__('Event Registration Options', 'event_espresso'),
328
+						'filename' => 'event_editor_event_registration_options',
329
+					],
330
+					'event_editor_tags_categories_help_tab'            => [
331
+						'title'    => esc_html__('Event Tags & Categories', 'event_espresso'),
332
+						'filename' => 'event_editor_tags_categories',
333
+					],
334
+					'event_editor_questions_registrants_help_tab'      => [
335
+						'title'    => esc_html__('Questions for Registrants', 'event_espresso'),
336
+						'filename' => 'event_editor_questions_registrants',
337
+					],
338
+					'event_editor_save_new_event_help_tab'             => [
339
+						'title'    => esc_html__('Save New Event', 'event_espresso'),
340
+						'filename' => 'event_editor_save_new_event',
341
+					],
342
+					'event_editor_other_help_tab'                      => [
343
+						'title'    => esc_html__('Event Other', 'event_espresso'),
344
+						'filename' => 'event_editor_other',
345
+					],
346
+				],
347
+				'qtips'         => ['EE_Event_Editor_Decaf_Tips'],
348
+				'require_nonce' => false,
349
+			],
350
+			'edit'                   => [
351
+				'nav'           => [
352
+					'label'      => esc_html__('Edit Event', 'event_espresso'),
353
+					'icon' => 'dashicons-edit',
354
+					'order'      => 5,
355
+					'persistent' => false,
356
+					'url'        => $post_id
357
+						? EE_Admin_Page::add_query_args_and_nonce(
358
+							['post' => $post_id, 'action' => 'edit'],
359
+							$this->_current_page_view_url
360
+						)
361
+						: $this->_admin_base_url,
362
+				],
363
+				'metaboxes'     => ['_register_event_editor_meta_boxes'],
364
+				'help_tabs'     => [
365
+					'event_editor_help_tab'                            => [
366
+						'title'    => esc_html__('Event Editor', 'event_espresso'),
367
+						'filename' => 'event_editor',
368
+					],
369
+					'event_editor_title_richtexteditor_help_tab'       => [
370
+						'title'    => esc_html__('Event Title & Rich Text Editor', 'event_espresso'),
371
+						'filename' => 'event_editor_title_richtexteditor',
372
+					],
373
+					'event_editor_venue_details_help_tab'              => [
374
+						'title'    => esc_html__('Event Venue Details', 'event_espresso'),
375
+						'filename' => 'event_editor_venue_details',
376
+					],
377
+					'event_editor_event_datetimes_help_tab'            => [
378
+						'title'    => esc_html__('Event Datetimes', 'event_espresso'),
379
+						'filename' => 'event_editor_event_datetimes',
380
+					],
381
+					'event_editor_event_tickets_help_tab'              => [
382
+						'title'    => esc_html__('Event Tickets', 'event_espresso'),
383
+						'filename' => 'event_editor_event_tickets',
384
+					],
385
+					'event_editor_event_registration_options_help_tab' => [
386
+						'title'    => esc_html__('Event Registration Options', 'event_espresso'),
387
+						'filename' => 'event_editor_event_registration_options',
388
+					],
389
+					'event_editor_tags_categories_help_tab'            => [
390
+						'title'    => esc_html__('Event Tags & Categories', 'event_espresso'),
391
+						'filename' => 'event_editor_tags_categories',
392
+					],
393
+					'event_editor_questions_registrants_help_tab'      => [
394
+						'title'    => esc_html__('Questions for Registrants', 'event_espresso'),
395
+						'filename' => 'event_editor_questions_registrants',
396
+					],
397
+					'event_editor_save_new_event_help_tab'             => [
398
+						'title'    => esc_html__('Save New Event', 'event_espresso'),
399
+						'filename' => 'event_editor_save_new_event',
400
+					],
401
+					'event_editor_other_help_tab'                      => [
402
+						'title'    => esc_html__('Event Other', 'event_espresso'),
403
+						'filename' => 'event_editor_other',
404
+					],
405
+				],
406
+				'require_nonce' => false,
407
+			],
408
+			'default_event_settings' => [
409
+				'nav'           => [
410
+					'label' => esc_html__('Default Settings', 'event_espresso'),
411
+					'icon' => 'dashicons-admin-generic',
412
+					'order' => 40,
413
+				],
414
+				'metaboxes'     => array_merge(['_publish_post_box'], $this->_default_espresso_metaboxes),
415
+				'labels'        => [
416
+					'publishbox' => esc_html__('Update Settings', 'event_espresso'),
417
+				],
418
+				'help_tabs'     => [
419
+					'default_settings_help_tab'        => [
420
+						'title'    => esc_html__('Default Event Settings', 'event_espresso'),
421
+						'filename' => 'events_default_settings',
422
+					],
423
+					'default_settings_status_help_tab' => [
424
+						'title'    => esc_html__('Default Registration Status', 'event_espresso'),
425
+						'filename' => 'events_default_settings_status',
426
+					],
427
+					'default_maximum_tickets_help_tab' => [
428
+						'title'    => esc_html__('Default Maximum Tickets Per Order', 'event_espresso'),
429
+						'filename' => 'events_default_settings_max_tickets',
430
+					],
431
+				],
432
+				'require_nonce' => false,
433
+			],
434
+			// template settings
435
+			'template_settings'      => [
436
+				'nav'           => [
437
+					'label' => esc_html__( 'Templates', 'event_espresso'),
438
+					'icon' => 'dashicons-layout',
439
+					'order' => 30,
440
+				],
441
+				'metaboxes'     => $this->_default_espresso_metaboxes,
442
+				'help_tabs'     => [
443
+					'general_settings_templates_help_tab' => [
444
+						'title'    => esc_html__('Templates', 'event_espresso'),
445
+						'filename' => 'general_settings_templates',
446
+					],
447
+				],
448
+				'require_nonce' => false,
449
+			],
450
+			// event category stuff
451
+			'add_category'           => [
452
+				'nav'           => [
453
+					'label'      => esc_html__('Add Category', 'event_espresso'),
454
+					'icon' => 'dashicons-plus-alt',
455
+					'order'      => 25,
456
+					'persistent' => false,
457
+				],
458
+				'help_tabs'     => [
459
+					'add_category_help_tab' => [
460
+						'title'    => esc_html__('Add New Event Category', 'event_espresso'),
461
+						'filename' => 'events_add_category',
462
+					],
463
+				],
464
+				'metaboxes'     => ['_publish_post_box'],
465
+				'require_nonce' => false,
466
+			],
467
+			'edit_category'          => [
468
+				'nav'           => [
469
+					'label'      => esc_html__('Edit Category', 'event_espresso'),
470
+					'icon' => 'dashicons-edit',
471
+					'order'      => 25,
472
+					'persistent' => false,
473
+					'url'        => $EVT_CAT_ID
474
+						? add_query_arg(
475
+							['EVT_CAT_ID' => $EVT_CAT_ID],
476
+							$this->_current_page_view_url
477
+						)
478
+						: $this->_admin_base_url,
479
+				],
480
+				'help_tabs'     => [
481
+					'edit_category_help_tab' => [
482
+						'title'    => esc_html__('Edit Event Category', 'event_espresso'),
483
+						'filename' => 'events_edit_category',
484
+					],
485
+				],
486
+				'metaboxes'     => ['_publish_post_box'],
487
+				'require_nonce' => false,
488
+			],
489
+			'category_list'          => [
490
+				'nav'           => [
491
+					'label' => esc_html__('Categories', 'event_espresso'),
492
+					'icon' => 'dashicons-networking',
493
+					'order' => 20,
494
+				],
495
+				'list_table'    => 'Event_Categories_Admin_List_Table',
496
+				'help_tabs'     => [
497
+					'events_categories_help_tab'                       => [
498
+						'title'    => esc_html__('Event Categories', 'event_espresso'),
499
+						'filename' => 'events_categories',
500
+					],
501
+					'events_categories_table_column_headings_help_tab' => [
502
+						'title'    => esc_html__('Event Categories Table Column Headings', 'event_espresso'),
503
+						'filename' => 'events_categories_table_column_headings',
504
+					],
505
+					'events_categories_view_help_tab'                  => [
506
+						'title'    => esc_html__('Event Categories Views', 'event_espresso'),
507
+						'filename' => 'events_categories_views',
508
+					],
509
+					'events_categories_other_help_tab'                 => [
510
+						'title'    => esc_html__('Event Categories Other', 'event_espresso'),
511
+						'filename' => 'events_categories_other',
512
+					],
513
+				],
514
+				'metaboxes'     => $this->_default_espresso_metaboxes,
515
+				'require_nonce' => false,
516
+			],
517
+			'preview_deletion'       => [
518
+				'nav'           => [
519
+					'label'      => esc_html__('Preview Deletion', 'event_espresso'),
520
+					'icon' => 'dashicons-remove',
521
+					'order'      => 15,
522
+					'persistent' => false,
523
+					'url'        => '',
524
+				],
525
+				'require_nonce' => false,
526
+			],
527
+		];
528
+	}
529
+
530
+
531
+	/**
532
+	 * Used to register any global screen options if necessary for every route in this admin page group.
533
+	 */
534
+	protected function _add_screen_options()
535
+	{
536
+	}
537
+
538
+
539
+	/**
540
+	 * Implementing the screen options for the 'default' route.
541
+	 *
542
+	 * @throws InvalidArgumentException
543
+	 * @throws InvalidDataTypeException
544
+	 * @throws InvalidInterfaceException
545
+	 */
546
+	protected function _add_screen_options_default()
547
+	{
548
+		$this->_per_page_screen_option();
549
+	}
550
+
551
+
552
+	/**
553
+	 * Implementing screen options for the category list route.
554
+	 *
555
+	 * @throws InvalidArgumentException
556
+	 * @throws InvalidDataTypeException
557
+	 * @throws InvalidInterfaceException
558
+	 */
559
+	protected function _add_screen_options_category_list()
560
+	{
561
+		$page_title              = $this->_admin_page_title;
562
+		$this->_admin_page_title = esc_html__('Categories', 'event_espresso');
563
+		$this->_per_page_screen_option();
564
+		$this->_admin_page_title = $page_title;
565
+	}
566
+
567
+
568
+	/**
569
+	 * Used to register any global feature pointers for the admin page group.
570
+	 */
571
+	protected function _add_feature_pointers()
572
+	{
573
+	}
574
+
575
+
576
+	/**
577
+	 * Registers and enqueues any global scripts and styles for the entire admin page group.
578
+	 */
579
+	public function load_scripts_styles()
580
+	{
581
+		wp_register_style(
582
+			'events-admin-css',
583
+			EVENTS_ASSETS_URL . 'events-admin-page.css',
584
+			[],
585
+			EVENT_ESPRESSO_VERSION
586
+		);
587
+		wp_register_style(
588
+			'ee-cat-admin',
589
+			EVENTS_ASSETS_URL . 'ee-cat-admin.css',
590
+			[],
591
+			EVENT_ESPRESSO_VERSION
592
+		);
593
+		wp_enqueue_style('events-admin-css');
594
+		wp_enqueue_style('ee-cat-admin');
595
+		// scripts
596
+		wp_register_script(
597
+			'event_editor_js',
598
+			EVENTS_ASSETS_URL . 'event_editor.js',
599
+			['ee_admin_js', 'jquery-ui-slider', 'jquery-ui-timepicker-addon'],
600
+			EVENT_ESPRESSO_VERSION,
601
+			true
602
+		);
603
+	}
604
+
605
+
606
+	/**
607
+	 * Enqueuing scripts and styles specific to this view
608
+	 */
609
+	public function load_scripts_styles_create_new()
610
+	{
611
+		$this->load_scripts_styles_edit();
612
+	}
613
+
614
+
615
+	/**
616
+	 * Enqueuing scripts and styles specific to this view
617
+	 */
618
+	public function load_scripts_styles_edit()
619
+	{
620
+		// styles
621
+		wp_enqueue_style('espresso-ui-theme');
622
+		wp_register_style(
623
+			'event-editor-css',
624
+			EVENTS_ASSETS_URL . 'event-editor.css',
625
+			['ee-admin-css'],
626
+			EVENT_ESPRESSO_VERSION
627
+		);
628
+		wp_enqueue_style('event-editor-css');
629
+		// scripts
630
+		if (! $this->admin_config->useAdvancedEditor()) {
631
+			wp_register_script(
632
+				'event-datetime-metabox',
633
+				EVENTS_ASSETS_URL . 'event-datetime-metabox.js',
634
+				['event_editor_js', 'ee-datepicker'],
635
+				EVENT_ESPRESSO_VERSION
636
+			);
637
+			wp_enqueue_script('event-datetime-metabox');
638
+		}
639
+	}
640
+
641
+
642
+	/**
643
+	 * Populating the _views property for the category list table view.
644
+	 */
645
+	protected function _set_list_table_views_category_list()
646
+	{
647
+		$this->_views = [
648
+			'all' => [
649
+				'slug'        => 'all',
650
+				'label'       => esc_html__('All', 'event_espresso'),
651
+				'count'       => 0,
652
+				'bulk_action' => [
653
+					'delete_categories' => esc_html__('Delete Permanently', 'event_espresso'),
654
+				],
655
+			],
656
+		];
657
+	}
658
+
659
+
660
+	/**
661
+	 * For adding anything that fires on the admin_init hook for any route within this admin page group.
662
+	 */
663
+	public function admin_init()
664
+	{
665
+		EE_Registry::$i18n_js_strings['image_confirm'] = esc_html__(
666
+			'Do you really want to delete this image? Please remember to update your event to complete the removal.',
667
+			'event_espresso'
668
+		);
669
+	}
670
+
671
+
672
+	/**
673
+	 * For adding anything that should be triggered on the admin_notices hook for any route within this admin page
674
+	 * group.
675
+	 */
676
+	public function admin_notices()
677
+	{
678
+	}
679
+
680
+
681
+	/**
682
+	 * For adding anything that should be triggered on the `admin_print_footer_scripts` hook for any route within
683
+	 * this admin page group.
684
+	 */
685
+	public function admin_footer_scripts()
686
+	{
687
+	}
688
+
689
+
690
+	/**
691
+	 * Call this function to verify if an event is public and has tickets for sale.  If it does, then we need to show a
692
+	 * warning (via EE_Error::add_error());
693
+	 *
694
+	 * @param EE_Event $event Event object
695
+	 * @param string   $req_type
696
+	 * @return void
697
+	 * @throws EE_Error
698
+	 * @throws ReflectionException
699
+	 */
700
+	public function verify_event_edit($event = null, $req_type = '')
701
+	{
702
+		// don't need to do this when processing
703
+		if (! empty($req_type)) {
704
+			return;
705
+		}
706
+		// no event?
707
+		if (! $event instanceof EE_Event) {
708
+			$event = $this->_cpt_model_obj;
709
+		}
710
+		// STILL no event?
711
+		if (! $event instanceof EE_Event) {
712
+			return;
713
+		}
714
+		$orig_status = $event->status();
715
+		// first check if event is active.
716
+		if (
717
+			$orig_status === EEM_Event::cancelled
718
+			|| $orig_status === EEM_Event::postponed
719
+			|| $event->is_expired()
720
+			|| $event->is_inactive()
721
+		) {
722
+			return;
723
+		}
724
+		// made it here so it IS active... next check that any of the tickets are sold.
725
+		if ($event->is_sold_out(true)) {
726
+			if ($orig_status !== EEM_Event::sold_out && $event->status() !== $orig_status) {
727
+				EE_Error::add_attention(
728
+					sprintf(
729
+						esc_html__(
730
+							'Please note that the Event Status has automatically been changed to %s because there are no more spaces available for this event.  However, this change is not permanent until you update the event.  You can change the status back to something else before updating if you wish.',
731
+							'event_espresso'
732
+						),
733
+						EEH_Template::pretty_status(EEM_Event::sold_out, false, 'sentence')
734
+					)
735
+				);
736
+			}
737
+			return;
738
+		}
739
+		if ($orig_status === EEM_Event::sold_out) {
740
+			EE_Error::add_attention(
741
+				sprintf(
742
+					esc_html__(
743
+						'Please note that the Event Status has automatically been changed to %s because more spaces have become available for this event, most likely due to abandoned transactions freeing up reserved tickets.  However, this change is not permanent until you update the event. If you wish, you can change the status back to something else before updating.',
744
+						'event_espresso'
745
+					),
746
+					EEH_Template::pretty_status($event->status(), false, 'sentence')
747
+				)
748
+			);
749
+		}
750
+		// now we need to determine if the event has any tickets on sale.  If not then we dont' show the error
751
+		if (! $event->tickets_on_sale()) {
752
+			return;
753
+		}
754
+		// made it here so show warning
755
+		$this->_edit_event_warning();
756
+	}
757
+
758
+
759
+	/**
760
+	 * This is the text used for when an event is being edited that is public and has tickets for sale.
761
+	 * When needed, hook this into a EE_Error::add_error() notice.
762
+	 *
763
+	 * @access protected
764
+	 * @return void
765
+	 */
766
+	protected function _edit_event_warning()
767
+	{
768
+		// we don't want to add warnings during these requests
769
+		if ($this->request->getRequestParam('action') === 'editpost') {
770
+			return;
771
+		}
772
+		EE_Error::add_attention(
773
+			sprintf(
774
+				esc_html__(
775
+					'Your event is open for registration. Making changes may disrupt any transactions in progress. %sLearn more%s',
776
+					'event_espresso'
777
+				),
778
+				'<a class="espresso-help-tab-lnk ee-help-tab-link">',
779
+				'</a>'
780
+			)
781
+		);
782
+	}
783
+
784
+
785
+	/**
786
+	 * When a user is creating a new event, notify them if they haven't set their timezone.
787
+	 * Otherwise, do the normal logic
788
+	 *
789
+	 * @return void
790
+	 * @throws EE_Error
791
+	 * @throws InvalidArgumentException
792
+	 * @throws InvalidDataTypeException
793
+	 * @throws InvalidInterfaceException
794
+	 */
795
+	protected function _create_new_cpt_item()
796
+	{
797
+		$has_timezone_string = get_option('timezone_string');
798
+		// only nag them about setting their timezone if it's their first event, and they haven't already done it
799
+		if (! $has_timezone_string && ! EEM_Event::instance()->exists([])) {
800
+			EE_Error::add_attention(
801
+				sprintf(
802
+					esc_html__(
803
+						'Your website\'s timezone is currently set to a UTC offset. We recommend updating your timezone to a city or region near you before you create an event. Change your timezone now:%1$s%2$s%3$sChange Timezone%4$s',
804
+						'event_espresso'
805
+					),
806
+					'<br>',
807
+					'<select id="timezone_string" name="timezone_string" aria-describedby="timezone-description">'
808
+					. EEH_DTT_Helper::wp_timezone_choice('', EEH_DTT_Helper::get_user_locale())
809
+					. '</select>',
810
+					'<button class="button button--secondary timezone-submit">',
811
+					'</button><span class="spinner"></span>'
812
+				),
813
+				__FILE__,
814
+				__FUNCTION__,
815
+				__LINE__
816
+			);
817
+		}
818
+		parent::_create_new_cpt_item();
819
+	}
820
+
821
+
822
+	/**
823
+	 * Sets the _views property for the default route in this admin page group.
824
+	 */
825
+	protected function _set_list_table_views_default()
826
+	{
827
+		$this->_views = [
828
+			'all'   => [
829
+				'slug'        => 'all',
830
+				'label'       => esc_html__('View All Events', 'event_espresso'),
831
+				'count'       => 0,
832
+				'bulk_action' => [
833
+					'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
834
+				],
835
+			],
836
+			'draft' => [
837
+				'slug'        => 'draft',
838
+				'label'       => esc_html__('Draft', 'event_espresso'),
839
+				'count'       => 0,
840
+				'bulk_action' => [
841
+					'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
842
+				],
843
+			],
844
+		];
845
+		if (EE_Registry::instance()->CAP->current_user_can('ee_delete_events', 'espresso_events_trash_events')) {
846
+			$this->_views['trash'] = [
847
+				'slug'        => 'trash',
848
+				'label'       => esc_html__('Trash', 'event_espresso'),
849
+				'count'       => 0,
850
+				'bulk_action' => [
851
+					'restore_events' => esc_html__('Restore From Trash', 'event_espresso'),
852
+					'delete_events'  => esc_html__('Delete Permanently', 'event_espresso'),
853
+				],
854
+			];
855
+		}
856
+	}
857
+
858
+
859
+	/**
860
+	 * Provides the legend item array for the default list table view.
861
+	 *
862
+	 * @return array
863
+	 * @throws EE_Error
864
+	 * @throws EE_Error
865
+	 */
866
+	protected function _event_legend_items()
867
+	{
868
+		$items    = [
869
+			'view_details'   => [
870
+				'class' => 'dashicons dashicons-visibility',
871
+				'desc'  => esc_html__('View Event', 'event_espresso'),
872
+			],
873
+			'edit_event'     => [
874
+				'class' => 'dashicons dashicons-calendar-alt',
875
+				'desc'  => esc_html__('Edit Event Details', 'event_espresso'),
876
+			],
877
+			'view_attendees' => [
878
+				'class' => 'dashicons dashicons-groups',
879
+				'desc'  => esc_html__('View Registrations for Event', 'event_espresso'),
880
+			],
881
+		];
882
+		$items    = apply_filters('FHEE__Events_Admin_Page___event_legend_items__items', $items);
883
+		$statuses = [
884
+			'sold_out_status'  => [
885
+				'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::sold_out,
886
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::sold_out, false, 'sentence'),
887
+			],
888
+			'active_status'    => [
889
+				'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::active,
890
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::active, false, 'sentence'),
891
+			],
892
+			'upcoming_status'  => [
893
+				'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::upcoming,
894
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::upcoming, false, 'sentence'),
895
+			],
896
+			'postponed_status' => [
897
+				'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::postponed,
898
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::postponed, false, 'sentence'),
899
+			],
900
+			'cancelled_status' => [
901
+				'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::cancelled,
902
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::cancelled, false, 'sentence'),
903
+			],
904
+			'expired_status'   => [
905
+				'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::expired,
906
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::expired, false, 'sentence'),
907
+			],
908
+			'inactive_status'  => [
909
+				'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::inactive,
910
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::inactive, false, 'sentence'),
911
+			],
912
+		];
913
+		$statuses = apply_filters('FHEE__Events_Admin_Page__event_legend_items__statuses', $statuses);
914
+		return array_merge($items, $statuses);
915
+	}
916
+
917
+
918
+	/**
919
+	 * @return EEM_Event
920
+	 * @throws EE_Error
921
+	 * @throws InvalidArgumentException
922
+	 * @throws InvalidDataTypeException
923
+	 * @throws InvalidInterfaceException
924
+	 * @throws ReflectionException
925
+	 */
926
+	private function _event_model()
927
+	{
928
+		if (! $this->_event_model instanceof EEM_Event) {
929
+			$this->_event_model = EE_Registry::instance()->load_model('Event');
930
+		}
931
+		return $this->_event_model;
932
+	}
933
+
934
+
935
+	/**
936
+	 * Adds extra buttons to the WP CPT permalink field row.
937
+	 * Method is called from parent and is hooked into the wp 'get_sample_permalink_html' filter.
938
+	 *
939
+	 * @param string $return    the current html
940
+	 * @param int    $id        the post id for the page
941
+	 * @param string $new_title What the title is
942
+	 * @param string $new_slug  what the slug is
943
+	 * @return string            The new html string for the permalink area
944
+	 */
945
+	public function extra_permalink_field_buttons($return, $id, $new_title, $new_slug)
946
+	{
947
+		// make sure this is only when editing
948
+		if (! empty($id)) {
949
+			$post = get_post($id);
950
+			$return .= '<a class="button button--small button--secondary" onclick="prompt(\'Shortcode:\', jQuery(\'#shortcode\').val()); return false;" href="#"  tabindex="-1">'
951
+					   . esc_html__('Shortcode', 'event_espresso')
952
+					   . '</a> ';
953
+			$return .= '<input id="shortcode" type="hidden" value="[ESPRESSO_TICKET_SELECTOR event_id='
954
+					   . $post->ID
955
+					   . ']">';
956
+		}
957
+		return $return;
958
+	}
959
+
960
+
961
+	/**
962
+	 * _events_overview_list_table
963
+	 * This contains the logic for showing the events_overview list
964
+	 *
965
+	 * @access protected
966
+	 * @return void
967
+	 * @throws DomainException
968
+	 * @throws EE_Error
969
+	 * @throws InvalidArgumentException
970
+	 * @throws InvalidDataTypeException
971
+	 * @throws InvalidInterfaceException
972
+	 */
973
+	protected function _events_overview_list_table()
974
+	{
975
+		$after_list_table                           = [];
976
+		$links_html = EEH_HTML::div('', '', 'ee-admin-section ee-layout-stack');
977
+		$links_html .= EEH_HTML::h3(esc_html__('Links', 'event_espresso'));
978
+		$links_html .= EEH_HTML::div(
979
+			EEH_Template::get_button_or_link(
980
+				get_post_type_archive_link('espresso_events'),
981
+				esc_html__('View Event Archive Page', 'event_espresso'),
982
+				'button button--small button--secondary'
983
+			),
984
+			'',
985
+			'ee-admin-button-row ee-admin-button-row--align-start'
986
+		);
987
+		$links_html .= EEH_HTML::divx();
988
+
989
+		$after_list_table['view_event_list_button'] = $links_html;
990
+
991
+		$after_list_table['legend'] = $this->_display_legend($this->_event_legend_items());
992
+		$this->_admin_page_title                    .= ' ' . $this->get_action_link_or_button(
993
+			'create_new',
994
+			'add',
995
+			[],
996
+			'add-new-h2'
997
+		);
998
+
999
+		$this->_template_args['after_list_table']   = array_merge(
1000
+			(array) $this->_template_args['after_list_table'],
1001
+			$after_list_table
1002
+		);
1003
+		$this->display_admin_list_table_page_with_no_sidebar();
1004
+	}
1005
+
1006
+
1007
+	/**
1008
+	 * this allows for extra misc actions in the default WP publish box
1009
+	 *
1010
+	 * @return void
1011
+	 * @throws DomainException
1012
+	 * @throws EE_Error
1013
+	 * @throws InvalidArgumentException
1014
+	 * @throws InvalidDataTypeException
1015
+	 * @throws InvalidInterfaceException
1016
+	 * @throws ReflectionException
1017
+	 */
1018
+	public function extra_misc_actions_publish_box()
1019
+	{
1020
+		$this->_generate_publish_box_extra_content();
1021
+	}
1022
+
1023
+
1024
+	/**
1025
+	 * This is hooked into the WordPress do_action('save_post') hook and runs after the custom post type has been
1026
+	 * saved.
1027
+	 * Typically you would use this to save any additional data.
1028
+	 * Keep in mind also that "save_post" runs on EVERY post update to the database.
1029
+	 * ALSO very important.  When a post transitions from scheduled to published,
1030
+	 * the save_post action is fired but you will NOT have any _POST data containing any extra info you may have from
1031
+	 * other meta saves. So MAKE sure that you handle this accordingly.
1032
+	 *
1033
+	 * @access protected
1034
+	 * @abstract
1035
+	 * @param string $post_id The ID of the cpt that was saved (so you can link relationally)
1036
+	 * @param WP_Post $post    The post object of the cpt that was saved.
1037
+	 * @return void
1038
+	 * @throws EE_Error
1039
+	 * @throws InvalidArgumentException
1040
+	 * @throws InvalidDataTypeException
1041
+	 * @throws InvalidInterfaceException
1042
+	 * @throws ReflectionException
1043
+	 */
1044
+	protected function _insert_update_cpt_item($post_id, $post)
1045
+	{
1046
+		if ($post instanceof WP_Post && $post->post_type !== 'espresso_events') {
1047
+			// get out we're not processing an event save.
1048
+			return;
1049
+		}
1050
+		$event_values = [
1051
+			'EVT_member_only'     => $this->request->getRequestParam('member_only', false, 'bool'),
1052
+			'EVT_allow_overflow'  => $this->request->getRequestParam('EVT_allow_overflow', false, 'bool'),
1053
+			'EVT_timezone_string' => $this->request->getRequestParam('timezone_string'),
1054
+		];
1055
+		// check if the new EDTR reg options meta box is being used, and if so, don't run updates for legacy version
1056
+		if (! $this->admin_config->useAdvancedEditor() || ! $this->feature->allowed('use_reg_options_meta_box')) {
1057
+			$event_values['EVT_display_ticket_selector']     = $this->request->getRequestParam(
1058
+				'display_ticket_selector',
1059
+				false,
1060
+				'bool'
1061
+			);
1062
+			$event_values['EVT_additional_limit']            = min(
1063
+				apply_filters('FHEE__EE_Events_Admin__insert_update_cpt_item__EVT_additional_limit_max', 255),
1064
+				$this->request->getRequestParam('additional_limit', null, 'int')
1065
+			);
1066
+			$event_values['EVT_default_registration_status'] = $this->request->getRequestParam(
1067
+				'EVT_default_registration_status',
1068
+				EE_Registry::instance()->CFG->registration->default_STS_ID
1069
+			);
1070
+
1071
+			$event_values['EVT_external_URL'] = $this->request->getRequestParam('externalURL');
1072
+			$event_values['EVT_phone']        = $this->request->getRequestParam('event_phone');
1073
+			$event_values['EVT_display_desc'] = $this->request->getRequestParam('display_desc', false, 'bool');
1074
+		}
1075
+		// update event
1076
+		$success = $this->_event_model()->update_by_ID($event_values, $post_id);
1077
+		// get event_object for other metaboxes...
1078
+		// though it would seem to make sense to just use $this->_event_model()->get_one_by_ID( $post_id )..
1079
+		// i have to setup where conditions to override the filters in the model
1080
+		// that filter out autodraft and inherit statuses so we GET the inherit id!
1081
+		$event = $this->_event_model()->get_one(
1082
+			[
1083
+				[
1084
+					$this->_event_model()->primary_key_name() => $post_id,
1085
+					'OR'                                      => [
1086
+						'status'   => $post->post_status,
1087
+						// if trying to "Publish" a sold out event, it's status will get switched back to "sold_out" in the db,
1088
+						// but the returned object here has a status of "publish", so use the original post status as well
1089
+						'status*1' => $this->request->getRequestParam('original_post_status'),
1090
+					],
1091
+				],
1092
+			]
1093
+		);
1094
+
1095
+		// the following are default callbacks for event attachment updates
1096
+		// that can be overridden by caffeinated functionality and/or addons.
1097
+		$event_update_callbacks = [];
1098
+		if (! $this->admin_config->useAdvancedEditor()) {
1099
+			$event_update_callbacks['_default_venue_update']   = [$this, '_default_venue_update'];
1100
+			$event_update_callbacks['_default_tickets_update'] = [$this, '_default_tickets_update'];
1101
+		}
1102
+		$event_update_callbacks = apply_filters(
1103
+			'FHEE__Events_Admin_Page___insert_update_cpt_item__event_update_callbacks',
1104
+			$event_update_callbacks
1105
+		);
1106
+
1107
+		$att_success = true;
1108
+		foreach ($event_update_callbacks as $e_callback) {
1109
+			$_success = is_callable($e_callback)
1110
+				? $e_callback($event, $this->request->requestParams())
1111
+				: false;
1112
+			// if ANY of these updates fail then we want the appropriate global error message
1113
+			$att_success = $_success !== false ? $att_success : false;
1114
+		}
1115
+		// any errors?
1116
+		if ($success && $att_success === false) {
1117
+			EE_Error::add_error(
1118
+				esc_html__(
1119
+					'Event Details saved successfully but something went wrong with saving attachments.',
1120
+					'event_espresso'
1121
+				),
1122
+				__FILE__,
1123
+				__FUNCTION__,
1124
+				__LINE__
1125
+			);
1126
+		} elseif ($success === false) {
1127
+			EE_Error::add_error(
1128
+				esc_html__('Event Details did not save successfully.', 'event_espresso'),
1129
+				__FILE__,
1130
+				__FUNCTION__,
1131
+				__LINE__
1132
+			);
1133
+		}
1134
+	}
1135
+
1136
+
1137
+	/**
1138
+	 * @param int $post_id
1139
+	 * @param int $revision_id
1140
+	 * @throws EE_Error
1141
+	 * @throws EE_Error
1142
+	 * @throws ReflectionException
1143
+	 * @see parent::restore_item()
1144
+	 */
1145
+	protected function _restore_cpt_item($post_id, $revision_id)
1146
+	{
1147
+		// copy existing event meta to new post
1148
+		$post_evt = $this->_event_model()->get_one_by_ID($post_id);
1149
+		if ($post_evt instanceof EE_Event) {
1150
+			// meta revision restore
1151
+			$post_evt->restore_revision($revision_id);
1152
+			// related objs restore
1153
+			$post_evt->restore_revision($revision_id, ['Venue', 'Datetime', 'Price']);
1154
+		}
1155
+	}
1156
+
1157
+
1158
+	/**
1159
+	 * Attach the venue to the Event
1160
+	 *
1161
+	 * @param EE_Event $event Event Object to add the venue to
1162
+	 * @param array    $data  The request data from the form
1163
+	 * @return bool           Success or fail.
1164
+	 * @throws EE_Error
1165
+	 * @throws ReflectionException
1166
+	 */
1167
+	protected function _default_venue_update(EE_Event $event, $data)
1168
+	{
1169
+		require_once(EE_MODELS . 'EEM_Venue.model.php');
1170
+		$venue_model = EE_Registry::instance()->load_model('Venue');
1171
+		$venue_id    = ! empty($data['venue_id']) ? $data['venue_id'] : null;
1172
+		// very important.  If we don't have a venue name...
1173
+		// then we'll get out because not necessary to create empty venue
1174
+		if (empty($data['venue_title'])) {
1175
+			return false;
1176
+		}
1177
+		$venue_array = [
1178
+			'VNU_wp_user'         => $event->get('EVT_wp_user'),
1179
+			'VNU_name'            => ! empty($data['venue_title']) ? $data['venue_title'] : null,
1180
+			'VNU_desc'            => ! empty($data['venue_description']) ? $data['venue_description'] : null,
1181
+			'VNU_identifier'      => ! empty($data['venue_identifier']) ? $data['venue_identifier'] : null,
1182
+			'VNU_short_desc'      => ! empty($data['venue_short_description'])
1183
+				? $data['venue_short_description']
1184
+				: null,
1185
+			'VNU_address'         => ! empty($data['address']) ? $data['address'] : null,
1186
+			'VNU_address2'        => ! empty($data['address2']) ? $data['address2'] : null,
1187
+			'VNU_city'            => ! empty($data['city']) ? $data['city'] : null,
1188
+			'STA_ID'              => ! empty($data['state']) ? $data['state'] : null,
1189
+			'CNT_ISO'             => ! empty($data['countries']) ? $data['countries'] : null,
1190
+			'VNU_zip'             => ! empty($data['zip']) ? $data['zip'] : null,
1191
+			'VNU_phone'           => ! empty($data['venue_phone']) ? $data['venue_phone'] : null,
1192
+			'VNU_capacity'        => ! empty($data['venue_capacity']) ? $data['venue_capacity'] : null,
1193
+			'VNU_url'             => ! empty($data['venue_url']) ? $data['venue_url'] : null,
1194
+			'VNU_virtual_phone'   => ! empty($data['virtual_phone']) ? $data['virtual_phone'] : null,
1195
+			'VNU_virtual_url'     => ! empty($data['virtual_url']) ? $data['virtual_url'] : null,
1196
+			'VNU_enable_for_gmap' => isset($data['enable_for_gmap']) ? 1 : 0,
1197
+			'status'              => 'publish',
1198
+		];
1199
+		// if we've got the venue_id then we're just updating the existing venue so let's do that and then get out.
1200
+		if (! empty($venue_id)) {
1201
+			$update_where  = [$venue_model->primary_key_name() => $venue_id];
1202
+			$rows_affected = $venue_model->update($venue_array, [$update_where]);
1203
+			// we've gotta make sure that the venue is always attached to a revision..
1204
+			// add_relation_to should take care of making sure that the relation is already present.
1205
+			$event->_add_relation_to($venue_id, 'Venue');
1206
+			return $rows_affected > 0;
1207
+		}
1208
+		// we insert the venue
1209
+		$venue_id = $venue_model->insert($venue_array);
1210
+		$event->_add_relation_to($venue_id, 'Venue');
1211
+		return ! empty($venue_id);
1212
+		// when we have the ancestor come in it's already been handled by the revision save.
1213
+	}
1214
+
1215
+
1216
+	/**
1217
+	 * Handles saving everything related to Tickets (datetimes, tickets, prices)
1218
+	 *
1219
+	 * @param EE_Event $event The Event object we're attaching data to
1220
+	 * @param array    $data  The request data from the form
1221
+	 * @return array
1222
+	 * @throws EE_Error
1223
+	 * @throws ReflectionException
1224
+	 * @throws Exception
1225
+	 */
1226
+	protected function _default_tickets_update(EE_Event $event, $data)
1227
+	{
1228
+		if ($this->admin_config->useAdvancedEditor()) {
1229
+			return [];
1230
+		}
1231
+		$datetime       = null;
1232
+		$saved_tickets  = [];
1233
+		$event_timezone = $event->get_timezone();
1234
+		$date_formats   = ['Y-m-d', 'h:i a'];
1235
+		foreach ($data['edit_event_datetimes'] as $row => $datetime_data) {
1236
+			// trim all values to ensure any excess whitespace is removed.
1237
+			$datetime_data                = array_map('trim', $datetime_data);
1238
+			$datetime_data['DTT_EVT_end'] =
1239
+				isset($datetime_data['DTT_EVT_end']) && ! empty($datetime_data['DTT_EVT_end'])
1240
+					? $datetime_data['DTT_EVT_end']
1241
+					: $datetime_data['DTT_EVT_start'];
1242
+			$datetime_values              = [
1243
+				'DTT_ID'        => ! empty($datetime_data['DTT_ID']) ? $datetime_data['DTT_ID'] : null,
1244
+				'DTT_EVT_start' => $datetime_data['DTT_EVT_start'],
1245
+				'DTT_EVT_end'   => $datetime_data['DTT_EVT_end'],
1246
+				'DTT_reg_limit' => empty($datetime_data['DTT_reg_limit']) ? EE_INF : $datetime_data['DTT_reg_limit'],
1247
+				'DTT_order'     => $row,
1248
+			];
1249
+			// if we have an id then let's get existing object first and then set the new values.
1250
+			//  Otherwise we instantiate a new object for save.
1251
+			if (! empty($datetime_data['DTT_ID'])) {
1252
+				$datetime = EEM_Datetime::instance($event_timezone)->get_one_by_ID($datetime_data['DTT_ID']);
1253
+				if (! $datetime instanceof EE_Datetime) {
1254
+					throw new RuntimeException(
1255
+						sprintf(
1256
+							esc_html__(
1257
+								'Something went wrong! A valid Datetime could not be retrieved from the database using the supplied ID: %1$d',
1258
+								'event_espresso'
1259
+							),
1260
+							$datetime_data['DTT_ID']
1261
+						)
1262
+					);
1263
+				}
1264
+				$datetime->set_date_format($date_formats[0]);
1265
+				$datetime->set_time_format($date_formats[1]);
1266
+				foreach ($datetime_values as $field => $value) {
1267
+					$datetime->set($field, $value);
1268
+				}
1269
+			} else {
1270
+				$datetime = EE_Datetime::new_instance($datetime_values, $event_timezone, $date_formats);
1271
+			}
1272
+			if (! $datetime instanceof EE_Datetime) {
1273
+				throw new RuntimeException(
1274
+					sprintf(
1275
+						esc_html__(
1276
+							'Something went wrong! A valid Datetime could not be generated or retrieved using the supplied data: %1$s',
1277
+							'event_espresso'
1278
+						),
1279
+						print_r($datetime_values, true)
1280
+					)
1281
+				);
1282
+			}
1283
+			// before going any further make sure our dates are setup correctly
1284
+			// so that the end date is always equal or greater than the start date.
1285
+			if ($datetime->get_raw('DTT_EVT_start') > $datetime->get_raw('DTT_EVT_end')) {
1286
+				$datetime->set('DTT_EVT_end', $datetime->get('DTT_EVT_start'));
1287
+				$datetime = EEH_DTT_Helper::date_time_add($datetime, 'DTT_EVT_end', 'days');
1288
+			}
1289
+			$datetime->save();
1290
+			$event->_add_relation_to($datetime, 'Datetime');
1291
+		}
1292
+		// no datetimes get deleted so we don't do any of that logic here.
1293
+		// update tickets next
1294
+		$old_tickets = isset($data['ticket_IDs']) ? explode(',', $data['ticket_IDs']) : [];
1295
+
1296
+		// set up some default start and end dates in case those are not present in the incoming data
1297
+		$default_start_date = new DateTime('now', new DateTimeZone($event->get_timezone()));
1298
+		$default_start_date = $default_start_date->format($date_formats[0] . ' ' . $date_formats[1]);
1299
+		// use the start date of the first datetime for the end date
1300
+		$first_datetime   = $event->first_datetime();
1301
+		$default_end_date = $first_datetime->start_date_and_time($date_formats[0], $date_formats[1]);
1302
+
1303
+		// now process the incoming data
1304
+		foreach ($data['edit_tickets'] as $row => $ticket_data) {
1305
+			$update_prices = false;
1306
+			$ticket_price  = isset($data['edit_prices'][ $row ][1]['PRC_amount'])
1307
+				? $data['edit_prices'][ $row ][1]['PRC_amount']
1308
+				: 0;
1309
+			// trim inputs to ensure any excess whitespace is removed.
1310
+			$ticket_data   = array_map('trim', $ticket_data);
1311
+			$ticket_values = [
1312
+				'TKT_ID'          => ! empty($ticket_data['TKT_ID']) ? $ticket_data['TKT_ID'] : null,
1313
+				'TTM_ID'          => ! empty($ticket_data['TTM_ID']) ? $ticket_data['TTM_ID'] : 0,
1314
+				'TKT_name'        => ! empty($ticket_data['TKT_name']) ? $ticket_data['TKT_name'] : '',
1315
+				'TKT_description' => ! empty($ticket_data['TKT_description']) ? $ticket_data['TKT_description'] : '',
1316
+				'TKT_start_date'  => ! empty($ticket_data['TKT_start_date'])
1317
+					? $ticket_data['TKT_start_date']
1318
+					: $default_start_date,
1319
+				'TKT_end_date'    => ! empty($ticket_data['TKT_end_date'])
1320
+					? $ticket_data['TKT_end_date']
1321
+					: $default_end_date,
1322
+				'TKT_qty'         => ! empty($ticket_data['TKT_qty'])
1323
+									 || (isset($ticket_data['TKT_qty']) && (int) $ticket_data['TKT_qty'] === 0)
1324
+					? $ticket_data['TKT_qty']
1325
+					: EE_INF,
1326
+				'TKT_uses'        => ! empty($ticket_data['TKT_uses'])
1327
+									 || (isset($ticket_data['TKT_uses']) && (int) $ticket_data['TKT_uses'] === 0)
1328
+					? $ticket_data['TKT_uses']
1329
+					: EE_INF,
1330
+				'TKT_min'         => ! empty($ticket_data['TKT_min']) ? $ticket_data['TKT_min'] : 0,
1331
+				'TKT_max'         => ! empty($ticket_data['TKT_max']) ? $ticket_data['TKT_max'] : EE_INF,
1332
+				'TKT_order'       => isset($ticket_data['TKT_order']) ? $ticket_data['TKT_order'] : $row,
1333
+				'TKT_price'       => $ticket_price,
1334
+				'TKT_row'         => $row,
1335
+			];
1336
+			// if this is a default ticket, then we need to set the TKT_ID to 0 and update accordingly,
1337
+			// which means in turn that the prices will become new prices as well.
1338
+			if (isset($ticket_data['TKT_is_default']) && $ticket_data['TKT_is_default']) {
1339
+				$ticket_values['TKT_ID']         = 0;
1340
+				$ticket_values['TKT_is_default'] = 0;
1341
+				$update_prices                   = true;
1342
+			}
1343
+			// if we have a TKT_ID then we need to get that existing TKT_obj and update it
1344
+			// we actually do our saves ahead of adding any relations because its entirely possible that this
1345
+			// ticket didn't get removed or added to any datetime in the session but DID have it's items modified.
1346
+			// keep in mind that if the ticket has been sold (and we have changed pricing information),
1347
+			// then we won't be updating the tkt but instead a new tkt will be created and the old one archived.
1348
+			if (! empty($ticket_data['TKT_ID'])) {
1349
+				$existing_ticket = EEM_Ticket::instance($event_timezone)->get_one_by_ID($ticket_data['TKT_ID']);
1350
+				if (! $existing_ticket instanceof EE_Ticket) {
1351
+					throw new RuntimeException(
1352
+						sprintf(
1353
+							esc_html__(
1354
+								'Something went wrong! A valid Ticket could not be retrieved from the database using the supplied ID: %1$d',
1355
+								'event_espresso'
1356
+							),
1357
+							$ticket_data['TKT_ID']
1358
+						)
1359
+					);
1360
+				}
1361
+				$ticket_sold = $existing_ticket->count_related(
1362
+					'Registration',
1363
+					[
1364
+							[
1365
+								'STS_ID' => [
1366
+									'NOT IN',
1367
+									[EEM_Registration::status_id_incomplete],
1368
+								],
1369
+							],
1370
+						]
1371
+				) > 0;
1372
+				// let's just check the total price for the existing ticket and determine if it matches the new total price.
1373
+				// if they are different then we create a new ticket (if $ticket_sold)
1374
+				// if they aren't different then we go ahead and modify existing ticket.
1375
+				$create_new_ticket = $ticket_sold
1376
+									 && $ticket_price !== $existing_ticket->price()
1377
+									 && ! $existing_ticket->deleted();
1378
+				$existing_ticket->set_date_format($date_formats[0]);
1379
+				$existing_ticket->set_time_format($date_formats[1]);
1380
+				// set new values
1381
+				foreach ($ticket_values as $field => $value) {
1382
+					if ($field == 'TKT_qty') {
1383
+						$existing_ticket->set_qty($value);
1384
+					} elseif ($field == 'TKT_price') {
1385
+						$existing_ticket->set('TKT_price', $ticket_price);
1386
+					} else {
1387
+						$existing_ticket->set($field, $value);
1388
+					}
1389
+				}
1390
+				$ticket = $existing_ticket;
1391
+				// if $create_new_ticket is false then we can safely update the existing ticket.
1392
+				//  Otherwise we have to create a new ticket.
1393
+				if ($create_new_ticket) {
1394
+					// archive the old ticket first
1395
+					$existing_ticket->set('TKT_deleted', 1);
1396
+					$existing_ticket->save();
1397
+					// make sure this ticket is still recorded in our $saved_tickets
1398
+					// so we don't run it through the regular trash routine.
1399
+					$saved_tickets[ $existing_ticket->ID() ] = $existing_ticket;
1400
+					// create new ticket that's a copy of the existing except,
1401
+					// (a new id of course and not archived) AND has the new TKT_price associated with it.
1402
+					$new_ticket = clone $existing_ticket;
1403
+					$new_ticket->set('TKT_ID', 0);
1404
+					$new_ticket->set('TKT_deleted', 0);
1405
+					$new_ticket->set('TKT_sold', 0);
1406
+					// now we need to make sure that $new prices are created as well and attached to new ticket.
1407
+					$update_prices = true;
1408
+					$ticket        = $new_ticket;
1409
+				}
1410
+			} else {
1411
+				// no TKT_id so a new ticket
1412
+				$ticket_values['TKT_price'] = $ticket_price;
1413
+				$ticket                     = EE_Ticket::new_instance($ticket_values, $event_timezone, $date_formats);
1414
+				$update_prices              = true;
1415
+			}
1416
+			if (! $ticket instanceof EE_Ticket) {
1417
+				throw new RuntimeException(
1418
+					sprintf(
1419
+						esc_html__(
1420
+							'Something went wrong! A valid Ticket could not be generated or retrieved using the supplied data: %1$s',
1421
+							'event_espresso'
1422
+						),
1423
+						print_r($ticket_values, true)
1424
+					)
1425
+				);
1426
+			}
1427
+			// cap ticket qty by datetime reg limits
1428
+			$ticket->set_qty(min($ticket->qty(), $ticket->qty('reg_limit')));
1429
+			// update ticket.
1430
+			$ticket->save();
1431
+			// before going any further make sure our dates are setup correctly
1432
+			// so that the end date is always equal or greater than the start date.
1433
+			if ($ticket->get_raw('TKT_start_date') > $ticket->get_raw('TKT_end_date')) {
1434
+				$ticket->set('TKT_end_date', $ticket->get('TKT_start_date'));
1435
+				$ticket = EEH_DTT_Helper::date_time_add($ticket, 'TKT_end_date', 'days');
1436
+				$ticket->save();
1437
+			}
1438
+			// initially let's add the ticket to the datetime
1439
+			$datetime->_add_relation_to($ticket, 'Ticket');
1440
+			$saved_tickets[ $ticket->ID() ] = $ticket;
1441
+			// add prices to ticket
1442
+			$prices_data = isset($data['edit_prices'][ $row ]) && is_array($data['edit_prices'][ $row ])
1443
+				? $data['edit_prices'][ $row ]
1444
+				: [];
1445
+			$this->_add_prices_to_ticket($prices_data, $ticket, $update_prices);
1446
+		}
1447
+		// however now we need to handle permanently deleting tickets via the ui.
1448
+		// Keep in mind that the ui does not allow deleting/archiving tickets that have ticket sold.
1449
+		// However, it does allow for deleting tickets that have no tickets sold,
1450
+		// in which case we want to get rid of permanently because there is no need to save in db.
1451
+		$old_tickets     = isset($old_tickets[0]) && $old_tickets[0] === '' ? [] : $old_tickets;
1452
+		$tickets_removed = array_diff($old_tickets, array_keys($saved_tickets));
1453
+		foreach ($tickets_removed as $id) {
1454
+			$id = absint($id);
1455
+			// get the ticket for this id
1456
+			$ticket_to_remove = EEM_Ticket::instance()->get_one_by_ID($id);
1457
+			if (! $ticket_to_remove instanceof EE_Ticket) {
1458
+				continue;
1459
+			}
1460
+			// need to get all the related datetimes on this ticket and remove from every single one of them
1461
+			// (remember this process can ONLY kick off if there are NO tickets sold)
1462
+			$related_datetimes = $ticket_to_remove->get_many_related('Datetime');
1463
+			foreach ($related_datetimes as $related_datetime) {
1464
+				$ticket_to_remove->_remove_relation_to($related_datetime, 'Datetime');
1465
+			}
1466
+			// need to do the same for prices (except these prices can also be deleted because again,
1467
+			// tickets can only be trashed if they don't have any TKTs sold (otherwise they are just archived))
1468
+			$ticket_to_remove->delete_related_permanently('Price');
1469
+			// finally let's delete this ticket
1470
+			// (which should not be blocked at this point b/c we've removed all our relationships)
1471
+			$ticket_to_remove->delete_permanently();
1472
+		}
1473
+		return [$datetime, $saved_tickets];
1474
+	}
1475
+
1476
+
1477
+	/**
1478
+	 * This attaches a list of given prices to a ticket.
1479
+	 * Note we dont' have to worry about ever removing relationships (or archiving prices)
1480
+	 * because if there is a change in price information on a ticket, a new ticket is created anyways
1481
+	 * so the archived ticket will retain the old price info and prices are automatically "archived" via the ticket.
1482
+	 *
1483
+	 * @access  private
1484
+	 * @param array     $prices_data Array of prices from the form.
1485
+	 * @param EE_Ticket $ticket      EE_Ticket object that prices are being attached to.
1486
+	 * @param bool      $new_prices  Whether attach existing incoming prices or create new ones.
1487
+	 * @return  void
1488
+	 * @throws EE_Error
1489
+	 * @throws ReflectionException
1490
+	 */
1491
+	private function _add_prices_to_ticket($prices_data, EE_Ticket $ticket, $new_prices = false)
1492
+	{
1493
+		$timezone = $ticket->get_timezone();
1494
+		foreach ($prices_data as $row => $price_data) {
1495
+			$price_values = [
1496
+				'PRC_ID'         => ! empty($price_data['PRC_ID']) ? $price_data['PRC_ID'] : null,
1497
+				'PRT_ID'         => ! empty($price_data['PRT_ID']) ? $price_data['PRT_ID'] : null,
1498
+				'PRC_amount'     => ! empty($price_data['PRC_amount']) ? $price_data['PRC_amount'] : 0,
1499
+				'PRC_name'       => ! empty($price_data['PRC_name']) ? $price_data['PRC_name'] : '',
1500
+				'PRC_desc'       => ! empty($price_data['PRC_desc']) ? $price_data['PRC_desc'] : '',
1501
+				'PRC_is_default' => 0, // make sure prices are NOT set as default from this context
1502
+				'PRC_order'      => $row,
1503
+			];
1504
+			if ($new_prices || empty($price_values['PRC_ID'])) {
1505
+				$price_values['PRC_ID'] = 0;
1506
+				$price                  = EE_Price::new_instance($price_values, $timezone);
1507
+			} else {
1508
+				$price = EEM_Price::instance($timezone)->get_one_by_ID($price_data['PRC_ID']);
1509
+				// update this price with new values
1510
+				foreach ($price_values as $field => $new_price) {
1511
+					$price->set($field, $new_price);
1512
+				}
1513
+			}
1514
+			if (! $price instanceof EE_Price) {
1515
+				throw new RuntimeException(
1516
+					sprintf(
1517
+						esc_html__(
1518
+							'Something went wrong! A valid Price could not be generated or retrieved using the supplied data: %1$s',
1519
+							'event_espresso'
1520
+						),
1521
+						print_r($price_values, true)
1522
+					)
1523
+				);
1524
+			}
1525
+			$price->save();
1526
+			$ticket->_add_relation_to($price, 'Price');
1527
+		}
1528
+	}
1529
+
1530
+
1531
+	/**
1532
+	 * Add in our autosave ajax handlers
1533
+	 *
1534
+	 */
1535
+	protected function _ee_autosave_create_new()
1536
+	{
1537
+	}
1538
+
1539
+
1540
+	/**
1541
+	 * More autosave handlers.
1542
+	 */
1543
+	protected function _ee_autosave_edit()
1544
+	{
1545
+	}
1546
+
1547
+
1548
+	/**
1549
+	 * @throws EE_Error
1550
+	 * @throws ReflectionException
1551
+	 */
1552
+	private function _generate_publish_box_extra_content()
1553
+	{
1554
+		// load formatter helper
1555
+		// args for getting related registrations
1556
+		$approved_query_args        = [
1557
+			[
1558
+				'REG_deleted' => 0,
1559
+				'STS_ID'      => EEM_Registration::status_id_approved,
1560
+			],
1561
+		];
1562
+		$not_approved_query_args    = [
1563
+			[
1564
+				'REG_deleted' => 0,
1565
+				'STS_ID'      => EEM_Registration::status_id_not_approved,
1566
+			],
1567
+		];
1568
+		$pending_payment_query_args = [
1569
+			[
1570
+				'REG_deleted' => 0,
1571
+				'STS_ID'      => EEM_Registration::status_id_pending_payment,
1572
+			],
1573
+		];
1574
+		// publish box
1575
+		$publish_box_extra_args = [
1576
+			'view_approved_reg_url'        => add_query_arg(
1577
+				[
1578
+					'action'      => 'default',
1579
+					'event_id'    => $this->_cpt_model_obj->ID(),
1580
+					'_reg_status' => EEM_Registration::status_id_approved,
1581
+				],
1582
+				REG_ADMIN_URL
1583
+			),
1584
+			'view_not_approved_reg_url'    => add_query_arg(
1585
+				[
1586
+					'action'      => 'default',
1587
+					'event_id'    => $this->_cpt_model_obj->ID(),
1588
+					'_reg_status' => EEM_Registration::status_id_not_approved,
1589
+				],
1590
+				REG_ADMIN_URL
1591
+			),
1592
+			'view_pending_payment_reg_url' => add_query_arg(
1593
+				[
1594
+					'action'      => 'default',
1595
+					'event_id'    => $this->_cpt_model_obj->ID(),
1596
+					'_reg_status' => EEM_Registration::status_id_pending_payment,
1597
+				],
1598
+				REG_ADMIN_URL
1599
+			),
1600
+			'approved_regs'                => $this->_cpt_model_obj->count_related(
1601
+				'Registration',
1602
+				$approved_query_args
1603
+			),
1604
+			'not_approved_regs'            => $this->_cpt_model_obj->count_related(
1605
+				'Registration',
1606
+				$not_approved_query_args
1607
+			),
1608
+			'pending_payment_regs'         => $this->_cpt_model_obj->count_related(
1609
+				'Registration',
1610
+				$pending_payment_query_args
1611
+			),
1612
+			'misc_pub_section_class'       => apply_filters(
1613
+				'FHEE_Events_Admin_Page___generate_publish_box_extra_content__misc_pub_section_class',
1614
+				'misc-pub-section'
1615
+			),
1616
+		];
1617
+		ob_start();
1618
+		do_action(
1619
+			'AHEE__Events_Admin_Page___generate_publish_box_extra_content__event_editor_overview_add',
1620
+			$this->_cpt_model_obj
1621
+		);
1622
+		$publish_box_extra_args['event_editor_overview_add'] = ob_get_clean();
1623
+		// load template
1624
+		EEH_Template::display_template(
1625
+			EVENTS_TEMPLATE_PATH . 'event_publish_box_extras.template.php',
1626
+			$publish_box_extra_args
1627
+		);
1628
+	}
1629
+
1630
+
1631
+	/**
1632
+	 * @return EE_Event
1633
+	 */
1634
+	public function get_event_object()
1635
+	{
1636
+		return $this->_cpt_model_obj;
1637
+	}
1638
+
1639
+
1640
+
1641
+
1642
+	/** METABOXES * */
1643
+	/**
1644
+	 * _register_event_editor_meta_boxes
1645
+	 * add all metaboxes related to the event_editor
1646
+	 *
1647
+	 * @return void
1648
+	 * @throws EE_Error
1649
+	 * @throws ReflectionException
1650
+	 */
1651
+	protected function _register_event_editor_meta_boxes()
1652
+	{
1653
+		$this->verify_cpt_object();
1654
+		$use_advanced_editor = $this->admin_config->useAdvancedEditor();
1655
+		// check if the new EDTR reg options meta box is being used, and if so, don't load the legacy version
1656
+		if (! $use_advanced_editor || ! $this->feature->allowed('use_reg_options_meta_box')) {
1657
+			$this->addMetaBox(
1658
+				'espresso_event_editor_event_options',
1659
+				esc_html__('Event Registration Options', 'event_espresso'),
1660
+				[$this, 'registration_options_meta_box'],
1661
+				$this->page_slug,
1662
+				'side'
1663
+			);
1664
+		}
1665
+		if (! $use_advanced_editor) {
1666
+			$this->addMetaBox(
1667
+				'espresso_event_editor_tickets',
1668
+				esc_html__('Event Datetime & Ticket', 'event_espresso'),
1669
+				[$this, 'ticket_metabox'],
1670
+				$this->page_slug,
1671
+				'normal',
1672
+				'high'
1673
+			);
1674
+		} elseif ($this->feature->allowed('use_reg_options_meta_box')) {
1675
+			add_action(
1676
+				'add_meta_boxes_espresso_events',
1677
+				function () {
1678
+					global $current_screen;
1679
+					remove_meta_box('authordiv', $current_screen, 'normal');
1680
+				},
1681
+				99
1682
+			);
1683
+		}
1684
+		// NOTE: if you're looking for other metaboxes in here,
1685
+		// where a metabox has a related management page in the admin
1686
+		// you will find it setup in the related management page's "_Hooks" file.
1687
+		// i.e. messages metabox is found in "espresso_events_Messages_Hooks.class.php".
1688
+	}
1689
+
1690
+
1691
+	/**
1692
+	 * @throws DomainException
1693
+	 * @throws EE_Error
1694
+	 * @throws ReflectionException
1695
+	 */
1696
+	public function ticket_metabox()
1697
+	{
1698
+		$existing_datetime_ids = $existing_ticket_ids = [];
1699
+		// defaults for template args
1700
+		$template_args = [
1701
+			'existing_datetime_ids'    => '',
1702
+			'event_datetime_help_link' => '',
1703
+			'ticket_options_help_link' => '',
1704
+			'time'                     => null,
1705
+			'ticket_rows'              => '',
1706
+			'existing_ticket_ids'      => '',
1707
+			'total_ticket_rows'        => 1,
1708
+			'ticket_js_structure'      => '',
1709
+			'trash_icon'               => 'dashicons dashicons-lock',
1710
+			'disabled'                 => '',
1711
+		];
1712
+		$event_id      = is_object($this->_cpt_model_obj) ? $this->_cpt_model_obj->ID() : null;
1713
+		/**
1714
+		 * 1. Start with retrieving Datetimes
1715
+		 * 2. Fore each datetime get related tickets
1716
+		 * 3. For each ticket get related prices
1717
+		 */
1718
+		/** @var EEM_Datetime $datetime_model */
1719
+		$datetime_model = EE_Registry::instance()->load_model('Datetime');
1720
+		/** @var EEM_Ticket $datetime_model */
1721
+		$ticket_model = EE_Registry::instance()->load_model('Ticket');
1722
+		$times        = $datetime_model->get_all_event_dates($event_id);
1723
+		/** @type EE_Datetime $first_datetime */
1724
+		$first_datetime = reset($times);
1725
+		// do we get related tickets?
1726
+		if (
1727
+			$first_datetime instanceof EE_Datetime
1728
+			&& $first_datetime->ID() !== 0
1729
+		) {
1730
+			$existing_datetime_ids[] = $first_datetime->get('DTT_ID');
1731
+			$template_args['time']   = $first_datetime;
1732
+			$related_tickets         = $first_datetime->tickets(
1733
+				[
1734
+					['OR' => ['TKT_deleted' => 1, 'TKT_deleted*' => 0]],
1735
+					'default_where_conditions' => 'none',
1736
+				]
1737
+			);
1738
+			if (! empty($related_tickets)) {
1739
+				$template_args['total_ticket_rows'] = count($related_tickets);
1740
+				$row                                = 0;
1741
+				foreach ($related_tickets as $ticket) {
1742
+					$existing_ticket_ids[]        = $ticket->get('TKT_ID');
1743
+					$template_args['ticket_rows'] .= $this->_get_ticket_row($ticket, false, $row);
1744
+					$row++;
1745
+				}
1746
+			} else {
1747
+				$template_args['total_ticket_rows'] = 1;
1748
+				/** @type EE_Ticket $ticket */
1749
+				$ticket                       = $ticket_model->create_default_object();
1750
+				$template_args['ticket_rows'] .= $this->_get_ticket_row($ticket);
1751
+			}
1752
+		} else {
1753
+			$template_args['time'] = $times[0];
1754
+			/** @type EE_Ticket[] $tickets */
1755
+			$tickets                      = $ticket_model->get_all_default_tickets();
1756
+			$template_args['ticket_rows'] .= $this->_get_ticket_row($tickets[1]);
1757
+			// NOTE: we're just sending the first default row
1758
+			// (decaf can't manage default tickets so this should be sufficient);
1759
+		}
1760
+		$template_args['event_datetime_help_link'] = $this->_get_help_tab_link(
1761
+			'event_editor_event_datetimes_help_tab'
1762
+		);
1763
+		$template_args['ticket_options_help_link'] = $this->_get_help_tab_link('ticket_options_info');
1764
+		$template_args['existing_datetime_ids']    = implode(',', $existing_datetime_ids);
1765
+		$template_args['existing_ticket_ids']      = implode(',', $existing_ticket_ids);
1766
+		$template_args['ticket_js_structure']      = $this->_get_ticket_row(
1767
+			$ticket_model->create_default_object(),
1768
+			true
1769
+		);
1770
+		$template                                  = apply_filters(
1771
+			'FHEE__Events_Admin_Page__ticket_metabox__template',
1772
+			EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_main.template.php'
1773
+		);
1774
+		EEH_Template::display_template($template, $template_args);
1775
+	}
1776
+
1777
+
1778
+	/**
1779
+	 * Setup an individual ticket form for the decaf event editor page
1780
+	 *
1781
+	 * @access private
1782
+	 * @param EE_Ticket $ticket   the ticket object
1783
+	 * @param boolean   $skeleton whether we're generating a skeleton for js manipulation
1784
+	 * @param int       $row
1785
+	 * @return string generated html for the ticket row.
1786
+	 * @throws EE_Error
1787
+	 * @throws ReflectionException
1788
+	 */
1789
+	private function _get_ticket_row($ticket, $skeleton = false, $row = 0)
1790
+	{
1791
+		$template_args = [
1792
+			'tkt_status_class'    => ' tkt-status-' . $ticket->ticket_status(),
1793
+			'tkt_archive_class'   => $ticket->ticket_status() === EE_Ticket::archived && ! $skeleton ? ' tkt-archived'
1794
+				: '',
1795
+			'ticketrow'           => $skeleton ? 'TICKETNUM' : $row,
1796
+			'TKT_ID'              => $ticket->get('TKT_ID'),
1797
+			'TKT_name'            => $ticket->get('TKT_name'),
1798
+			'TKT_start_date'      => $skeleton ? '' : $ticket->get_date('TKT_start_date', 'Y-m-d h:i a'),
1799
+			'TKT_end_date'        => $skeleton ? '' : $ticket->get_date('TKT_end_date', 'Y-m-d h:i a'),
1800
+			'TKT_is_default'      => $ticket->get('TKT_is_default'),
1801
+			'TKT_qty'             => $ticket->get_pretty('TKT_qty', 'input'),
1802
+			'edit_ticketrow_name' => $skeleton ? 'TICKETNAMEATTR' : 'edit_tickets',
1803
+			'TKT_sold'            => $skeleton ? 0 : $ticket->get('TKT_sold'),
1804
+			'trash_icon'          => ($skeleton || (! empty($ticket) && ! $ticket->get('TKT_deleted')))
1805
+									 && (! empty($ticket) && $ticket->get('TKT_sold') === 0)
1806
+				? 'trash-icon dashicons dashicons-post-trash clickable' : 'dashicons dashicons-lock',
1807
+			'disabled'            => $skeleton || (! empty($ticket) && ! $ticket->get('TKT_deleted')) ? ''
1808
+				: ' disabled=disabled',
1809
+		];
1810
+		$price         = $ticket->ID() !== 0
1811
+			? $ticket->get_first_related('Price', ['default_where_conditions' => 'none'])
1812
+			: null;
1813
+		$price         = $price instanceof EE_Price
1814
+			? $price
1815
+			: EEM_Price::instance()->create_default_object();
1816
+		$price_args    = [
1817
+			'price_currency_symbol' => EE_Registry::instance()->CFG->currency->sign,
1818
+			'PRC_amount'            => $price->get('PRC_amount'),
1819
+			'PRT_ID'                => $price->get('PRT_ID'),
1820
+			'PRC_ID'                => $price->get('PRC_ID'),
1821
+			'PRC_is_default'        => $price->get('PRC_is_default'),
1822
+		];
1823
+		// make sure we have default start and end dates if skeleton
1824
+		// handle rows that should NOT be empty
1825
+		if (empty($template_args['TKT_start_date'])) {
1826
+			// if empty then the start date will be now.
1827
+			$template_args['TKT_start_date'] = date('Y-m-d h:i a', current_time('timestamp'));
1828
+		}
1829
+		if (empty($template_args['TKT_end_date'])) {
1830
+			// get the earliest datetime (if present);
1831
+			$earliest_datetime             = $this->_cpt_model_obj->ID() > 0
1832
+				? $this->_cpt_model_obj->get_first_related(
1833
+					'Datetime',
1834
+					['order_by' => ['DTT_EVT_start' => 'ASC']]
1835
+				)
1836
+				: null;
1837
+			$template_args['TKT_end_date'] = $earliest_datetime instanceof EE_Datetime
1838
+				? $earliest_datetime->get_datetime('DTT_EVT_start', 'Y-m-d', 'h:i a')
1839
+				: date('Y-m-d h:i a', mktime(0, 0, 0, date('m'), date('d') + 7, date('Y')));
1840
+		}
1841
+		$template_args = array_merge($template_args, $price_args);
1842
+		$template      = apply_filters(
1843
+			'FHEE__Events_Admin_Page__get_ticket_row__template',
1844
+			EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_ticket_row.template.php',
1845
+			$ticket
1846
+		);
1847
+		return EEH_Template::display_template($template, $template_args, true);
1848
+	}
1849
+
1850
+
1851
+	/**
1852
+	 * @throws EE_Error
1853
+	 * @throws ReflectionException
1854
+	 */
1855
+	public function registration_options_meta_box()
1856
+	{
1857
+		$yes_no_values             = [
1858
+			['id' => true, 'text' => esc_html__('Yes', 'event_espresso')],
1859
+			['id' => false, 'text' => esc_html__('No', 'event_espresso')],
1860
+		];
1861
+		$default_reg_status_values = EEM_Registration::reg_status_array(
1862
+			[
1863
+				EEM_Registration::status_id_cancelled,
1864
+				EEM_Registration::status_id_declined,
1865
+				EEM_Registration::status_id_incomplete,
1866
+			],
1867
+			true
1868
+		);
1869
+		// $template_args['is_active_select'] = EEH_Form_Fields::select_input('is_active', $yes_no_values, $this->_cpt_model_obj->is_active());
1870
+		$template_args['_event']                          = $this->_cpt_model_obj;
1871
+		$template_args['event']                           = $this->_cpt_model_obj;
1872
+		$template_args['active_status']                   = $this->_cpt_model_obj->pretty_active_status(false);
1873
+		$template_args['additional_limit']                = $this->_cpt_model_obj->additional_limit();
1874
+		$template_args['default_registration_status']     = EEH_Form_Fields::select_input(
1875
+			'default_reg_status',
1876
+			$default_reg_status_values,
1877
+			$this->_cpt_model_obj->default_registration_status()
1878
+		);
1879
+		$template_args['display_description']             = EEH_Form_Fields::select_input(
1880
+			'display_desc',
1881
+			$yes_no_values,
1882
+			$this->_cpt_model_obj->display_description()
1883
+		);
1884
+		$template_args['display_ticket_selector']         = EEH_Form_Fields::select_input(
1885
+			'display_ticket_selector',
1886
+			$yes_no_values,
1887
+			$this->_cpt_model_obj->display_ticket_selector(),
1888
+			'',
1889
+			'',
1890
+			false
1891
+		);
1892
+		$template_args['additional_registration_options'] = apply_filters(
1893
+			'FHEE__Events_Admin_Page__registration_options_meta_box__additional_registration_options',
1894
+			'',
1895
+			$template_args,
1896
+			$yes_no_values,
1897
+			$default_reg_status_values
1898
+		);
1899
+		EEH_Template::display_template(
1900
+			EVENTS_TEMPLATE_PATH . 'event_registration_options.template.php',
1901
+			$template_args
1902
+		);
1903
+	}
1904
+
1905
+
1906
+	/**
1907
+	 * _get_events()
1908
+	 * This method simply returns all the events (for the given _view and paging)
1909
+	 *
1910
+	 * @access public
1911
+	 * @param int  $per_page     count of items per page (20 default);
1912
+	 * @param int  $current_page what is the current page being viewed.
1913
+	 * @param bool $count        if TRUE then we just return a count of ALL events matching the given _view.
1914
+	 *                           If FALSE then we return an array of event objects
1915
+	 *                           that match the given _view and paging parameters.
1916
+	 * @return array|int         an array of event objects or a count of them.
1917
+	 * @throws Exception
1918
+	 */
1919
+	public function get_events($per_page = 10, $current_page = 1, $count = false)
1920
+	{
1921
+		$EEM_Event   = $this->_event_model();
1922
+		$offset      = ($current_page - 1) * $per_page;
1923
+		$limit       = $count ? null : $offset . ',' . $per_page;
1924
+		$orderby     = $this->request->getRequestParam('orderby', 'EVT_ID');
1925
+		$order       = $this->request->getRequestParam('order', 'DESC');
1926
+		$month_range = $this->request->getRequestParam('month_range');
1927
+		if ($month_range) {
1928
+			$pieces = explode(' ', $month_range, 3);
1929
+			// simulate the FIRST day of the month, that fixes issues for months like February
1930
+			// where PHP doesn't know what to assume for date.
1931
+			// @see https://events.codebasehq.com/projects/event-espresso/tickets/10437
1932
+			$month_r = ! empty($pieces[0]) ? date('m', EEH_DTT_Helper::first_of_month_timestamp($pieces[0])) : '';
1933
+			$year_r  = ! empty($pieces[1]) ? $pieces[1] : '';
1934
+		}
1935
+		$where  = [];
1936
+		$status = $this->request->getRequestParam('status');
1937
+		// determine what post_status our condition will have for the query.
1938
+		switch ($status) {
1939
+			case 'month':
1940
+			case 'today':
1941
+			case null:
1942
+			case 'all':
1943
+				break;
1944
+			case 'draft':
1945
+				$where['status'] = ['IN', ['draft', 'auto-draft']];
1946
+				break;
1947
+			default:
1948
+				$where['status'] = $status;
1949
+		}
1950
+		// categories? The default for all categories is -1
1951
+		$category = $this->request->getRequestParam('EVT_CAT', -1, 'int');
1952
+		if ($category !== -1) {
1953
+			$where['Term_Taxonomy.taxonomy'] = EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY;
1954
+			$where['Term_Taxonomy.term_id']  = $category;
1955
+		}
1956
+		// date where conditions
1957
+		$start_formats = EEM_Datetime::instance()->get_formats_for('DTT_EVT_start');
1958
+		if ($month_range) {
1959
+			$DateTime = new DateTime(
1960
+				$year_r . '-' . $month_r . '-01 00:00:00',
1961
+				new DateTimeZone('UTC')
1962
+			);
1963
+			$start    = $DateTime->getTimestamp();
1964
+			// set the datetime to be the end of the month
1965
+			$DateTime->setDate(
1966
+				$year_r,
1967
+				$month_r,
1968
+				$DateTime->format('t')
1969
+			)->setTime(23, 59, 59);
1970
+			$end                             = $DateTime->getTimestamp();
1971
+			$where['Datetime.DTT_EVT_start'] = ['BETWEEN', [$start, $end]];
1972
+		} elseif ($status === 'today') {
1973
+			$DateTime                        =
1974
+				new DateTime('now', new DateTimeZone(EEM_Event::instance()->get_timezone()));
1975
+			$start                           = $DateTime->setTime(0, 0)->format(implode(' ', $start_formats));
1976
+			$end                             = $DateTime->setTime(23, 59, 59)->format(implode(' ', $start_formats));
1977
+			$where['Datetime.DTT_EVT_start'] = ['BETWEEN', [$start, $end]];
1978
+		} elseif ($status === 'month') {
1979
+			$now                             = date('Y-m-01');
1980
+			$DateTime                        =
1981
+				new DateTime($now, new DateTimeZone(EEM_Event::instance()->get_timezone()));
1982
+			$start                           = $DateTime->setTime(0, 0)->format(implode(' ', $start_formats));
1983
+			$end                             = $DateTime->setDate(date('Y'), date('m'), $DateTime->format('t'))
1984
+														->setTime(23, 59, 59)
1985
+														->format(implode(' ', $start_formats));
1986
+			$where['Datetime.DTT_EVT_start'] = ['BETWEEN', [$start, $end]];
1987
+		}
1988
+		if (! EE_Registry::instance()->CAP->current_user_can('ee_read_others_events', 'get_events')) {
1989
+			$where['EVT_wp_user'] = get_current_user_id();
1990
+		} else {
1991
+			if (! isset($where['status'])) {
1992
+				if (! EE_Registry::instance()->CAP->current_user_can('ee_read_private_events', 'get_events')) {
1993
+					$where['OR'] = [
1994
+						'status*restrict_private' => ['!=', 'private'],
1995
+						'AND'                     => [
1996
+							'status*inclusive' => ['=', 'private'],
1997
+							'EVT_wp_user'      => get_current_user_id(),
1998
+						],
1999
+					];
2000
+				}
2001
+			}
2002
+		}
2003
+		$wp_user = $this->request->getRequestParam('EVT_wp_user', 0, 'int');
2004
+		if (
2005
+			$wp_user
2006
+			&& $wp_user !== get_current_user_id()
2007
+			&& EE_Registry::instance()->CAP->current_user_can('ee_read_others_events', 'get_events')
2008
+		) {
2009
+			$where['EVT_wp_user'] = $wp_user;
2010
+		}
2011
+		// search query handling
2012
+		$search_term = $this->request->getRequestParam('s');
2013
+		if ($search_term) {
2014
+			$search_term = '%' . $search_term . '%';
2015
+			$where['OR'] = [
2016
+				'EVT_name'       => ['LIKE', $search_term],
2017
+				'EVT_desc'       => ['LIKE', $search_term],
2018
+				'EVT_short_desc' => ['LIKE', $search_term],
2019
+			];
2020
+		}
2021
+		// filter events by venue.
2022
+		$venue = $this->request->getRequestParam('venue', 0, 'int');
2023
+		if ($venue) {
2024
+			$where['Venue.VNU_ID'] = $venue;
2025
+		}
2026
+		$request_params = $this->request->requestParams();
2027
+		$where          = apply_filters('FHEE__Events_Admin_Page__get_events__where', $where, $request_params);
2028
+		$query_params   = apply_filters(
2029
+			'FHEE__Events_Admin_Page__get_events__query_params',
2030
+			[
2031
+				$where,
2032
+				'limit'    => $limit,
2033
+				'order_by' => $orderby,
2034
+				'order'    => $order,
2035
+				'group_by' => 'EVT_ID',
2036
+			],
2037
+			$request_params
2038
+		);
2039
+
2040
+		// let's first check if we have special requests coming in.
2041
+		$active_status = $this->request->getRequestParam('active_status');
2042
+		if ($active_status) {
2043
+			switch ($active_status) {
2044
+				case 'upcoming':
2045
+					return $EEM_Event->get_upcoming_events($query_params, $count);
2046
+				case 'expired':
2047
+					return $EEM_Event->get_expired_events($query_params, $count);
2048
+				case 'active':
2049
+					return $EEM_Event->get_active_events($query_params, $count);
2050
+				case 'inactive':
2051
+					return $EEM_Event->get_inactive_events($query_params, $count);
2052
+			}
2053
+		}
2054
+
2055
+		return $count ? $EEM_Event->count([$where], 'EVT_ID', true) : $EEM_Event->get_all($query_params);
2056
+	}
2057
+
2058
+
2059
+	/**
2060
+	 * handling for WordPress CPT actions (trash, restore, delete)
2061
+	 *
2062
+	 * @param string $post_id
2063
+	 * @throws EE_Error
2064
+	 * @throws ReflectionException
2065
+	 */
2066
+	public function trash_cpt_item($post_id)
2067
+	{
2068
+		$this->request->setRequestParam('EVT_ID', $post_id);
2069
+		$this->_trash_or_restore_event('trash', false);
2070
+	}
2071
+
2072
+
2073
+	/**
2074
+	 * @param string $post_id
2075
+	 * @throws EE_Error
2076
+	 * @throws ReflectionException
2077
+	 */
2078
+	public function restore_cpt_item($post_id)
2079
+	{
2080
+		$this->request->setRequestParam('EVT_ID', $post_id);
2081
+		$this->_trash_or_restore_event('draft', false);
2082
+	}
2083
+
2084
+
2085
+	/**
2086
+	 * @param string $post_id
2087
+	 * @throws EE_Error
2088
+	 * @throws EE_Error
2089
+	 */
2090
+	public function delete_cpt_item($post_id)
2091
+	{
2092
+		throw new EE_Error(
2093
+			esc_html__(
2094
+				'Please contact Event Espresso support with the details of the steps taken to produce this error.',
2095
+				'event_espresso'
2096
+			)
2097
+		);
2098
+		// $this->request->setRequestParam('EVT_ID', $post_id);
2099
+		// $this->_delete_event();
2100
+	}
2101
+
2102
+
2103
+	/**
2104
+	 * _trash_or_restore_event
2105
+	 *
2106
+	 * @access protected
2107
+	 * @param string $event_status
2108
+	 * @param bool   $redirect_after
2109
+	 * @throws EE_Error
2110
+	 * @throws EE_Error
2111
+	 * @throws ReflectionException
2112
+	 */
2113
+	protected function _trash_or_restore_event($event_status = 'trash', $redirect_after = true)
2114
+	{
2115
+		// determine the event id and set to array.
2116
+		$EVT_ID = $this->request->getRequestParam('EVT_ID', 0, 'int');
2117
+		// loop thru events
2118
+		if ($EVT_ID) {
2119
+			// clean status
2120
+			$event_status = sanitize_key($event_status);
2121
+			// grab status
2122
+			if (! empty($event_status)) {
2123
+				$success = $this->_change_event_status($EVT_ID, $event_status);
2124
+			} else {
2125
+				$success = false;
2126
+				$msg     = esc_html__(
2127
+					'An error occurred. The event could not be moved to the trash because a valid event status was not not supplied.',
2128
+					'event_espresso'
2129
+				);
2130
+				EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2131
+			}
2132
+		} else {
2133
+			$success = false;
2134
+			$msg     = esc_html__(
2135
+				'An error occurred. The event could not be moved to the trash because a valid event ID was not not supplied.',
2136
+				'event_espresso'
2137
+			);
2138
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2139
+		}
2140
+		$action = $event_status === 'trash' ? 'moved to the trash' : 'restored from the trash';
2141
+		if ($redirect_after) {
2142
+			$this->_redirect_after_action($success, 'Event', $action, ['action' => 'default']);
2143
+		}
2144
+	}
2145
+
2146
+
2147
+	/**
2148
+	 * _trash_or_restore_events
2149
+	 *
2150
+	 * @access protected
2151
+	 * @param string $event_status
2152
+	 * @return void
2153
+	 * @throws EE_Error
2154
+	 * @throws EE_Error
2155
+	 * @throws ReflectionException
2156
+	 */
2157
+	protected function _trash_or_restore_events($event_status = 'trash')
2158
+	{
2159
+		// clean status
2160
+		$event_status = sanitize_key($event_status);
2161
+		// grab status
2162
+		if (! empty($event_status)) {
2163
+			$success = true;
2164
+			// determine the event id and set to array.
2165
+			$EVT_IDs = $this->request->getRequestParam('EVT_IDs', [], 'int', true);
2166
+			// loop thru events
2167
+			foreach ($EVT_IDs as $EVT_ID) {
2168
+				if ($EVT_ID = absint($EVT_ID)) {
2169
+					$results = $this->_change_event_status($EVT_ID, $event_status);
2170
+					$success = $results !== false ? $success : false;
2171
+				} else {
2172
+					$msg = sprintf(
2173
+						esc_html__(
2174
+							'An error occurred. Event #%d could not be moved to the trash because a valid event ID was not not supplied.',
2175
+							'event_espresso'
2176
+						),
2177
+						$EVT_ID
2178
+					);
2179
+					EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2180
+					$success = false;
2181
+				}
2182
+			}
2183
+		} else {
2184
+			$success = false;
2185
+			$msg     = esc_html__(
2186
+				'An error occurred. The event could not be moved to the trash because a valid event status was not not supplied.',
2187
+				'event_espresso'
2188
+			);
2189
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2190
+		}
2191
+		// in order to force a pluralized result message we need to send back a success status greater than 1
2192
+		$success = $success ? 2 : false;
2193
+		$action  = $event_status === 'trash' ? 'moved to the trash' : 'restored from the trash';
2194
+		$this->_redirect_after_action($success, 'Events', $action, ['action' => 'default']);
2195
+	}
2196
+
2197
+
2198
+	/**
2199
+	 * @param int    $EVT_ID
2200
+	 * @param string $event_status
2201
+	 * @return bool
2202
+	 * @throws EE_Error
2203
+	 * @throws ReflectionException
2204
+	 */
2205
+	private function _change_event_status($EVT_ID = 0, $event_status = '')
2206
+	{
2207
+		// grab event id
2208
+		if (! $EVT_ID) {
2209
+			$msg = esc_html__(
2210
+				'An error occurred. No Event ID or an invalid Event ID was received.',
2211
+				'event_espresso'
2212
+			);
2213
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2214
+			return false;
2215
+		}
2216
+		$this->_cpt_model_obj = EEM_Event::instance()->get_one_by_ID($EVT_ID);
2217
+		// clean status
2218
+		$event_status = sanitize_key($event_status);
2219
+		// grab status
2220
+		if (empty($event_status)) {
2221
+			$msg = esc_html__(
2222
+				'An error occurred. No Event Status or an invalid Event Status was received.',
2223
+				'event_espresso'
2224
+			);
2225
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2226
+			return false;
2227
+		}
2228
+		// was event trashed or restored ?
2229
+		switch ($event_status) {
2230
+			case 'draft':
2231
+				$action = 'restored from the trash';
2232
+				$hook   = 'AHEE_event_restored_from_trash';
2233
+				break;
2234
+			case 'trash':
2235
+				$action = 'moved to the trash';
2236
+				$hook   = 'AHEE_event_moved_to_trash';
2237
+				break;
2238
+			default:
2239
+				$action = 'updated';
2240
+				$hook   = false;
2241
+		}
2242
+		// use class to change status
2243
+		$this->_cpt_model_obj->set_status($event_status);
2244
+		$success = $this->_cpt_model_obj->save();
2245
+		if (! $success) {
2246
+			$msg = sprintf(esc_html__('An error occurred. The event could not be %s.', 'event_espresso'), $action);
2247
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2248
+			return false;
2249
+		}
2250
+		if ($hook) {
2251
+			do_action($hook);
2252
+		}
2253
+		return true;
2254
+	}
2255
+
2256
+
2257
+	/**
2258
+	 * @param array $event_ids
2259
+	 * @return array
2260
+	 * @since   4.10.23.p
2261
+	 */
2262
+	private function cleanEventIds(array $event_ids)
2263
+	{
2264
+		return array_map('absint', $event_ids);
2265
+	}
2266
+
2267
+
2268
+	/**
2269
+	 * @return array
2270
+	 * @since   4.10.23.p
2271
+	 */
2272
+	private function getEventIdsFromRequest()
2273
+	{
2274
+		if ($this->request->requestParamIsSet('EVT_IDs')) {
2275
+			return $this->request->getRequestParam('EVT_IDs', [], 'int', true);
2276
+		} else {
2277
+			return $this->request->getRequestParam('EVT_ID', [], 'int', true);
2278
+		}
2279
+	}
2280
+
2281
+
2282
+	/**
2283
+	 * @param bool $preview_delete
2284
+	 * @throws EE_Error
2285
+	 */
2286
+	protected function _delete_event($preview_delete = true)
2287
+	{
2288
+		$this->_delete_events($preview_delete);
2289
+	}
2290
+
2291
+
2292
+	/**
2293
+	 * Gets the tree traversal batch persister.
2294
+	 *
2295
+	 * @return NodeGroupDao
2296
+	 * @throws InvalidArgumentException
2297
+	 * @throws InvalidDataTypeException
2298
+	 * @throws InvalidInterfaceException
2299
+	 * @since 4.10.12.p
2300
+	 */
2301
+	protected function getModelObjNodeGroupPersister()
2302
+	{
2303
+		if (! $this->model_obj_node_group_persister instanceof NodeGroupDao) {
2304
+			$this->model_obj_node_group_persister =
2305
+				$this->getLoader()->load('\EventEspresso\core\services\orm\tree_traversal\NodeGroupDao');
2306
+		}
2307
+		return $this->model_obj_node_group_persister;
2308
+	}
2309
+
2310
+
2311
+	/**
2312
+	 * @param bool $preview_delete
2313
+	 * @return void
2314
+	 * @throws EE_Error
2315
+	 */
2316
+	protected function _delete_events($preview_delete = true)
2317
+	{
2318
+		$event_ids = $this->getEventIdsFromRequest();
2319
+		if ($preview_delete) {
2320
+			$this->generateDeletionPreview($event_ids);
2321
+		} else {
2322
+			EEM_Event::instance()->delete_permanently([['EVT_ID' => ['IN', $event_ids]]]);
2323
+		}
2324
+	}
2325
+
2326
+
2327
+	/**
2328
+	 * @param array $event_ids
2329
+	 */
2330
+	protected function generateDeletionPreview(array $event_ids)
2331
+	{
2332
+		$event_ids = $this->cleanEventIds($event_ids);
2333
+		// Set a code we can use to reference this deletion task in the batch jobs and preview page.
2334
+		$deletion_job_code = $this->getModelObjNodeGroupPersister()->generateGroupCode();
2335
+		$return_url        = EE_Admin_Page::add_query_args_and_nonce(
2336
+			[
2337
+				'action'            => 'preview_deletion',
2338
+				'deletion_job_code' => $deletion_job_code,
2339
+			],
2340
+			$this->_admin_base_url
2341
+		);
2342
+		EEH_URL::safeRedirectAndExit(
2343
+			EE_Admin_Page::add_query_args_and_nonce(
2344
+				[
2345
+					'page'              => EED_Batch::PAGE_SLUG,
2346
+					'batch'             => EED_Batch::batch_job,
2347
+					'EVT_IDs'           => $event_ids,
2348
+					'deletion_job_code' => $deletion_job_code,
2349
+					'job_handler'       => urlencode('EventEspressoBatchRequest\JobHandlers\PreviewEventDeletion'),
2350
+					'return_url'        => urlencode($return_url),
2351
+				],
2352
+				admin_url()
2353
+			)
2354
+		);
2355
+	}
2356
+
2357
+
2358
+	/**
2359
+	 * Checks for a POST submission
2360
+	 *
2361
+	 * @since 4.10.12.p
2362
+	 */
2363
+	protected function confirmDeletion()
2364
+	{
2365
+		$deletion_redirect_logic =
2366
+			$this->getLoader()->getShared('\EventEspresso\core\domain\services\admin\events\data\ConfirmDeletion');
2367
+		$deletion_redirect_logic->handle($this->get_request_data(), $this->admin_base_url());
2368
+	}
2369
+
2370
+
2371
+	/**
2372
+	 * A page for users to preview what exactly will be deleted, and confirm they want to delete it.
2373
+	 *
2374
+	 * @throws EE_Error
2375
+	 * @since 4.10.12.p
2376
+	 */
2377
+	protected function previewDeletion()
2378
+	{
2379
+		$preview_deletion_logic =
2380
+			$this->getLoader()->getShared('\EventEspresso\core\domain\services\admin\events\data\PreviewDeletion');
2381
+		$this->set_template_args($preview_deletion_logic->handle($this->get_request_data(), $this->admin_base_url()));
2382
+		$this->display_admin_page_with_no_sidebar();
2383
+	}
2384
+
2385
+
2386
+	/**
2387
+	 * get total number of events
2388
+	 *
2389
+	 * @access public
2390
+	 * @return int
2391
+	 * @throws EE_Error
2392
+	 * @throws EE_Error
2393
+	 */
2394
+	public function total_events()
2395
+	{
2396
+		return EEM_Event::instance()->count(
2397
+			['caps' => 'read_admin'],
2398
+			'EVT_ID',
2399
+			true
2400
+		);
2401
+	}
2402
+
2403
+
2404
+	/**
2405
+	 * get total number of draft events
2406
+	 *
2407
+	 * @access public
2408
+	 * @return int
2409
+	 * @throws EE_Error
2410
+	 * @throws EE_Error
2411
+	 */
2412
+	public function total_events_draft()
2413
+	{
2414
+		return EEM_Event::instance()->count(
2415
+			[
2416
+				['status' => ['IN', ['draft', 'auto-draft']]],
2417
+				'caps' => 'read_admin',
2418
+			],
2419
+			'EVT_ID',
2420
+			true
2421
+		);
2422
+	}
2423
+
2424
+
2425
+	/**
2426
+	 * get total number of trashed events
2427
+	 *
2428
+	 * @access public
2429
+	 * @return int
2430
+	 * @throws EE_Error
2431
+	 * @throws EE_Error
2432
+	 */
2433
+	public function total_trashed_events()
2434
+	{
2435
+		return EEM_Event::instance()->count(
2436
+			[
2437
+				['status' => 'trash'],
2438
+				'caps' => 'read_admin',
2439
+			],
2440
+			'EVT_ID',
2441
+			true
2442
+		);
2443
+	}
2444
+
2445
+
2446
+	/**
2447
+	 *    _default_event_settings
2448
+	 *    This generates the Default Settings Tab
2449
+	 *
2450
+	 * @return void
2451
+	 * @throws DomainException
2452
+	 * @throws EE_Error
2453
+	 * @throws InvalidArgumentException
2454
+	 * @throws InvalidDataTypeException
2455
+	 * @throws InvalidInterfaceException
2456
+	 */
2457
+	protected function _default_event_settings()
2458
+	{
2459
+		$this->_set_add_edit_form_tags('update_default_event_settings');
2460
+		$this->_set_publish_post_box_vars(null, false, false, null, false);
2461
+		$this->_template_args['admin_page_content'] = EEH_HTML::div(
2462
+			$this->_default_event_settings_form()->get_html(),
2463
+			'',
2464
+			'padding'
2465
+		);
2466
+		$this->display_admin_page_with_sidebar();
2467
+	}
2468
+
2469
+
2470
+	/**
2471
+	 * Return the form for event settings.
2472
+	 *
2473
+	 * @return EE_Form_Section_Proper
2474
+	 * @throws EE_Error
2475
+	 */
2476
+	protected function _default_event_settings_form()
2477
+	{
2478
+		$registration_config              = EE_Registry::instance()->CFG->registration;
2479
+		$registration_stati_for_selection = EEM_Registration::reg_status_array(
2480
+		// exclude
2481
+			[
2482
+				EEM_Registration::status_id_cancelled,
2483
+				EEM_Registration::status_id_declined,
2484
+				EEM_Registration::status_id_incomplete,
2485
+				EEM_Registration::status_id_wait_list,
2486
+			],
2487
+			true
2488
+		);
2489
+		// setup Advanced Editor ???
2490
+		if (
2491
+			$this->raw_req_action === 'default_event_settings'
2492
+			|| $this->raw_req_action === 'update_default_event_settings'
2493
+		) {
2494
+			$this->advanced_editor_admin_form = $this->loader->getShared(AdvancedEditorAdminFormSection::class);
2495
+		}
2496
+		return new EE_Form_Section_Proper(
2497
+			[
2498
+				'name'            => 'update_default_event_settings',
2499
+				'html_id'         => 'update_default_event_settings',
2500
+				'html_class'      => 'form-table',
2501
+				'layout_strategy' => new EE_Admin_Two_Column_Layout(),
2502
+				'subsections'     => apply_filters(
2503
+					'FHEE__Events_Admin_Page___default_event_settings_form__form_subsections',
2504
+					[
2505
+						'defaults_section_header' => new EE_Form_Section_HTML(
2506
+							EEH_HTML::h2(
2507
+								esc_html__('Default Settings', 'event_espresso'),
2508
+								'',
2509
+								'ee-admin-settings-hdr'
2510
+							)
2511
+						),
2512
+						'default_reg_status'  => new EE_Select_Input(
2513
+							$registration_stati_for_selection,
2514
+							[
2515
+								'default'         => isset($registration_config->default_STS_ID)
2516
+													 && array_key_exists(
2517
+														 $registration_config->default_STS_ID,
2518
+														 $registration_stati_for_selection
2519
+													 )
2520
+									? sanitize_text_field($registration_config->default_STS_ID)
2521
+									: EEM_Registration::status_id_pending_payment,
2522
+								'html_label_text' => esc_html__('Default Registration Status', 'event_espresso')
2523
+													 . EEH_Template::get_help_tab_link(
2524
+														 'default_settings_status_help_tab'
2525
+													 ),
2526
+								'html_help_text'  => esc_html__(
2527
+									'This setting allows you to preselect what the default registration status setting is when creating an event.  Note that changing this setting does NOT retroactively apply it to existing events.',
2528
+									'event_espresso'
2529
+								),
2530
+							]
2531
+						),
2532
+						'default_max_tickets' => new EE_Integer_Input(
2533
+							[
2534
+								'default'         => isset($registration_config->default_maximum_number_of_tickets)
2535
+									? $registration_config->default_maximum_number_of_tickets
2536
+									: EEM_Event::get_default_additional_limit(),
2537
+								'html_label_text' => esc_html__(
2538
+									'Default Maximum Tickets Allowed Per Order:',
2539
+									'event_espresso'
2540
+								)
2541
+													 . EEH_Template::get_help_tab_link(
2542
+														 'default_maximum_tickets_help_tab"'
2543
+													 ),
2544
+								'html_help_text'  => esc_html__(
2545
+									'This setting allows you to indicate what will be the default for the maximum number of tickets per order when creating new events.',
2546
+									'event_espresso'
2547
+								),
2548
+							]
2549
+						),
2550
+					]
2551
+				),
2552
+			]
2553
+		);
2554
+	}
2555
+
2556
+
2557
+	/**
2558
+	 * @return void
2559
+	 * @throws EE_Error
2560
+	 * @throws InvalidArgumentException
2561
+	 * @throws InvalidDataTypeException
2562
+	 * @throws InvalidInterfaceException
2563
+	 */
2564
+	protected function _update_default_event_settings()
2565
+	{
2566
+		$form = $this->_default_event_settings_form();
2567
+		if ($form->was_submitted()) {
2568
+			$form->receive_form_submission();
2569
+			if ($form->is_valid()) {
2570
+				$registration_config = EE_Registry::instance()->CFG->registration;
2571
+				$valid_data          = $form->valid_data();
2572
+				if (isset($valid_data['default_reg_status'])) {
2573
+					$registration_config->default_STS_ID = $valid_data['default_reg_status'];
2574
+				}
2575
+				if (isset($valid_data['default_max_tickets'])) {
2576
+					$registration_config->default_maximum_number_of_tickets = $valid_data['default_max_tickets'];
2577
+				}
2578
+				do_action(
2579
+					'AHEE__Events_Admin_Page___update_default_event_settings',
2580
+					$valid_data,
2581
+					EE_Registry::instance()->CFG,
2582
+					$this
2583
+				);
2584
+				// update because data was valid!
2585
+				EE_Registry::instance()->CFG->update_espresso_config();
2586
+				EE_Error::overwrite_success();
2587
+				EE_Error::add_success(
2588
+					esc_html__('Default Event Settings were updated', 'event_espresso')
2589
+				);
2590
+			}
2591
+		}
2592
+		$this->_redirect_after_action(0, '', '', ['action' => 'default_event_settings'], true);
2593
+	}
2594
+
2595
+
2596
+	/*************        Templates        *************
21 2597
      *
22
-     * @var EE_Event $_event
23
-     */
24
-    protected $_event;
25
-
26
-
27
-    /**
28
-     * This will hold the category object for category_details screen.
29
-     *
30
-     * @var stdClass $_category
31
-     */
32
-    protected $_category;
33
-
34
-
35
-    /**
36
-     * This will hold the event model instance
37
-     *
38
-     * @var EEM_Event $_event_model
39
-     */
40
-    protected $_event_model;
41
-
42
-
43
-    /**
44
-     * @var EE_Event
45
-     */
46
-    protected $_cpt_model_obj = false;
47
-
48
-
49
-    /**
50
-     * @var NodeGroupDao
51
-     */
52
-    protected $model_obj_node_group_persister;
53
-
54
-    /**
55
-     * @var AdvancedEditorAdminFormSection
56
-     */
57
-    protected $advanced_editor_admin_form;
58
-
59
-
60
-    /**
61
-     * Initialize page props for this admin page group.
62
-     */
63
-    protected function _init_page_props()
64
-    {
65
-        $this->page_slug        = EVENTS_PG_SLUG;
66
-        $this->page_label       = EVENTS_LABEL;
67
-        $this->_admin_base_url  = EVENTS_ADMIN_URL;
68
-        $this->_admin_base_path = EVENTS_ADMIN;
69
-        $this->_cpt_model_names = [
70
-            'create_new' => 'EEM_Event',
71
-            'edit'       => 'EEM_Event',
72
-        ];
73
-        $this->_cpt_edit_routes = [
74
-            'espresso_events' => 'edit',
75
-        ];
76
-        add_action(
77
-            'AHEE__EE_Admin_Page_CPT__set_model_object__after_set_object',
78
-            [$this, 'verify_event_edit'],
79
-            10,
80
-            2
81
-        );
82
-    }
83
-
84
-
85
-    /**
86
-     * Sets the ajax hooks used for this admin page group.
87
-     */
88
-    protected function _ajax_hooks()
89
-    {
90
-        add_action('wp_ajax_ee_save_timezone_setting', [$this, 'saveTimezoneString']);
91
-    }
92
-
93
-
94
-    /**
95
-     * Sets the page properties for this admin page group.
96
-     */
97
-    protected function _define_page_props()
98
-    {
99
-        $this->_admin_page_title = EVENTS_LABEL;
100
-        $this->_labels           = [
101
-            'buttons'      => [
102
-                'add'             => esc_html__('Add New Event', 'event_espresso'),
103
-                'edit'            => esc_html__('Edit Event', 'event_espresso'),
104
-                'delete'          => esc_html__('Delete Event', 'event_espresso'),
105
-                'add_category'    => esc_html__('Add New Category', 'event_espresso'),
106
-                'edit_category'   => esc_html__('Edit Category', 'event_espresso'),
107
-                'delete_category' => esc_html__('Delete Category', 'event_espresso'),
108
-            ],
109
-            'editor_title' => [
110
-                'espresso_events' => esc_html__('Enter event title here', 'event_espresso'),
111
-            ],
112
-            'publishbox'   => [
113
-                'create_new'        => esc_html__('Save New Event', 'event_espresso'),
114
-                'edit'              => esc_html__('Update Event', 'event_espresso'),
115
-                'add_category'      => esc_html__('Save New Category', 'event_espresso'),
116
-                'edit_category'     => esc_html__('Update Category', 'event_espresso'),
117
-                'template_settings' => esc_html__('Update Settings', 'event_espresso'),
118
-            ],
119
-        ];
120
-    }
121
-
122
-
123
-    /**
124
-     * Sets the page routes property for this admin page group.
125
-     */
126
-    protected function _set_page_routes()
127
-    {
128
-        // load formatter helper
129
-        // load field generator helper
130
-        // is there a evt_id in the request?
131
-        $EVT_ID = $this->request->getRequestParam('EVT_ID', 0, 'int');
132
-        $EVT_ID = $this->request->getRequestParam('post', $EVT_ID, 'int');
133
-
134
-        $this->_page_routes = [
135
-            'default'                       => [
136
-                'func'       => '_events_overview_list_table',
137
-                'capability' => 'ee_read_events',
138
-            ],
139
-            'create_new'                    => [
140
-                'func'       => '_create_new_cpt_item',
141
-                'capability' => 'ee_edit_events',
142
-            ],
143
-            'edit'                          => [
144
-                'func'       => '_edit_cpt_item',
145
-                'capability' => 'ee_edit_event',
146
-                'obj_id'     => $EVT_ID,
147
-            ],
148
-            'copy_event'                    => [
149
-                'func'       => '_copy_events',
150
-                'capability' => 'ee_edit_event',
151
-                'obj_id'     => $EVT_ID,
152
-                'noheader'   => true,
153
-            ],
154
-            'trash_event'                   => [
155
-                'func'       => '_trash_or_restore_event',
156
-                'args'       => ['event_status' => 'trash'],
157
-                'capability' => 'ee_delete_event',
158
-                'obj_id'     => $EVT_ID,
159
-                'noheader'   => true,
160
-            ],
161
-            'trash_events'                  => [
162
-                'func'       => '_trash_or_restore_events',
163
-                'args'       => ['event_status' => 'trash'],
164
-                'capability' => 'ee_delete_events',
165
-                'noheader'   => true,
166
-            ],
167
-            'restore_event'                 => [
168
-                'func'       => '_trash_or_restore_event',
169
-                'args'       => ['event_status' => 'draft'],
170
-                'capability' => 'ee_delete_event',
171
-                'obj_id'     => $EVT_ID,
172
-                'noheader'   => true,
173
-            ],
174
-            'restore_events'                => [
175
-                'func'       => '_trash_or_restore_events',
176
-                'args'       => ['event_status' => 'draft'],
177
-                'capability' => 'ee_delete_events',
178
-                'noheader'   => true,
179
-            ],
180
-            'delete_event'                  => [
181
-                'func'       => '_delete_event',
182
-                'capability' => 'ee_delete_event',
183
-                'obj_id'     => $EVT_ID,
184
-                'noheader'   => true,
185
-            ],
186
-            'delete_events'                 => [
187
-                'func'       => '_delete_events',
188
-                'capability' => 'ee_delete_events',
189
-                'noheader'   => true,
190
-            ],
191
-            'view_report'                   => [
192
-                'func'       => '_view_report',
193
-                'capability' => 'ee_edit_events',
194
-            ],
195
-            'default_event_settings'        => [
196
-                'func'       => '_default_event_settings',
197
-                'capability' => 'manage_options',
198
-            ],
199
-            'update_default_event_settings' => [
200
-                'func'       => '_update_default_event_settings',
201
-                'capability' => 'manage_options',
202
-                'noheader'   => true,
203
-            ],
204
-            'template_settings'             => [
205
-                'func'       => '_template_settings',
206
-                'capability' => 'manage_options',
207
-            ],
208
-            // event category tab related
209
-            'add_category'                  => [
210
-                'func'       => '_category_details',
211
-                'capability' => 'ee_edit_event_category',
212
-                'args'       => ['add'],
213
-            ],
214
-            'edit_category'                 => [
215
-                'func'       => '_category_details',
216
-                'capability' => 'ee_edit_event_category',
217
-                'args'       => ['edit'],
218
-            ],
219
-            'delete_categories'             => [
220
-                'func'       => '_delete_categories',
221
-                'capability' => 'ee_delete_event_category',
222
-                'noheader'   => true,
223
-            ],
224
-            'delete_category'               => [
225
-                'func'       => '_delete_categories',
226
-                'capability' => 'ee_delete_event_category',
227
-                'noheader'   => true,
228
-            ],
229
-            'insert_category'               => [
230
-                'func'       => '_insert_or_update_category',
231
-                'args'       => ['new_category' => true],
232
-                'capability' => 'ee_edit_event_category',
233
-                'noheader'   => true,
234
-            ],
235
-            'update_category'               => [
236
-                'func'       => '_insert_or_update_category',
237
-                'args'       => ['new_category' => false],
238
-                'capability' => 'ee_edit_event_category',
239
-                'noheader'   => true,
240
-            ],
241
-            'category_list'                 => [
242
-                'func'       => '_category_list_table',
243
-                'capability' => 'ee_manage_event_categories',
244
-            ],
245
-            'preview_deletion'              => [
246
-                'func'       => 'previewDeletion',
247
-                'capability' => 'ee_delete_events',
248
-            ],
249
-            'confirm_deletion'              => [
250
-                'func'       => 'confirmDeletion',
251
-                'capability' => 'ee_delete_events',
252
-                'noheader'   => true,
253
-            ],
254
-        ];
255
-    }
256
-
257
-
258
-    /**
259
-     * Set the _page_config property for this admin page group.
260
-     */
261
-    protected function _set_page_config()
262
-    {
263
-        $post_id            = $this->request->getRequestParam('post', 0, 'int');
264
-        $EVT_CAT_ID         = $this->request->getRequestParam('EVT_CAT_ID', 0, 'int');
265
-        $this->_page_config = [
266
-            'default'                => [
267
-                'nav'           => [
268
-                    'label' => esc_html__('Overview', 'event_espresso'),
269
-                    'icon' => 'dashicons-list-view',
270
-                    'order' => 10,
271
-                ],
272
-                'list_table'    => 'Events_Admin_List_Table',
273
-                'help_tabs'     => [
274
-                    'events_overview_help_tab'                       => [
275
-                        'title'    => esc_html__('Events Overview', 'event_espresso'),
276
-                        'filename' => 'events_overview',
277
-                    ],
278
-                    'events_overview_table_column_headings_help_tab' => [
279
-                        'title'    => esc_html__('Events Overview Table Column Headings', 'event_espresso'),
280
-                        'filename' => 'events_overview_table_column_headings',
281
-                    ],
282
-                    'events_overview_filters_help_tab'               => [
283
-                        'title'    => esc_html__('Events Overview Filters', 'event_espresso'),
284
-                        'filename' => 'events_overview_filters',
285
-                    ],
286
-                    'events_overview_view_help_tab'                  => [
287
-                        'title'    => esc_html__('Events Overview Views', 'event_espresso'),
288
-                        'filename' => 'events_overview_views',
289
-                    ],
290
-                    'events_overview_other_help_tab'                 => [
291
-                        'title'    => esc_html__('Events Overview Other', 'event_espresso'),
292
-                        'filename' => 'events_overview_other',
293
-                    ],
294
-                ],
295
-                'require_nonce' => false,
296
-            ],
297
-            'create_new'             => [
298
-                'nav'           => [
299
-                    'label'      => esc_html__('Add New Event', 'event_espresso'),
300
-                    'icon' => 'dashicons-plus-alt',
301
-                    'order'      => 5,
302
-                    'persistent' => false,
303
-                ],
304
-                'metaboxes'     => ['_register_event_editor_meta_boxes'],
305
-                'help_tabs'     => [
306
-                    'event_editor_help_tab'                            => [
307
-                        'title'    => esc_html__('Event Editor', 'event_espresso'),
308
-                        'filename' => 'event_editor',
309
-                    ],
310
-                    'event_editor_title_richtexteditor_help_tab'       => [
311
-                        'title'    => esc_html__('Event Title & Rich Text Editor', 'event_espresso'),
312
-                        'filename' => 'event_editor_title_richtexteditor',
313
-                    ],
314
-                    'event_editor_venue_details_help_tab'              => [
315
-                        'title'    => esc_html__('Event Venue Details', 'event_espresso'),
316
-                        'filename' => 'event_editor_venue_details',
317
-                    ],
318
-                    'event_editor_event_datetimes_help_tab'            => [
319
-                        'title'    => esc_html__('Event Datetimes', 'event_espresso'),
320
-                        'filename' => 'event_editor_event_datetimes',
321
-                    ],
322
-                    'event_editor_event_tickets_help_tab'              => [
323
-                        'title'    => esc_html__('Event Tickets', 'event_espresso'),
324
-                        'filename' => 'event_editor_event_tickets',
325
-                    ],
326
-                    'event_editor_event_registration_options_help_tab' => [
327
-                        'title'    => esc_html__('Event Registration Options', 'event_espresso'),
328
-                        'filename' => 'event_editor_event_registration_options',
329
-                    ],
330
-                    'event_editor_tags_categories_help_tab'            => [
331
-                        'title'    => esc_html__('Event Tags & Categories', 'event_espresso'),
332
-                        'filename' => 'event_editor_tags_categories',
333
-                    ],
334
-                    'event_editor_questions_registrants_help_tab'      => [
335
-                        'title'    => esc_html__('Questions for Registrants', 'event_espresso'),
336
-                        'filename' => 'event_editor_questions_registrants',
337
-                    ],
338
-                    'event_editor_save_new_event_help_tab'             => [
339
-                        'title'    => esc_html__('Save New Event', 'event_espresso'),
340
-                        'filename' => 'event_editor_save_new_event',
341
-                    ],
342
-                    'event_editor_other_help_tab'                      => [
343
-                        'title'    => esc_html__('Event Other', 'event_espresso'),
344
-                        'filename' => 'event_editor_other',
345
-                    ],
346
-                ],
347
-                'qtips'         => ['EE_Event_Editor_Decaf_Tips'],
348
-                'require_nonce' => false,
349
-            ],
350
-            'edit'                   => [
351
-                'nav'           => [
352
-                    'label'      => esc_html__('Edit Event', 'event_espresso'),
353
-                    'icon' => 'dashicons-edit',
354
-                    'order'      => 5,
355
-                    'persistent' => false,
356
-                    'url'        => $post_id
357
-                        ? EE_Admin_Page::add_query_args_and_nonce(
358
-                            ['post' => $post_id, 'action' => 'edit'],
359
-                            $this->_current_page_view_url
360
-                        )
361
-                        : $this->_admin_base_url,
362
-                ],
363
-                'metaboxes'     => ['_register_event_editor_meta_boxes'],
364
-                'help_tabs'     => [
365
-                    'event_editor_help_tab'                            => [
366
-                        'title'    => esc_html__('Event Editor', 'event_espresso'),
367
-                        'filename' => 'event_editor',
368
-                    ],
369
-                    'event_editor_title_richtexteditor_help_tab'       => [
370
-                        'title'    => esc_html__('Event Title & Rich Text Editor', 'event_espresso'),
371
-                        'filename' => 'event_editor_title_richtexteditor',
372
-                    ],
373
-                    'event_editor_venue_details_help_tab'              => [
374
-                        'title'    => esc_html__('Event Venue Details', 'event_espresso'),
375
-                        'filename' => 'event_editor_venue_details',
376
-                    ],
377
-                    'event_editor_event_datetimes_help_tab'            => [
378
-                        'title'    => esc_html__('Event Datetimes', 'event_espresso'),
379
-                        'filename' => 'event_editor_event_datetimes',
380
-                    ],
381
-                    'event_editor_event_tickets_help_tab'              => [
382
-                        'title'    => esc_html__('Event Tickets', 'event_espresso'),
383
-                        'filename' => 'event_editor_event_tickets',
384
-                    ],
385
-                    'event_editor_event_registration_options_help_tab' => [
386
-                        'title'    => esc_html__('Event Registration Options', 'event_espresso'),
387
-                        'filename' => 'event_editor_event_registration_options',
388
-                    ],
389
-                    'event_editor_tags_categories_help_tab'            => [
390
-                        'title'    => esc_html__('Event Tags & Categories', 'event_espresso'),
391
-                        'filename' => 'event_editor_tags_categories',
392
-                    ],
393
-                    'event_editor_questions_registrants_help_tab'      => [
394
-                        'title'    => esc_html__('Questions for Registrants', 'event_espresso'),
395
-                        'filename' => 'event_editor_questions_registrants',
396
-                    ],
397
-                    'event_editor_save_new_event_help_tab'             => [
398
-                        'title'    => esc_html__('Save New Event', 'event_espresso'),
399
-                        'filename' => 'event_editor_save_new_event',
400
-                    ],
401
-                    'event_editor_other_help_tab'                      => [
402
-                        'title'    => esc_html__('Event Other', 'event_espresso'),
403
-                        'filename' => 'event_editor_other',
404
-                    ],
405
-                ],
406
-                'require_nonce' => false,
407
-            ],
408
-            'default_event_settings' => [
409
-                'nav'           => [
410
-                    'label' => esc_html__('Default Settings', 'event_espresso'),
411
-                    'icon' => 'dashicons-admin-generic',
412
-                    'order' => 40,
413
-                ],
414
-                'metaboxes'     => array_merge(['_publish_post_box'], $this->_default_espresso_metaboxes),
415
-                'labels'        => [
416
-                    'publishbox' => esc_html__('Update Settings', 'event_espresso'),
417
-                ],
418
-                'help_tabs'     => [
419
-                    'default_settings_help_tab'        => [
420
-                        'title'    => esc_html__('Default Event Settings', 'event_espresso'),
421
-                        'filename' => 'events_default_settings',
422
-                    ],
423
-                    'default_settings_status_help_tab' => [
424
-                        'title'    => esc_html__('Default Registration Status', 'event_espresso'),
425
-                        'filename' => 'events_default_settings_status',
426
-                    ],
427
-                    'default_maximum_tickets_help_tab' => [
428
-                        'title'    => esc_html__('Default Maximum Tickets Per Order', 'event_espresso'),
429
-                        'filename' => 'events_default_settings_max_tickets',
430
-                    ],
431
-                ],
432
-                'require_nonce' => false,
433
-            ],
434
-            // template settings
435
-            'template_settings'      => [
436
-                'nav'           => [
437
-                    'label' => esc_html__( 'Templates', 'event_espresso'),
438
-                    'icon' => 'dashicons-layout',
439
-                    'order' => 30,
440
-                ],
441
-                'metaboxes'     => $this->_default_espresso_metaboxes,
442
-                'help_tabs'     => [
443
-                    'general_settings_templates_help_tab' => [
444
-                        'title'    => esc_html__('Templates', 'event_espresso'),
445
-                        'filename' => 'general_settings_templates',
446
-                    ],
447
-                ],
448
-                'require_nonce' => false,
449
-            ],
450
-            // event category stuff
451
-            'add_category'           => [
452
-                'nav'           => [
453
-                    'label'      => esc_html__('Add Category', 'event_espresso'),
454
-                    'icon' => 'dashicons-plus-alt',
455
-                    'order'      => 25,
456
-                    'persistent' => false,
457
-                ],
458
-                'help_tabs'     => [
459
-                    'add_category_help_tab' => [
460
-                        'title'    => esc_html__('Add New Event Category', 'event_espresso'),
461
-                        'filename' => 'events_add_category',
462
-                    ],
463
-                ],
464
-                'metaboxes'     => ['_publish_post_box'],
465
-                'require_nonce' => false,
466
-            ],
467
-            'edit_category'          => [
468
-                'nav'           => [
469
-                    'label'      => esc_html__('Edit Category', 'event_espresso'),
470
-                    'icon' => 'dashicons-edit',
471
-                    'order'      => 25,
472
-                    'persistent' => false,
473
-                    'url'        => $EVT_CAT_ID
474
-                        ? add_query_arg(
475
-                            ['EVT_CAT_ID' => $EVT_CAT_ID],
476
-                            $this->_current_page_view_url
477
-                        )
478
-                        : $this->_admin_base_url,
479
-                ],
480
-                'help_tabs'     => [
481
-                    'edit_category_help_tab' => [
482
-                        'title'    => esc_html__('Edit Event Category', 'event_espresso'),
483
-                        'filename' => 'events_edit_category',
484
-                    ],
485
-                ],
486
-                'metaboxes'     => ['_publish_post_box'],
487
-                'require_nonce' => false,
488
-            ],
489
-            'category_list'          => [
490
-                'nav'           => [
491
-                    'label' => esc_html__('Categories', 'event_espresso'),
492
-                    'icon' => 'dashicons-networking',
493
-                    'order' => 20,
494
-                ],
495
-                'list_table'    => 'Event_Categories_Admin_List_Table',
496
-                'help_tabs'     => [
497
-                    'events_categories_help_tab'                       => [
498
-                        'title'    => esc_html__('Event Categories', 'event_espresso'),
499
-                        'filename' => 'events_categories',
500
-                    ],
501
-                    'events_categories_table_column_headings_help_tab' => [
502
-                        'title'    => esc_html__('Event Categories Table Column Headings', 'event_espresso'),
503
-                        'filename' => 'events_categories_table_column_headings',
504
-                    ],
505
-                    'events_categories_view_help_tab'                  => [
506
-                        'title'    => esc_html__('Event Categories Views', 'event_espresso'),
507
-                        'filename' => 'events_categories_views',
508
-                    ],
509
-                    'events_categories_other_help_tab'                 => [
510
-                        'title'    => esc_html__('Event Categories Other', 'event_espresso'),
511
-                        'filename' => 'events_categories_other',
512
-                    ],
513
-                ],
514
-                'metaboxes'     => $this->_default_espresso_metaboxes,
515
-                'require_nonce' => false,
516
-            ],
517
-            'preview_deletion'       => [
518
-                'nav'           => [
519
-                    'label'      => esc_html__('Preview Deletion', 'event_espresso'),
520
-                    'icon' => 'dashicons-remove',
521
-                    'order'      => 15,
522
-                    'persistent' => false,
523
-                    'url'        => '',
524
-                ],
525
-                'require_nonce' => false,
526
-            ],
527
-        ];
528
-    }
529
-
530
-
531
-    /**
532
-     * Used to register any global screen options if necessary for every route in this admin page group.
533
-     */
534
-    protected function _add_screen_options()
535
-    {
536
-    }
537
-
538
-
539
-    /**
540
-     * Implementing the screen options for the 'default' route.
541
-     *
542
-     * @throws InvalidArgumentException
543
-     * @throws InvalidDataTypeException
544
-     * @throws InvalidInterfaceException
545
-     */
546
-    protected function _add_screen_options_default()
547
-    {
548
-        $this->_per_page_screen_option();
549
-    }
550
-
551
-
552
-    /**
553
-     * Implementing screen options for the category list route.
554
-     *
555
-     * @throws InvalidArgumentException
556
-     * @throws InvalidDataTypeException
557
-     * @throws InvalidInterfaceException
558
-     */
559
-    protected function _add_screen_options_category_list()
560
-    {
561
-        $page_title              = $this->_admin_page_title;
562
-        $this->_admin_page_title = esc_html__('Categories', 'event_espresso');
563
-        $this->_per_page_screen_option();
564
-        $this->_admin_page_title = $page_title;
565
-    }
566
-
567
-
568
-    /**
569
-     * Used to register any global feature pointers for the admin page group.
570
-     */
571
-    protected function _add_feature_pointers()
572
-    {
573
-    }
574
-
575
-
576
-    /**
577
-     * Registers and enqueues any global scripts and styles for the entire admin page group.
578
-     */
579
-    public function load_scripts_styles()
580
-    {
581
-        wp_register_style(
582
-            'events-admin-css',
583
-            EVENTS_ASSETS_URL . 'events-admin-page.css',
584
-            [],
585
-            EVENT_ESPRESSO_VERSION
586
-        );
587
-        wp_register_style(
588
-            'ee-cat-admin',
589
-            EVENTS_ASSETS_URL . 'ee-cat-admin.css',
590
-            [],
591
-            EVENT_ESPRESSO_VERSION
592
-        );
593
-        wp_enqueue_style('events-admin-css');
594
-        wp_enqueue_style('ee-cat-admin');
595
-        // scripts
596
-        wp_register_script(
597
-            'event_editor_js',
598
-            EVENTS_ASSETS_URL . 'event_editor.js',
599
-            ['ee_admin_js', 'jquery-ui-slider', 'jquery-ui-timepicker-addon'],
600
-            EVENT_ESPRESSO_VERSION,
601
-            true
602
-        );
603
-    }
604
-
605
-
606
-    /**
607
-     * Enqueuing scripts and styles specific to this view
608
-     */
609
-    public function load_scripts_styles_create_new()
610
-    {
611
-        $this->load_scripts_styles_edit();
612
-    }
613
-
614
-
615
-    /**
616
-     * Enqueuing scripts and styles specific to this view
617
-     */
618
-    public function load_scripts_styles_edit()
619
-    {
620
-        // styles
621
-        wp_enqueue_style('espresso-ui-theme');
622
-        wp_register_style(
623
-            'event-editor-css',
624
-            EVENTS_ASSETS_URL . 'event-editor.css',
625
-            ['ee-admin-css'],
626
-            EVENT_ESPRESSO_VERSION
627
-        );
628
-        wp_enqueue_style('event-editor-css');
629
-        // scripts
630
-        if (! $this->admin_config->useAdvancedEditor()) {
631
-            wp_register_script(
632
-                'event-datetime-metabox',
633
-                EVENTS_ASSETS_URL . 'event-datetime-metabox.js',
634
-                ['event_editor_js', 'ee-datepicker'],
635
-                EVENT_ESPRESSO_VERSION
636
-            );
637
-            wp_enqueue_script('event-datetime-metabox');
638
-        }
639
-    }
640
-
641
-
642
-    /**
643
-     * Populating the _views property for the category list table view.
644
-     */
645
-    protected function _set_list_table_views_category_list()
646
-    {
647
-        $this->_views = [
648
-            'all' => [
649
-                'slug'        => 'all',
650
-                'label'       => esc_html__('All', 'event_espresso'),
651
-                'count'       => 0,
652
-                'bulk_action' => [
653
-                    'delete_categories' => esc_html__('Delete Permanently', 'event_espresso'),
654
-                ],
655
-            ],
656
-        ];
657
-    }
658
-
659
-
660
-    /**
661
-     * For adding anything that fires on the admin_init hook for any route within this admin page group.
662
-     */
663
-    public function admin_init()
664
-    {
665
-        EE_Registry::$i18n_js_strings['image_confirm'] = esc_html__(
666
-            'Do you really want to delete this image? Please remember to update your event to complete the removal.',
667
-            'event_espresso'
668
-        );
669
-    }
670
-
671
-
672
-    /**
673
-     * For adding anything that should be triggered on the admin_notices hook for any route within this admin page
674
-     * group.
675
-     */
676
-    public function admin_notices()
677
-    {
678
-    }
679
-
680
-
681
-    /**
682
-     * For adding anything that should be triggered on the `admin_print_footer_scripts` hook for any route within
683
-     * this admin page group.
684
-     */
685
-    public function admin_footer_scripts()
686
-    {
687
-    }
688
-
689
-
690
-    /**
691
-     * Call this function to verify if an event is public and has tickets for sale.  If it does, then we need to show a
692
-     * warning (via EE_Error::add_error());
693
-     *
694
-     * @param EE_Event $event Event object
695
-     * @param string   $req_type
696
-     * @return void
697
-     * @throws EE_Error
698
-     * @throws ReflectionException
699
-     */
700
-    public function verify_event_edit($event = null, $req_type = '')
701
-    {
702
-        // don't need to do this when processing
703
-        if (! empty($req_type)) {
704
-            return;
705
-        }
706
-        // no event?
707
-        if (! $event instanceof EE_Event) {
708
-            $event = $this->_cpt_model_obj;
709
-        }
710
-        // STILL no event?
711
-        if (! $event instanceof EE_Event) {
712
-            return;
713
-        }
714
-        $orig_status = $event->status();
715
-        // first check if event is active.
716
-        if (
717
-            $orig_status === EEM_Event::cancelled
718
-            || $orig_status === EEM_Event::postponed
719
-            || $event->is_expired()
720
-            || $event->is_inactive()
721
-        ) {
722
-            return;
723
-        }
724
-        // made it here so it IS active... next check that any of the tickets are sold.
725
-        if ($event->is_sold_out(true)) {
726
-            if ($orig_status !== EEM_Event::sold_out && $event->status() !== $orig_status) {
727
-                EE_Error::add_attention(
728
-                    sprintf(
729
-                        esc_html__(
730
-                            'Please note that the Event Status has automatically been changed to %s because there are no more spaces available for this event.  However, this change is not permanent until you update the event.  You can change the status back to something else before updating if you wish.',
731
-                            'event_espresso'
732
-                        ),
733
-                        EEH_Template::pretty_status(EEM_Event::sold_out, false, 'sentence')
734
-                    )
735
-                );
736
-            }
737
-            return;
738
-        }
739
-        if ($orig_status === EEM_Event::sold_out) {
740
-            EE_Error::add_attention(
741
-                sprintf(
742
-                    esc_html__(
743
-                        'Please note that the Event Status has automatically been changed to %s because more spaces have become available for this event, most likely due to abandoned transactions freeing up reserved tickets.  However, this change is not permanent until you update the event. If you wish, you can change the status back to something else before updating.',
744
-                        'event_espresso'
745
-                    ),
746
-                    EEH_Template::pretty_status($event->status(), false, 'sentence')
747
-                )
748
-            );
749
-        }
750
-        // now we need to determine if the event has any tickets on sale.  If not then we dont' show the error
751
-        if (! $event->tickets_on_sale()) {
752
-            return;
753
-        }
754
-        // made it here so show warning
755
-        $this->_edit_event_warning();
756
-    }
757
-
758
-
759
-    /**
760
-     * This is the text used for when an event is being edited that is public and has tickets for sale.
761
-     * When needed, hook this into a EE_Error::add_error() notice.
762
-     *
763
-     * @access protected
764
-     * @return void
765
-     */
766
-    protected function _edit_event_warning()
767
-    {
768
-        // we don't want to add warnings during these requests
769
-        if ($this->request->getRequestParam('action') === 'editpost') {
770
-            return;
771
-        }
772
-        EE_Error::add_attention(
773
-            sprintf(
774
-                esc_html__(
775
-                    'Your event is open for registration. Making changes may disrupt any transactions in progress. %sLearn more%s',
776
-                    'event_espresso'
777
-                ),
778
-                '<a class="espresso-help-tab-lnk ee-help-tab-link">',
779
-                '</a>'
780
-            )
781
-        );
782
-    }
783
-
784
-
785
-    /**
786
-     * When a user is creating a new event, notify them if they haven't set their timezone.
787
-     * Otherwise, do the normal logic
788
-     *
789
-     * @return void
790
-     * @throws EE_Error
791
-     * @throws InvalidArgumentException
792
-     * @throws InvalidDataTypeException
793
-     * @throws InvalidInterfaceException
794
-     */
795
-    protected function _create_new_cpt_item()
796
-    {
797
-        $has_timezone_string = get_option('timezone_string');
798
-        // only nag them about setting their timezone if it's their first event, and they haven't already done it
799
-        if (! $has_timezone_string && ! EEM_Event::instance()->exists([])) {
800
-            EE_Error::add_attention(
801
-                sprintf(
802
-                    esc_html__(
803
-                        'Your website\'s timezone is currently set to a UTC offset. We recommend updating your timezone to a city or region near you before you create an event. Change your timezone now:%1$s%2$s%3$sChange Timezone%4$s',
804
-                        'event_espresso'
805
-                    ),
806
-                    '<br>',
807
-                    '<select id="timezone_string" name="timezone_string" aria-describedby="timezone-description">'
808
-                    . EEH_DTT_Helper::wp_timezone_choice('', EEH_DTT_Helper::get_user_locale())
809
-                    . '</select>',
810
-                    '<button class="button button--secondary timezone-submit">',
811
-                    '</button><span class="spinner"></span>'
812
-                ),
813
-                __FILE__,
814
-                __FUNCTION__,
815
-                __LINE__
816
-            );
817
-        }
818
-        parent::_create_new_cpt_item();
819
-    }
820
-
821
-
822
-    /**
823
-     * Sets the _views property for the default route in this admin page group.
824
-     */
825
-    protected function _set_list_table_views_default()
826
-    {
827
-        $this->_views = [
828
-            'all'   => [
829
-                'slug'        => 'all',
830
-                'label'       => esc_html__('View All Events', 'event_espresso'),
831
-                'count'       => 0,
832
-                'bulk_action' => [
833
-                    'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
834
-                ],
835
-            ],
836
-            'draft' => [
837
-                'slug'        => 'draft',
838
-                'label'       => esc_html__('Draft', 'event_espresso'),
839
-                'count'       => 0,
840
-                'bulk_action' => [
841
-                    'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
842
-                ],
843
-            ],
844
-        ];
845
-        if (EE_Registry::instance()->CAP->current_user_can('ee_delete_events', 'espresso_events_trash_events')) {
846
-            $this->_views['trash'] = [
847
-                'slug'        => 'trash',
848
-                'label'       => esc_html__('Trash', 'event_espresso'),
849
-                'count'       => 0,
850
-                'bulk_action' => [
851
-                    'restore_events' => esc_html__('Restore From Trash', 'event_espresso'),
852
-                    'delete_events'  => esc_html__('Delete Permanently', 'event_espresso'),
853
-                ],
854
-            ];
855
-        }
856
-    }
857
-
858
-
859
-    /**
860
-     * Provides the legend item array for the default list table view.
861
-     *
862
-     * @return array
863
-     * @throws EE_Error
864
-     * @throws EE_Error
865
-     */
866
-    protected function _event_legend_items()
867
-    {
868
-        $items    = [
869
-            'view_details'   => [
870
-                'class' => 'dashicons dashicons-visibility',
871
-                'desc'  => esc_html__('View Event', 'event_espresso'),
872
-            ],
873
-            'edit_event'     => [
874
-                'class' => 'dashicons dashicons-calendar-alt',
875
-                'desc'  => esc_html__('Edit Event Details', 'event_espresso'),
876
-            ],
877
-            'view_attendees' => [
878
-                'class' => 'dashicons dashicons-groups',
879
-                'desc'  => esc_html__('View Registrations for Event', 'event_espresso'),
880
-            ],
881
-        ];
882
-        $items    = apply_filters('FHEE__Events_Admin_Page___event_legend_items__items', $items);
883
-        $statuses = [
884
-            'sold_out_status'  => [
885
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::sold_out,
886
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::sold_out, false, 'sentence'),
887
-            ],
888
-            'active_status'    => [
889
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::active,
890
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::active, false, 'sentence'),
891
-            ],
892
-            'upcoming_status'  => [
893
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::upcoming,
894
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::upcoming, false, 'sentence'),
895
-            ],
896
-            'postponed_status' => [
897
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::postponed,
898
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::postponed, false, 'sentence'),
899
-            ],
900
-            'cancelled_status' => [
901
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::cancelled,
902
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::cancelled, false, 'sentence'),
903
-            ],
904
-            'expired_status'   => [
905
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::expired,
906
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::expired, false, 'sentence'),
907
-            ],
908
-            'inactive_status'  => [
909
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::inactive,
910
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::inactive, false, 'sentence'),
911
-            ],
912
-        ];
913
-        $statuses = apply_filters('FHEE__Events_Admin_Page__event_legend_items__statuses', $statuses);
914
-        return array_merge($items, $statuses);
915
-    }
916
-
917
-
918
-    /**
919
-     * @return EEM_Event
920
-     * @throws EE_Error
921
-     * @throws InvalidArgumentException
922
-     * @throws InvalidDataTypeException
923
-     * @throws InvalidInterfaceException
924
-     * @throws ReflectionException
925
-     */
926
-    private function _event_model()
927
-    {
928
-        if (! $this->_event_model instanceof EEM_Event) {
929
-            $this->_event_model = EE_Registry::instance()->load_model('Event');
930
-        }
931
-        return $this->_event_model;
932
-    }
933
-
934
-
935
-    /**
936
-     * Adds extra buttons to the WP CPT permalink field row.
937
-     * Method is called from parent and is hooked into the wp 'get_sample_permalink_html' filter.
938
-     *
939
-     * @param string $return    the current html
940
-     * @param int    $id        the post id for the page
941
-     * @param string $new_title What the title is
942
-     * @param string $new_slug  what the slug is
943
-     * @return string            The new html string for the permalink area
944
-     */
945
-    public function extra_permalink_field_buttons($return, $id, $new_title, $new_slug)
946
-    {
947
-        // make sure this is only when editing
948
-        if (! empty($id)) {
949
-            $post = get_post($id);
950
-            $return .= '<a class="button button--small button--secondary" onclick="prompt(\'Shortcode:\', jQuery(\'#shortcode\').val()); return false;" href="#"  tabindex="-1">'
951
-                       . esc_html__('Shortcode', 'event_espresso')
952
-                       . '</a> ';
953
-            $return .= '<input id="shortcode" type="hidden" value="[ESPRESSO_TICKET_SELECTOR event_id='
954
-                       . $post->ID
955
-                       . ']">';
956
-        }
957
-        return $return;
958
-    }
959
-
960
-
961
-    /**
962
-     * _events_overview_list_table
963
-     * This contains the logic for showing the events_overview list
964
-     *
965
-     * @access protected
966
-     * @return void
967
-     * @throws DomainException
968
-     * @throws EE_Error
969
-     * @throws InvalidArgumentException
970
-     * @throws InvalidDataTypeException
971
-     * @throws InvalidInterfaceException
972
-     */
973
-    protected function _events_overview_list_table()
974
-    {
975
-        $after_list_table                           = [];
976
-        $links_html = EEH_HTML::div('', '', 'ee-admin-section ee-layout-stack');
977
-        $links_html .= EEH_HTML::h3(esc_html__('Links', 'event_espresso'));
978
-        $links_html .= EEH_HTML::div(
979
-            EEH_Template::get_button_or_link(
980
-                get_post_type_archive_link('espresso_events'),
981
-                esc_html__('View Event Archive Page', 'event_espresso'),
982
-                'button button--small button--secondary'
983
-            ),
984
-            '',
985
-            'ee-admin-button-row ee-admin-button-row--align-start'
986
-        );
987
-        $links_html .= EEH_HTML::divx();
988
-
989
-        $after_list_table['view_event_list_button'] = $links_html;
990
-
991
-        $after_list_table['legend'] = $this->_display_legend($this->_event_legend_items());
992
-        $this->_admin_page_title                    .= ' ' . $this->get_action_link_or_button(
993
-            'create_new',
994
-            'add',
995
-            [],
996
-            'add-new-h2'
997
-        );
998
-
999
-        $this->_template_args['after_list_table']   = array_merge(
1000
-            (array) $this->_template_args['after_list_table'],
1001
-            $after_list_table
1002
-        );
1003
-        $this->display_admin_list_table_page_with_no_sidebar();
1004
-    }
1005
-
1006
-
1007
-    /**
1008
-     * this allows for extra misc actions in the default WP publish box
1009
-     *
1010
-     * @return void
1011
-     * @throws DomainException
1012
-     * @throws EE_Error
1013
-     * @throws InvalidArgumentException
1014
-     * @throws InvalidDataTypeException
1015
-     * @throws InvalidInterfaceException
1016
-     * @throws ReflectionException
1017
-     */
1018
-    public function extra_misc_actions_publish_box()
1019
-    {
1020
-        $this->_generate_publish_box_extra_content();
1021
-    }
1022
-
1023
-
1024
-    /**
1025
-     * This is hooked into the WordPress do_action('save_post') hook and runs after the custom post type has been
1026
-     * saved.
1027
-     * Typically you would use this to save any additional data.
1028
-     * Keep in mind also that "save_post" runs on EVERY post update to the database.
1029
-     * ALSO very important.  When a post transitions from scheduled to published,
1030
-     * the save_post action is fired but you will NOT have any _POST data containing any extra info you may have from
1031
-     * other meta saves. So MAKE sure that you handle this accordingly.
1032
-     *
1033
-     * @access protected
1034
-     * @abstract
1035
-     * @param string $post_id The ID of the cpt that was saved (so you can link relationally)
1036
-     * @param WP_Post $post    The post object of the cpt that was saved.
1037
-     * @return void
1038
-     * @throws EE_Error
1039
-     * @throws InvalidArgumentException
1040
-     * @throws InvalidDataTypeException
1041
-     * @throws InvalidInterfaceException
1042
-     * @throws ReflectionException
1043
-     */
1044
-    protected function _insert_update_cpt_item($post_id, $post)
1045
-    {
1046
-        if ($post instanceof WP_Post && $post->post_type !== 'espresso_events') {
1047
-            // get out we're not processing an event save.
1048
-            return;
1049
-        }
1050
-        $event_values = [
1051
-            'EVT_member_only'     => $this->request->getRequestParam('member_only', false, 'bool'),
1052
-            'EVT_allow_overflow'  => $this->request->getRequestParam('EVT_allow_overflow', false, 'bool'),
1053
-            'EVT_timezone_string' => $this->request->getRequestParam('timezone_string'),
1054
-        ];
1055
-        // check if the new EDTR reg options meta box is being used, and if so, don't run updates for legacy version
1056
-        if (! $this->admin_config->useAdvancedEditor() || ! $this->feature->allowed('use_reg_options_meta_box')) {
1057
-            $event_values['EVT_display_ticket_selector']     = $this->request->getRequestParam(
1058
-                'display_ticket_selector',
1059
-                false,
1060
-                'bool'
1061
-            );
1062
-            $event_values['EVT_additional_limit']            = min(
1063
-                apply_filters('FHEE__EE_Events_Admin__insert_update_cpt_item__EVT_additional_limit_max', 255),
1064
-                $this->request->getRequestParam('additional_limit', null, 'int')
1065
-            );
1066
-            $event_values['EVT_default_registration_status'] = $this->request->getRequestParam(
1067
-                'EVT_default_registration_status',
1068
-                EE_Registry::instance()->CFG->registration->default_STS_ID
1069
-            );
1070
-
1071
-            $event_values['EVT_external_URL'] = $this->request->getRequestParam('externalURL');
1072
-            $event_values['EVT_phone']        = $this->request->getRequestParam('event_phone');
1073
-            $event_values['EVT_display_desc'] = $this->request->getRequestParam('display_desc', false, 'bool');
1074
-        }
1075
-        // update event
1076
-        $success = $this->_event_model()->update_by_ID($event_values, $post_id);
1077
-        // get event_object for other metaboxes...
1078
-        // though it would seem to make sense to just use $this->_event_model()->get_one_by_ID( $post_id )..
1079
-        // i have to setup where conditions to override the filters in the model
1080
-        // that filter out autodraft and inherit statuses so we GET the inherit id!
1081
-        $event = $this->_event_model()->get_one(
1082
-            [
1083
-                [
1084
-                    $this->_event_model()->primary_key_name() => $post_id,
1085
-                    'OR'                                      => [
1086
-                        'status'   => $post->post_status,
1087
-                        // if trying to "Publish" a sold out event, it's status will get switched back to "sold_out" in the db,
1088
-                        // but the returned object here has a status of "publish", so use the original post status as well
1089
-                        'status*1' => $this->request->getRequestParam('original_post_status'),
1090
-                    ],
1091
-                ],
1092
-            ]
1093
-        );
1094
-
1095
-        // the following are default callbacks for event attachment updates
1096
-        // that can be overridden by caffeinated functionality and/or addons.
1097
-        $event_update_callbacks = [];
1098
-        if (! $this->admin_config->useAdvancedEditor()) {
1099
-            $event_update_callbacks['_default_venue_update']   = [$this, '_default_venue_update'];
1100
-            $event_update_callbacks['_default_tickets_update'] = [$this, '_default_tickets_update'];
1101
-        }
1102
-        $event_update_callbacks = apply_filters(
1103
-            'FHEE__Events_Admin_Page___insert_update_cpt_item__event_update_callbacks',
1104
-            $event_update_callbacks
1105
-        );
1106
-
1107
-        $att_success = true;
1108
-        foreach ($event_update_callbacks as $e_callback) {
1109
-            $_success = is_callable($e_callback)
1110
-                ? $e_callback($event, $this->request->requestParams())
1111
-                : false;
1112
-            // if ANY of these updates fail then we want the appropriate global error message
1113
-            $att_success = $_success !== false ? $att_success : false;
1114
-        }
1115
-        // any errors?
1116
-        if ($success && $att_success === false) {
1117
-            EE_Error::add_error(
1118
-                esc_html__(
1119
-                    'Event Details saved successfully but something went wrong with saving attachments.',
1120
-                    'event_espresso'
1121
-                ),
1122
-                __FILE__,
1123
-                __FUNCTION__,
1124
-                __LINE__
1125
-            );
1126
-        } elseif ($success === false) {
1127
-            EE_Error::add_error(
1128
-                esc_html__('Event Details did not save successfully.', 'event_espresso'),
1129
-                __FILE__,
1130
-                __FUNCTION__,
1131
-                __LINE__
1132
-            );
1133
-        }
1134
-    }
1135
-
1136
-
1137
-    /**
1138
-     * @param int $post_id
1139
-     * @param int $revision_id
1140
-     * @throws EE_Error
1141
-     * @throws EE_Error
1142
-     * @throws ReflectionException
1143
-     * @see parent::restore_item()
1144
-     */
1145
-    protected function _restore_cpt_item($post_id, $revision_id)
1146
-    {
1147
-        // copy existing event meta to new post
1148
-        $post_evt = $this->_event_model()->get_one_by_ID($post_id);
1149
-        if ($post_evt instanceof EE_Event) {
1150
-            // meta revision restore
1151
-            $post_evt->restore_revision($revision_id);
1152
-            // related objs restore
1153
-            $post_evt->restore_revision($revision_id, ['Venue', 'Datetime', 'Price']);
1154
-        }
1155
-    }
1156
-
1157
-
1158
-    /**
1159
-     * Attach the venue to the Event
1160
-     *
1161
-     * @param EE_Event $event Event Object to add the venue to
1162
-     * @param array    $data  The request data from the form
1163
-     * @return bool           Success or fail.
1164
-     * @throws EE_Error
1165
-     * @throws ReflectionException
1166
-     */
1167
-    protected function _default_venue_update(EE_Event $event, $data)
1168
-    {
1169
-        require_once(EE_MODELS . 'EEM_Venue.model.php');
1170
-        $venue_model = EE_Registry::instance()->load_model('Venue');
1171
-        $venue_id    = ! empty($data['venue_id']) ? $data['venue_id'] : null;
1172
-        // very important.  If we don't have a venue name...
1173
-        // then we'll get out because not necessary to create empty venue
1174
-        if (empty($data['venue_title'])) {
1175
-            return false;
1176
-        }
1177
-        $venue_array = [
1178
-            'VNU_wp_user'         => $event->get('EVT_wp_user'),
1179
-            'VNU_name'            => ! empty($data['venue_title']) ? $data['venue_title'] : null,
1180
-            'VNU_desc'            => ! empty($data['venue_description']) ? $data['venue_description'] : null,
1181
-            'VNU_identifier'      => ! empty($data['venue_identifier']) ? $data['venue_identifier'] : null,
1182
-            'VNU_short_desc'      => ! empty($data['venue_short_description'])
1183
-                ? $data['venue_short_description']
1184
-                : null,
1185
-            'VNU_address'         => ! empty($data['address']) ? $data['address'] : null,
1186
-            'VNU_address2'        => ! empty($data['address2']) ? $data['address2'] : null,
1187
-            'VNU_city'            => ! empty($data['city']) ? $data['city'] : null,
1188
-            'STA_ID'              => ! empty($data['state']) ? $data['state'] : null,
1189
-            'CNT_ISO'             => ! empty($data['countries']) ? $data['countries'] : null,
1190
-            'VNU_zip'             => ! empty($data['zip']) ? $data['zip'] : null,
1191
-            'VNU_phone'           => ! empty($data['venue_phone']) ? $data['venue_phone'] : null,
1192
-            'VNU_capacity'        => ! empty($data['venue_capacity']) ? $data['venue_capacity'] : null,
1193
-            'VNU_url'             => ! empty($data['venue_url']) ? $data['venue_url'] : null,
1194
-            'VNU_virtual_phone'   => ! empty($data['virtual_phone']) ? $data['virtual_phone'] : null,
1195
-            'VNU_virtual_url'     => ! empty($data['virtual_url']) ? $data['virtual_url'] : null,
1196
-            'VNU_enable_for_gmap' => isset($data['enable_for_gmap']) ? 1 : 0,
1197
-            'status'              => 'publish',
1198
-        ];
1199
-        // if we've got the venue_id then we're just updating the existing venue so let's do that and then get out.
1200
-        if (! empty($venue_id)) {
1201
-            $update_where  = [$venue_model->primary_key_name() => $venue_id];
1202
-            $rows_affected = $venue_model->update($venue_array, [$update_where]);
1203
-            // we've gotta make sure that the venue is always attached to a revision..
1204
-            // add_relation_to should take care of making sure that the relation is already present.
1205
-            $event->_add_relation_to($venue_id, 'Venue');
1206
-            return $rows_affected > 0;
1207
-        }
1208
-        // we insert the venue
1209
-        $venue_id = $venue_model->insert($venue_array);
1210
-        $event->_add_relation_to($venue_id, 'Venue');
1211
-        return ! empty($venue_id);
1212
-        // when we have the ancestor come in it's already been handled by the revision save.
1213
-    }
1214
-
1215
-
1216
-    /**
1217
-     * Handles saving everything related to Tickets (datetimes, tickets, prices)
1218
-     *
1219
-     * @param EE_Event $event The Event object we're attaching data to
1220
-     * @param array    $data  The request data from the form
1221
-     * @return array
1222
-     * @throws EE_Error
1223
-     * @throws ReflectionException
1224
-     * @throws Exception
1225
-     */
1226
-    protected function _default_tickets_update(EE_Event $event, $data)
1227
-    {
1228
-        if ($this->admin_config->useAdvancedEditor()) {
1229
-            return [];
1230
-        }
1231
-        $datetime       = null;
1232
-        $saved_tickets  = [];
1233
-        $event_timezone = $event->get_timezone();
1234
-        $date_formats   = ['Y-m-d', 'h:i a'];
1235
-        foreach ($data['edit_event_datetimes'] as $row => $datetime_data) {
1236
-            // trim all values to ensure any excess whitespace is removed.
1237
-            $datetime_data                = array_map('trim', $datetime_data);
1238
-            $datetime_data['DTT_EVT_end'] =
1239
-                isset($datetime_data['DTT_EVT_end']) && ! empty($datetime_data['DTT_EVT_end'])
1240
-                    ? $datetime_data['DTT_EVT_end']
1241
-                    : $datetime_data['DTT_EVT_start'];
1242
-            $datetime_values              = [
1243
-                'DTT_ID'        => ! empty($datetime_data['DTT_ID']) ? $datetime_data['DTT_ID'] : null,
1244
-                'DTT_EVT_start' => $datetime_data['DTT_EVT_start'],
1245
-                'DTT_EVT_end'   => $datetime_data['DTT_EVT_end'],
1246
-                'DTT_reg_limit' => empty($datetime_data['DTT_reg_limit']) ? EE_INF : $datetime_data['DTT_reg_limit'],
1247
-                'DTT_order'     => $row,
1248
-            ];
1249
-            // if we have an id then let's get existing object first and then set the new values.
1250
-            //  Otherwise we instantiate a new object for save.
1251
-            if (! empty($datetime_data['DTT_ID'])) {
1252
-                $datetime = EEM_Datetime::instance($event_timezone)->get_one_by_ID($datetime_data['DTT_ID']);
1253
-                if (! $datetime instanceof EE_Datetime) {
1254
-                    throw new RuntimeException(
1255
-                        sprintf(
1256
-                            esc_html__(
1257
-                                'Something went wrong! A valid Datetime could not be retrieved from the database using the supplied ID: %1$d',
1258
-                                'event_espresso'
1259
-                            ),
1260
-                            $datetime_data['DTT_ID']
1261
-                        )
1262
-                    );
1263
-                }
1264
-                $datetime->set_date_format($date_formats[0]);
1265
-                $datetime->set_time_format($date_formats[1]);
1266
-                foreach ($datetime_values as $field => $value) {
1267
-                    $datetime->set($field, $value);
1268
-                }
1269
-            } else {
1270
-                $datetime = EE_Datetime::new_instance($datetime_values, $event_timezone, $date_formats);
1271
-            }
1272
-            if (! $datetime instanceof EE_Datetime) {
1273
-                throw new RuntimeException(
1274
-                    sprintf(
1275
-                        esc_html__(
1276
-                            'Something went wrong! A valid Datetime could not be generated or retrieved using the supplied data: %1$s',
1277
-                            'event_espresso'
1278
-                        ),
1279
-                        print_r($datetime_values, true)
1280
-                    )
1281
-                );
1282
-            }
1283
-            // before going any further make sure our dates are setup correctly
1284
-            // so that the end date is always equal or greater than the start date.
1285
-            if ($datetime->get_raw('DTT_EVT_start') > $datetime->get_raw('DTT_EVT_end')) {
1286
-                $datetime->set('DTT_EVT_end', $datetime->get('DTT_EVT_start'));
1287
-                $datetime = EEH_DTT_Helper::date_time_add($datetime, 'DTT_EVT_end', 'days');
1288
-            }
1289
-            $datetime->save();
1290
-            $event->_add_relation_to($datetime, 'Datetime');
1291
-        }
1292
-        // no datetimes get deleted so we don't do any of that logic here.
1293
-        // update tickets next
1294
-        $old_tickets = isset($data['ticket_IDs']) ? explode(',', $data['ticket_IDs']) : [];
1295
-
1296
-        // set up some default start and end dates in case those are not present in the incoming data
1297
-        $default_start_date = new DateTime('now', new DateTimeZone($event->get_timezone()));
1298
-        $default_start_date = $default_start_date->format($date_formats[0] . ' ' . $date_formats[1]);
1299
-        // use the start date of the first datetime for the end date
1300
-        $first_datetime   = $event->first_datetime();
1301
-        $default_end_date = $first_datetime->start_date_and_time($date_formats[0], $date_formats[1]);
1302
-
1303
-        // now process the incoming data
1304
-        foreach ($data['edit_tickets'] as $row => $ticket_data) {
1305
-            $update_prices = false;
1306
-            $ticket_price  = isset($data['edit_prices'][ $row ][1]['PRC_amount'])
1307
-                ? $data['edit_prices'][ $row ][1]['PRC_amount']
1308
-                : 0;
1309
-            // trim inputs to ensure any excess whitespace is removed.
1310
-            $ticket_data   = array_map('trim', $ticket_data);
1311
-            $ticket_values = [
1312
-                'TKT_ID'          => ! empty($ticket_data['TKT_ID']) ? $ticket_data['TKT_ID'] : null,
1313
-                'TTM_ID'          => ! empty($ticket_data['TTM_ID']) ? $ticket_data['TTM_ID'] : 0,
1314
-                'TKT_name'        => ! empty($ticket_data['TKT_name']) ? $ticket_data['TKT_name'] : '',
1315
-                'TKT_description' => ! empty($ticket_data['TKT_description']) ? $ticket_data['TKT_description'] : '',
1316
-                'TKT_start_date'  => ! empty($ticket_data['TKT_start_date'])
1317
-                    ? $ticket_data['TKT_start_date']
1318
-                    : $default_start_date,
1319
-                'TKT_end_date'    => ! empty($ticket_data['TKT_end_date'])
1320
-                    ? $ticket_data['TKT_end_date']
1321
-                    : $default_end_date,
1322
-                'TKT_qty'         => ! empty($ticket_data['TKT_qty'])
1323
-                                     || (isset($ticket_data['TKT_qty']) && (int) $ticket_data['TKT_qty'] === 0)
1324
-                    ? $ticket_data['TKT_qty']
1325
-                    : EE_INF,
1326
-                'TKT_uses'        => ! empty($ticket_data['TKT_uses'])
1327
-                                     || (isset($ticket_data['TKT_uses']) && (int) $ticket_data['TKT_uses'] === 0)
1328
-                    ? $ticket_data['TKT_uses']
1329
-                    : EE_INF,
1330
-                'TKT_min'         => ! empty($ticket_data['TKT_min']) ? $ticket_data['TKT_min'] : 0,
1331
-                'TKT_max'         => ! empty($ticket_data['TKT_max']) ? $ticket_data['TKT_max'] : EE_INF,
1332
-                'TKT_order'       => isset($ticket_data['TKT_order']) ? $ticket_data['TKT_order'] : $row,
1333
-                'TKT_price'       => $ticket_price,
1334
-                'TKT_row'         => $row,
1335
-            ];
1336
-            // if this is a default ticket, then we need to set the TKT_ID to 0 and update accordingly,
1337
-            // which means in turn that the prices will become new prices as well.
1338
-            if (isset($ticket_data['TKT_is_default']) && $ticket_data['TKT_is_default']) {
1339
-                $ticket_values['TKT_ID']         = 0;
1340
-                $ticket_values['TKT_is_default'] = 0;
1341
-                $update_prices                   = true;
1342
-            }
1343
-            // if we have a TKT_ID then we need to get that existing TKT_obj and update it
1344
-            // we actually do our saves ahead of adding any relations because its entirely possible that this
1345
-            // ticket didn't get removed or added to any datetime in the session but DID have it's items modified.
1346
-            // keep in mind that if the ticket has been sold (and we have changed pricing information),
1347
-            // then we won't be updating the tkt but instead a new tkt will be created and the old one archived.
1348
-            if (! empty($ticket_data['TKT_ID'])) {
1349
-                $existing_ticket = EEM_Ticket::instance($event_timezone)->get_one_by_ID($ticket_data['TKT_ID']);
1350
-                if (! $existing_ticket instanceof EE_Ticket) {
1351
-                    throw new RuntimeException(
1352
-                        sprintf(
1353
-                            esc_html__(
1354
-                                'Something went wrong! A valid Ticket could not be retrieved from the database using the supplied ID: %1$d',
1355
-                                'event_espresso'
1356
-                            ),
1357
-                            $ticket_data['TKT_ID']
1358
-                        )
1359
-                    );
1360
-                }
1361
-                $ticket_sold = $existing_ticket->count_related(
1362
-                    'Registration',
1363
-                    [
1364
-                            [
1365
-                                'STS_ID' => [
1366
-                                    'NOT IN',
1367
-                                    [EEM_Registration::status_id_incomplete],
1368
-                                ],
1369
-                            ],
1370
-                        ]
1371
-                ) > 0;
1372
-                // let's just check the total price for the existing ticket and determine if it matches the new total price.
1373
-                // if they are different then we create a new ticket (if $ticket_sold)
1374
-                // if they aren't different then we go ahead and modify existing ticket.
1375
-                $create_new_ticket = $ticket_sold
1376
-                                     && $ticket_price !== $existing_ticket->price()
1377
-                                     && ! $existing_ticket->deleted();
1378
-                $existing_ticket->set_date_format($date_formats[0]);
1379
-                $existing_ticket->set_time_format($date_formats[1]);
1380
-                // set new values
1381
-                foreach ($ticket_values as $field => $value) {
1382
-                    if ($field == 'TKT_qty') {
1383
-                        $existing_ticket->set_qty($value);
1384
-                    } elseif ($field == 'TKT_price') {
1385
-                        $existing_ticket->set('TKT_price', $ticket_price);
1386
-                    } else {
1387
-                        $existing_ticket->set($field, $value);
1388
-                    }
1389
-                }
1390
-                $ticket = $existing_ticket;
1391
-                // if $create_new_ticket is false then we can safely update the existing ticket.
1392
-                //  Otherwise we have to create a new ticket.
1393
-                if ($create_new_ticket) {
1394
-                    // archive the old ticket first
1395
-                    $existing_ticket->set('TKT_deleted', 1);
1396
-                    $existing_ticket->save();
1397
-                    // make sure this ticket is still recorded in our $saved_tickets
1398
-                    // so we don't run it through the regular trash routine.
1399
-                    $saved_tickets[ $existing_ticket->ID() ] = $existing_ticket;
1400
-                    // create new ticket that's a copy of the existing except,
1401
-                    // (a new id of course and not archived) AND has the new TKT_price associated with it.
1402
-                    $new_ticket = clone $existing_ticket;
1403
-                    $new_ticket->set('TKT_ID', 0);
1404
-                    $new_ticket->set('TKT_deleted', 0);
1405
-                    $new_ticket->set('TKT_sold', 0);
1406
-                    // now we need to make sure that $new prices are created as well and attached to new ticket.
1407
-                    $update_prices = true;
1408
-                    $ticket        = $new_ticket;
1409
-                }
1410
-            } else {
1411
-                // no TKT_id so a new ticket
1412
-                $ticket_values['TKT_price'] = $ticket_price;
1413
-                $ticket                     = EE_Ticket::new_instance($ticket_values, $event_timezone, $date_formats);
1414
-                $update_prices              = true;
1415
-            }
1416
-            if (! $ticket instanceof EE_Ticket) {
1417
-                throw new RuntimeException(
1418
-                    sprintf(
1419
-                        esc_html__(
1420
-                            'Something went wrong! A valid Ticket could not be generated or retrieved using the supplied data: %1$s',
1421
-                            'event_espresso'
1422
-                        ),
1423
-                        print_r($ticket_values, true)
1424
-                    )
1425
-                );
1426
-            }
1427
-            // cap ticket qty by datetime reg limits
1428
-            $ticket->set_qty(min($ticket->qty(), $ticket->qty('reg_limit')));
1429
-            // update ticket.
1430
-            $ticket->save();
1431
-            // before going any further make sure our dates are setup correctly
1432
-            // so that the end date is always equal or greater than the start date.
1433
-            if ($ticket->get_raw('TKT_start_date') > $ticket->get_raw('TKT_end_date')) {
1434
-                $ticket->set('TKT_end_date', $ticket->get('TKT_start_date'));
1435
-                $ticket = EEH_DTT_Helper::date_time_add($ticket, 'TKT_end_date', 'days');
1436
-                $ticket->save();
1437
-            }
1438
-            // initially let's add the ticket to the datetime
1439
-            $datetime->_add_relation_to($ticket, 'Ticket');
1440
-            $saved_tickets[ $ticket->ID() ] = $ticket;
1441
-            // add prices to ticket
1442
-            $prices_data = isset($data['edit_prices'][ $row ]) && is_array($data['edit_prices'][ $row ])
1443
-                ? $data['edit_prices'][ $row ]
1444
-                : [];
1445
-            $this->_add_prices_to_ticket($prices_data, $ticket, $update_prices);
1446
-        }
1447
-        // however now we need to handle permanently deleting tickets via the ui.
1448
-        // Keep in mind that the ui does not allow deleting/archiving tickets that have ticket sold.
1449
-        // However, it does allow for deleting tickets that have no tickets sold,
1450
-        // in which case we want to get rid of permanently because there is no need to save in db.
1451
-        $old_tickets     = isset($old_tickets[0]) && $old_tickets[0] === '' ? [] : $old_tickets;
1452
-        $tickets_removed = array_diff($old_tickets, array_keys($saved_tickets));
1453
-        foreach ($tickets_removed as $id) {
1454
-            $id = absint($id);
1455
-            // get the ticket for this id
1456
-            $ticket_to_remove = EEM_Ticket::instance()->get_one_by_ID($id);
1457
-            if (! $ticket_to_remove instanceof EE_Ticket) {
1458
-                continue;
1459
-            }
1460
-            // need to get all the related datetimes on this ticket and remove from every single one of them
1461
-            // (remember this process can ONLY kick off if there are NO tickets sold)
1462
-            $related_datetimes = $ticket_to_remove->get_many_related('Datetime');
1463
-            foreach ($related_datetimes as $related_datetime) {
1464
-                $ticket_to_remove->_remove_relation_to($related_datetime, 'Datetime');
1465
-            }
1466
-            // need to do the same for prices (except these prices can also be deleted because again,
1467
-            // tickets can only be trashed if they don't have any TKTs sold (otherwise they are just archived))
1468
-            $ticket_to_remove->delete_related_permanently('Price');
1469
-            // finally let's delete this ticket
1470
-            // (which should not be blocked at this point b/c we've removed all our relationships)
1471
-            $ticket_to_remove->delete_permanently();
1472
-        }
1473
-        return [$datetime, $saved_tickets];
1474
-    }
1475
-
1476
-
1477
-    /**
1478
-     * This attaches a list of given prices to a ticket.
1479
-     * Note we dont' have to worry about ever removing relationships (or archiving prices)
1480
-     * because if there is a change in price information on a ticket, a new ticket is created anyways
1481
-     * so the archived ticket will retain the old price info and prices are automatically "archived" via the ticket.
1482
-     *
1483
-     * @access  private
1484
-     * @param array     $prices_data Array of prices from the form.
1485
-     * @param EE_Ticket $ticket      EE_Ticket object that prices are being attached to.
1486
-     * @param bool      $new_prices  Whether attach existing incoming prices or create new ones.
1487
-     * @return  void
1488
-     * @throws EE_Error
1489
-     * @throws ReflectionException
1490
-     */
1491
-    private function _add_prices_to_ticket($prices_data, EE_Ticket $ticket, $new_prices = false)
1492
-    {
1493
-        $timezone = $ticket->get_timezone();
1494
-        foreach ($prices_data as $row => $price_data) {
1495
-            $price_values = [
1496
-                'PRC_ID'         => ! empty($price_data['PRC_ID']) ? $price_data['PRC_ID'] : null,
1497
-                'PRT_ID'         => ! empty($price_data['PRT_ID']) ? $price_data['PRT_ID'] : null,
1498
-                'PRC_amount'     => ! empty($price_data['PRC_amount']) ? $price_data['PRC_amount'] : 0,
1499
-                'PRC_name'       => ! empty($price_data['PRC_name']) ? $price_data['PRC_name'] : '',
1500
-                'PRC_desc'       => ! empty($price_data['PRC_desc']) ? $price_data['PRC_desc'] : '',
1501
-                'PRC_is_default' => 0, // make sure prices are NOT set as default from this context
1502
-                'PRC_order'      => $row,
1503
-            ];
1504
-            if ($new_prices || empty($price_values['PRC_ID'])) {
1505
-                $price_values['PRC_ID'] = 0;
1506
-                $price                  = EE_Price::new_instance($price_values, $timezone);
1507
-            } else {
1508
-                $price = EEM_Price::instance($timezone)->get_one_by_ID($price_data['PRC_ID']);
1509
-                // update this price with new values
1510
-                foreach ($price_values as $field => $new_price) {
1511
-                    $price->set($field, $new_price);
1512
-                }
1513
-            }
1514
-            if (! $price instanceof EE_Price) {
1515
-                throw new RuntimeException(
1516
-                    sprintf(
1517
-                        esc_html__(
1518
-                            'Something went wrong! A valid Price could not be generated or retrieved using the supplied data: %1$s',
1519
-                            'event_espresso'
1520
-                        ),
1521
-                        print_r($price_values, true)
1522
-                    )
1523
-                );
1524
-            }
1525
-            $price->save();
1526
-            $ticket->_add_relation_to($price, 'Price');
1527
-        }
1528
-    }
1529
-
1530
-
1531
-    /**
1532
-     * Add in our autosave ajax handlers
1533
-     *
1534
-     */
1535
-    protected function _ee_autosave_create_new()
1536
-    {
1537
-    }
1538
-
1539
-
1540
-    /**
1541
-     * More autosave handlers.
1542
-     */
1543
-    protected function _ee_autosave_edit()
1544
-    {
1545
-    }
1546
-
1547
-
1548
-    /**
1549
-     * @throws EE_Error
1550
-     * @throws ReflectionException
1551
-     */
1552
-    private function _generate_publish_box_extra_content()
1553
-    {
1554
-        // load formatter helper
1555
-        // args for getting related registrations
1556
-        $approved_query_args        = [
1557
-            [
1558
-                'REG_deleted' => 0,
1559
-                'STS_ID'      => EEM_Registration::status_id_approved,
1560
-            ],
1561
-        ];
1562
-        $not_approved_query_args    = [
1563
-            [
1564
-                'REG_deleted' => 0,
1565
-                'STS_ID'      => EEM_Registration::status_id_not_approved,
1566
-            ],
1567
-        ];
1568
-        $pending_payment_query_args = [
1569
-            [
1570
-                'REG_deleted' => 0,
1571
-                'STS_ID'      => EEM_Registration::status_id_pending_payment,
1572
-            ],
1573
-        ];
1574
-        // publish box
1575
-        $publish_box_extra_args = [
1576
-            'view_approved_reg_url'        => add_query_arg(
1577
-                [
1578
-                    'action'      => 'default',
1579
-                    'event_id'    => $this->_cpt_model_obj->ID(),
1580
-                    '_reg_status' => EEM_Registration::status_id_approved,
1581
-                ],
1582
-                REG_ADMIN_URL
1583
-            ),
1584
-            'view_not_approved_reg_url'    => add_query_arg(
1585
-                [
1586
-                    'action'      => 'default',
1587
-                    'event_id'    => $this->_cpt_model_obj->ID(),
1588
-                    '_reg_status' => EEM_Registration::status_id_not_approved,
1589
-                ],
1590
-                REG_ADMIN_URL
1591
-            ),
1592
-            'view_pending_payment_reg_url' => add_query_arg(
1593
-                [
1594
-                    'action'      => 'default',
1595
-                    'event_id'    => $this->_cpt_model_obj->ID(),
1596
-                    '_reg_status' => EEM_Registration::status_id_pending_payment,
1597
-                ],
1598
-                REG_ADMIN_URL
1599
-            ),
1600
-            'approved_regs'                => $this->_cpt_model_obj->count_related(
1601
-                'Registration',
1602
-                $approved_query_args
1603
-            ),
1604
-            'not_approved_regs'            => $this->_cpt_model_obj->count_related(
1605
-                'Registration',
1606
-                $not_approved_query_args
1607
-            ),
1608
-            'pending_payment_regs'         => $this->_cpt_model_obj->count_related(
1609
-                'Registration',
1610
-                $pending_payment_query_args
1611
-            ),
1612
-            'misc_pub_section_class'       => apply_filters(
1613
-                'FHEE_Events_Admin_Page___generate_publish_box_extra_content__misc_pub_section_class',
1614
-                'misc-pub-section'
1615
-            ),
1616
-        ];
1617
-        ob_start();
1618
-        do_action(
1619
-            'AHEE__Events_Admin_Page___generate_publish_box_extra_content__event_editor_overview_add',
1620
-            $this->_cpt_model_obj
1621
-        );
1622
-        $publish_box_extra_args['event_editor_overview_add'] = ob_get_clean();
1623
-        // load template
1624
-        EEH_Template::display_template(
1625
-            EVENTS_TEMPLATE_PATH . 'event_publish_box_extras.template.php',
1626
-            $publish_box_extra_args
1627
-        );
1628
-    }
1629
-
1630
-
1631
-    /**
1632
-     * @return EE_Event
1633
-     */
1634
-    public function get_event_object()
1635
-    {
1636
-        return $this->_cpt_model_obj;
1637
-    }
1638
-
1639
-
1640
-
1641
-
1642
-    /** METABOXES * */
1643
-    /**
1644
-     * _register_event_editor_meta_boxes
1645
-     * add all metaboxes related to the event_editor
1646
-     *
1647
-     * @return void
1648
-     * @throws EE_Error
1649
-     * @throws ReflectionException
1650
-     */
1651
-    protected function _register_event_editor_meta_boxes()
1652
-    {
1653
-        $this->verify_cpt_object();
1654
-        $use_advanced_editor = $this->admin_config->useAdvancedEditor();
1655
-        // check if the new EDTR reg options meta box is being used, and if so, don't load the legacy version
1656
-        if (! $use_advanced_editor || ! $this->feature->allowed('use_reg_options_meta_box')) {
1657
-            $this->addMetaBox(
1658
-                'espresso_event_editor_event_options',
1659
-                esc_html__('Event Registration Options', 'event_espresso'),
1660
-                [$this, 'registration_options_meta_box'],
1661
-                $this->page_slug,
1662
-                'side'
1663
-            );
1664
-        }
1665
-        if (! $use_advanced_editor) {
1666
-            $this->addMetaBox(
1667
-                'espresso_event_editor_tickets',
1668
-                esc_html__('Event Datetime & Ticket', 'event_espresso'),
1669
-                [$this, 'ticket_metabox'],
1670
-                $this->page_slug,
1671
-                'normal',
1672
-                'high'
1673
-            );
1674
-        } elseif ($this->feature->allowed('use_reg_options_meta_box')) {
1675
-            add_action(
1676
-                'add_meta_boxes_espresso_events',
1677
-                function () {
1678
-                    global $current_screen;
1679
-                    remove_meta_box('authordiv', $current_screen, 'normal');
1680
-                },
1681
-                99
1682
-            );
1683
-        }
1684
-        // NOTE: if you're looking for other metaboxes in here,
1685
-        // where a metabox has a related management page in the admin
1686
-        // you will find it setup in the related management page's "_Hooks" file.
1687
-        // i.e. messages metabox is found in "espresso_events_Messages_Hooks.class.php".
1688
-    }
1689
-
1690
-
1691
-    /**
1692
-     * @throws DomainException
1693
-     * @throws EE_Error
1694
-     * @throws ReflectionException
1695
-     */
1696
-    public function ticket_metabox()
1697
-    {
1698
-        $existing_datetime_ids = $existing_ticket_ids = [];
1699
-        // defaults for template args
1700
-        $template_args = [
1701
-            'existing_datetime_ids'    => '',
1702
-            'event_datetime_help_link' => '',
1703
-            'ticket_options_help_link' => '',
1704
-            'time'                     => null,
1705
-            'ticket_rows'              => '',
1706
-            'existing_ticket_ids'      => '',
1707
-            'total_ticket_rows'        => 1,
1708
-            'ticket_js_structure'      => '',
1709
-            'trash_icon'               => 'dashicons dashicons-lock',
1710
-            'disabled'                 => '',
1711
-        ];
1712
-        $event_id      = is_object($this->_cpt_model_obj) ? $this->_cpt_model_obj->ID() : null;
1713
-        /**
1714
-         * 1. Start with retrieving Datetimes
1715
-         * 2. Fore each datetime get related tickets
1716
-         * 3. For each ticket get related prices
1717
-         */
1718
-        /** @var EEM_Datetime $datetime_model */
1719
-        $datetime_model = EE_Registry::instance()->load_model('Datetime');
1720
-        /** @var EEM_Ticket $datetime_model */
1721
-        $ticket_model = EE_Registry::instance()->load_model('Ticket');
1722
-        $times        = $datetime_model->get_all_event_dates($event_id);
1723
-        /** @type EE_Datetime $first_datetime */
1724
-        $first_datetime = reset($times);
1725
-        // do we get related tickets?
1726
-        if (
1727
-            $first_datetime instanceof EE_Datetime
1728
-            && $first_datetime->ID() !== 0
1729
-        ) {
1730
-            $existing_datetime_ids[] = $first_datetime->get('DTT_ID');
1731
-            $template_args['time']   = $first_datetime;
1732
-            $related_tickets         = $first_datetime->tickets(
1733
-                [
1734
-                    ['OR' => ['TKT_deleted' => 1, 'TKT_deleted*' => 0]],
1735
-                    'default_where_conditions' => 'none',
1736
-                ]
1737
-            );
1738
-            if (! empty($related_tickets)) {
1739
-                $template_args['total_ticket_rows'] = count($related_tickets);
1740
-                $row                                = 0;
1741
-                foreach ($related_tickets as $ticket) {
1742
-                    $existing_ticket_ids[]        = $ticket->get('TKT_ID');
1743
-                    $template_args['ticket_rows'] .= $this->_get_ticket_row($ticket, false, $row);
1744
-                    $row++;
1745
-                }
1746
-            } else {
1747
-                $template_args['total_ticket_rows'] = 1;
1748
-                /** @type EE_Ticket $ticket */
1749
-                $ticket                       = $ticket_model->create_default_object();
1750
-                $template_args['ticket_rows'] .= $this->_get_ticket_row($ticket);
1751
-            }
1752
-        } else {
1753
-            $template_args['time'] = $times[0];
1754
-            /** @type EE_Ticket[] $tickets */
1755
-            $tickets                      = $ticket_model->get_all_default_tickets();
1756
-            $template_args['ticket_rows'] .= $this->_get_ticket_row($tickets[1]);
1757
-            // NOTE: we're just sending the first default row
1758
-            // (decaf can't manage default tickets so this should be sufficient);
1759
-        }
1760
-        $template_args['event_datetime_help_link'] = $this->_get_help_tab_link(
1761
-            'event_editor_event_datetimes_help_tab'
1762
-        );
1763
-        $template_args['ticket_options_help_link'] = $this->_get_help_tab_link('ticket_options_info');
1764
-        $template_args['existing_datetime_ids']    = implode(',', $existing_datetime_ids);
1765
-        $template_args['existing_ticket_ids']      = implode(',', $existing_ticket_ids);
1766
-        $template_args['ticket_js_structure']      = $this->_get_ticket_row(
1767
-            $ticket_model->create_default_object(),
1768
-            true
1769
-        );
1770
-        $template                                  = apply_filters(
1771
-            'FHEE__Events_Admin_Page__ticket_metabox__template',
1772
-            EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_main.template.php'
1773
-        );
1774
-        EEH_Template::display_template($template, $template_args);
1775
-    }
1776
-
1777
-
1778
-    /**
1779
-     * Setup an individual ticket form for the decaf event editor page
1780
-     *
1781
-     * @access private
1782
-     * @param EE_Ticket $ticket   the ticket object
1783
-     * @param boolean   $skeleton whether we're generating a skeleton for js manipulation
1784
-     * @param int       $row
1785
-     * @return string generated html for the ticket row.
1786
-     * @throws EE_Error
1787
-     * @throws ReflectionException
1788
-     */
1789
-    private function _get_ticket_row($ticket, $skeleton = false, $row = 0)
1790
-    {
1791
-        $template_args = [
1792
-            'tkt_status_class'    => ' tkt-status-' . $ticket->ticket_status(),
1793
-            'tkt_archive_class'   => $ticket->ticket_status() === EE_Ticket::archived && ! $skeleton ? ' tkt-archived'
1794
-                : '',
1795
-            'ticketrow'           => $skeleton ? 'TICKETNUM' : $row,
1796
-            'TKT_ID'              => $ticket->get('TKT_ID'),
1797
-            'TKT_name'            => $ticket->get('TKT_name'),
1798
-            'TKT_start_date'      => $skeleton ? '' : $ticket->get_date('TKT_start_date', 'Y-m-d h:i a'),
1799
-            'TKT_end_date'        => $skeleton ? '' : $ticket->get_date('TKT_end_date', 'Y-m-d h:i a'),
1800
-            'TKT_is_default'      => $ticket->get('TKT_is_default'),
1801
-            'TKT_qty'             => $ticket->get_pretty('TKT_qty', 'input'),
1802
-            'edit_ticketrow_name' => $skeleton ? 'TICKETNAMEATTR' : 'edit_tickets',
1803
-            'TKT_sold'            => $skeleton ? 0 : $ticket->get('TKT_sold'),
1804
-            'trash_icon'          => ($skeleton || (! empty($ticket) && ! $ticket->get('TKT_deleted')))
1805
-                                     && (! empty($ticket) && $ticket->get('TKT_sold') === 0)
1806
-                ? 'trash-icon dashicons dashicons-post-trash clickable' : 'dashicons dashicons-lock',
1807
-            'disabled'            => $skeleton || (! empty($ticket) && ! $ticket->get('TKT_deleted')) ? ''
1808
-                : ' disabled=disabled',
1809
-        ];
1810
-        $price         = $ticket->ID() !== 0
1811
-            ? $ticket->get_first_related('Price', ['default_where_conditions' => 'none'])
1812
-            : null;
1813
-        $price         = $price instanceof EE_Price
1814
-            ? $price
1815
-            : EEM_Price::instance()->create_default_object();
1816
-        $price_args    = [
1817
-            'price_currency_symbol' => EE_Registry::instance()->CFG->currency->sign,
1818
-            'PRC_amount'            => $price->get('PRC_amount'),
1819
-            'PRT_ID'                => $price->get('PRT_ID'),
1820
-            'PRC_ID'                => $price->get('PRC_ID'),
1821
-            'PRC_is_default'        => $price->get('PRC_is_default'),
1822
-        ];
1823
-        // make sure we have default start and end dates if skeleton
1824
-        // handle rows that should NOT be empty
1825
-        if (empty($template_args['TKT_start_date'])) {
1826
-            // if empty then the start date will be now.
1827
-            $template_args['TKT_start_date'] = date('Y-m-d h:i a', current_time('timestamp'));
1828
-        }
1829
-        if (empty($template_args['TKT_end_date'])) {
1830
-            // get the earliest datetime (if present);
1831
-            $earliest_datetime             = $this->_cpt_model_obj->ID() > 0
1832
-                ? $this->_cpt_model_obj->get_first_related(
1833
-                    'Datetime',
1834
-                    ['order_by' => ['DTT_EVT_start' => 'ASC']]
1835
-                )
1836
-                : null;
1837
-            $template_args['TKT_end_date'] = $earliest_datetime instanceof EE_Datetime
1838
-                ? $earliest_datetime->get_datetime('DTT_EVT_start', 'Y-m-d', 'h:i a')
1839
-                : date('Y-m-d h:i a', mktime(0, 0, 0, date('m'), date('d') + 7, date('Y')));
1840
-        }
1841
-        $template_args = array_merge($template_args, $price_args);
1842
-        $template      = apply_filters(
1843
-            'FHEE__Events_Admin_Page__get_ticket_row__template',
1844
-            EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_ticket_row.template.php',
1845
-            $ticket
1846
-        );
1847
-        return EEH_Template::display_template($template, $template_args, true);
1848
-    }
1849
-
1850
-
1851
-    /**
1852
-     * @throws EE_Error
1853
-     * @throws ReflectionException
1854
-     */
1855
-    public function registration_options_meta_box()
1856
-    {
1857
-        $yes_no_values             = [
1858
-            ['id' => true, 'text' => esc_html__('Yes', 'event_espresso')],
1859
-            ['id' => false, 'text' => esc_html__('No', 'event_espresso')],
1860
-        ];
1861
-        $default_reg_status_values = EEM_Registration::reg_status_array(
1862
-            [
1863
-                EEM_Registration::status_id_cancelled,
1864
-                EEM_Registration::status_id_declined,
1865
-                EEM_Registration::status_id_incomplete,
1866
-            ],
1867
-            true
1868
-        );
1869
-        // $template_args['is_active_select'] = EEH_Form_Fields::select_input('is_active', $yes_no_values, $this->_cpt_model_obj->is_active());
1870
-        $template_args['_event']                          = $this->_cpt_model_obj;
1871
-        $template_args['event']                           = $this->_cpt_model_obj;
1872
-        $template_args['active_status']                   = $this->_cpt_model_obj->pretty_active_status(false);
1873
-        $template_args['additional_limit']                = $this->_cpt_model_obj->additional_limit();
1874
-        $template_args['default_registration_status']     = EEH_Form_Fields::select_input(
1875
-            'default_reg_status',
1876
-            $default_reg_status_values,
1877
-            $this->_cpt_model_obj->default_registration_status()
1878
-        );
1879
-        $template_args['display_description']             = EEH_Form_Fields::select_input(
1880
-            'display_desc',
1881
-            $yes_no_values,
1882
-            $this->_cpt_model_obj->display_description()
1883
-        );
1884
-        $template_args['display_ticket_selector']         = EEH_Form_Fields::select_input(
1885
-            'display_ticket_selector',
1886
-            $yes_no_values,
1887
-            $this->_cpt_model_obj->display_ticket_selector(),
1888
-            '',
1889
-            '',
1890
-            false
1891
-        );
1892
-        $template_args['additional_registration_options'] = apply_filters(
1893
-            'FHEE__Events_Admin_Page__registration_options_meta_box__additional_registration_options',
1894
-            '',
1895
-            $template_args,
1896
-            $yes_no_values,
1897
-            $default_reg_status_values
1898
-        );
1899
-        EEH_Template::display_template(
1900
-            EVENTS_TEMPLATE_PATH . 'event_registration_options.template.php',
1901
-            $template_args
1902
-        );
1903
-    }
1904
-
1905
-
1906
-    /**
1907
-     * _get_events()
1908
-     * This method simply returns all the events (for the given _view and paging)
1909
-     *
1910
-     * @access public
1911
-     * @param int  $per_page     count of items per page (20 default);
1912
-     * @param int  $current_page what is the current page being viewed.
1913
-     * @param bool $count        if TRUE then we just return a count of ALL events matching the given _view.
1914
-     *                           If FALSE then we return an array of event objects
1915
-     *                           that match the given _view and paging parameters.
1916
-     * @return array|int         an array of event objects or a count of them.
1917
-     * @throws Exception
1918
-     */
1919
-    public function get_events($per_page = 10, $current_page = 1, $count = false)
1920
-    {
1921
-        $EEM_Event   = $this->_event_model();
1922
-        $offset      = ($current_page - 1) * $per_page;
1923
-        $limit       = $count ? null : $offset . ',' . $per_page;
1924
-        $orderby     = $this->request->getRequestParam('orderby', 'EVT_ID');
1925
-        $order       = $this->request->getRequestParam('order', 'DESC');
1926
-        $month_range = $this->request->getRequestParam('month_range');
1927
-        if ($month_range) {
1928
-            $pieces = explode(' ', $month_range, 3);
1929
-            // simulate the FIRST day of the month, that fixes issues for months like February
1930
-            // where PHP doesn't know what to assume for date.
1931
-            // @see https://events.codebasehq.com/projects/event-espresso/tickets/10437
1932
-            $month_r = ! empty($pieces[0]) ? date('m', EEH_DTT_Helper::first_of_month_timestamp($pieces[0])) : '';
1933
-            $year_r  = ! empty($pieces[1]) ? $pieces[1] : '';
1934
-        }
1935
-        $where  = [];
1936
-        $status = $this->request->getRequestParam('status');
1937
-        // determine what post_status our condition will have for the query.
1938
-        switch ($status) {
1939
-            case 'month':
1940
-            case 'today':
1941
-            case null:
1942
-            case 'all':
1943
-                break;
1944
-            case 'draft':
1945
-                $where['status'] = ['IN', ['draft', 'auto-draft']];
1946
-                break;
1947
-            default:
1948
-                $where['status'] = $status;
1949
-        }
1950
-        // categories? The default for all categories is -1
1951
-        $category = $this->request->getRequestParam('EVT_CAT', -1, 'int');
1952
-        if ($category !== -1) {
1953
-            $where['Term_Taxonomy.taxonomy'] = EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY;
1954
-            $where['Term_Taxonomy.term_id']  = $category;
1955
-        }
1956
-        // date where conditions
1957
-        $start_formats = EEM_Datetime::instance()->get_formats_for('DTT_EVT_start');
1958
-        if ($month_range) {
1959
-            $DateTime = new DateTime(
1960
-                $year_r . '-' . $month_r . '-01 00:00:00',
1961
-                new DateTimeZone('UTC')
1962
-            );
1963
-            $start    = $DateTime->getTimestamp();
1964
-            // set the datetime to be the end of the month
1965
-            $DateTime->setDate(
1966
-                $year_r,
1967
-                $month_r,
1968
-                $DateTime->format('t')
1969
-            )->setTime(23, 59, 59);
1970
-            $end                             = $DateTime->getTimestamp();
1971
-            $where['Datetime.DTT_EVT_start'] = ['BETWEEN', [$start, $end]];
1972
-        } elseif ($status === 'today') {
1973
-            $DateTime                        =
1974
-                new DateTime('now', new DateTimeZone(EEM_Event::instance()->get_timezone()));
1975
-            $start                           = $DateTime->setTime(0, 0)->format(implode(' ', $start_formats));
1976
-            $end                             = $DateTime->setTime(23, 59, 59)->format(implode(' ', $start_formats));
1977
-            $where['Datetime.DTT_EVT_start'] = ['BETWEEN', [$start, $end]];
1978
-        } elseif ($status === 'month') {
1979
-            $now                             = date('Y-m-01');
1980
-            $DateTime                        =
1981
-                new DateTime($now, new DateTimeZone(EEM_Event::instance()->get_timezone()));
1982
-            $start                           = $DateTime->setTime(0, 0)->format(implode(' ', $start_formats));
1983
-            $end                             = $DateTime->setDate(date('Y'), date('m'), $DateTime->format('t'))
1984
-                                                        ->setTime(23, 59, 59)
1985
-                                                        ->format(implode(' ', $start_formats));
1986
-            $where['Datetime.DTT_EVT_start'] = ['BETWEEN', [$start, $end]];
1987
-        }
1988
-        if (! EE_Registry::instance()->CAP->current_user_can('ee_read_others_events', 'get_events')) {
1989
-            $where['EVT_wp_user'] = get_current_user_id();
1990
-        } else {
1991
-            if (! isset($where['status'])) {
1992
-                if (! EE_Registry::instance()->CAP->current_user_can('ee_read_private_events', 'get_events')) {
1993
-                    $where['OR'] = [
1994
-                        'status*restrict_private' => ['!=', 'private'],
1995
-                        'AND'                     => [
1996
-                            'status*inclusive' => ['=', 'private'],
1997
-                            'EVT_wp_user'      => get_current_user_id(),
1998
-                        ],
1999
-                    ];
2000
-                }
2001
-            }
2002
-        }
2003
-        $wp_user = $this->request->getRequestParam('EVT_wp_user', 0, 'int');
2004
-        if (
2005
-            $wp_user
2006
-            && $wp_user !== get_current_user_id()
2007
-            && EE_Registry::instance()->CAP->current_user_can('ee_read_others_events', 'get_events')
2008
-        ) {
2009
-            $where['EVT_wp_user'] = $wp_user;
2010
-        }
2011
-        // search query handling
2012
-        $search_term = $this->request->getRequestParam('s');
2013
-        if ($search_term) {
2014
-            $search_term = '%' . $search_term . '%';
2015
-            $where['OR'] = [
2016
-                'EVT_name'       => ['LIKE', $search_term],
2017
-                'EVT_desc'       => ['LIKE', $search_term],
2018
-                'EVT_short_desc' => ['LIKE', $search_term],
2019
-            ];
2020
-        }
2021
-        // filter events by venue.
2022
-        $venue = $this->request->getRequestParam('venue', 0, 'int');
2023
-        if ($venue) {
2024
-            $where['Venue.VNU_ID'] = $venue;
2025
-        }
2026
-        $request_params = $this->request->requestParams();
2027
-        $where          = apply_filters('FHEE__Events_Admin_Page__get_events__where', $where, $request_params);
2028
-        $query_params   = apply_filters(
2029
-            'FHEE__Events_Admin_Page__get_events__query_params',
2030
-            [
2031
-                $where,
2032
-                'limit'    => $limit,
2033
-                'order_by' => $orderby,
2034
-                'order'    => $order,
2035
-                'group_by' => 'EVT_ID',
2036
-            ],
2037
-            $request_params
2038
-        );
2039
-
2040
-        // let's first check if we have special requests coming in.
2041
-        $active_status = $this->request->getRequestParam('active_status');
2042
-        if ($active_status) {
2043
-            switch ($active_status) {
2044
-                case 'upcoming':
2045
-                    return $EEM_Event->get_upcoming_events($query_params, $count);
2046
-                case 'expired':
2047
-                    return $EEM_Event->get_expired_events($query_params, $count);
2048
-                case 'active':
2049
-                    return $EEM_Event->get_active_events($query_params, $count);
2050
-                case 'inactive':
2051
-                    return $EEM_Event->get_inactive_events($query_params, $count);
2052
-            }
2053
-        }
2054
-
2055
-        return $count ? $EEM_Event->count([$where], 'EVT_ID', true) : $EEM_Event->get_all($query_params);
2056
-    }
2057
-
2058
-
2059
-    /**
2060
-     * handling for WordPress CPT actions (trash, restore, delete)
2061
-     *
2062
-     * @param string $post_id
2063
-     * @throws EE_Error
2064
-     * @throws ReflectionException
2065
-     */
2066
-    public function trash_cpt_item($post_id)
2067
-    {
2068
-        $this->request->setRequestParam('EVT_ID', $post_id);
2069
-        $this->_trash_or_restore_event('trash', false);
2070
-    }
2071
-
2072
-
2073
-    /**
2074
-     * @param string $post_id
2075
-     * @throws EE_Error
2076
-     * @throws ReflectionException
2077
-     */
2078
-    public function restore_cpt_item($post_id)
2079
-    {
2080
-        $this->request->setRequestParam('EVT_ID', $post_id);
2081
-        $this->_trash_or_restore_event('draft', false);
2082
-    }
2083
-
2084
-
2085
-    /**
2086
-     * @param string $post_id
2087
-     * @throws EE_Error
2088
-     * @throws EE_Error
2089
-     */
2090
-    public function delete_cpt_item($post_id)
2091
-    {
2092
-        throw new EE_Error(
2093
-            esc_html__(
2094
-                'Please contact Event Espresso support with the details of the steps taken to produce this error.',
2095
-                'event_espresso'
2096
-            )
2097
-        );
2098
-        // $this->request->setRequestParam('EVT_ID', $post_id);
2099
-        // $this->_delete_event();
2100
-    }
2101
-
2102
-
2103
-    /**
2104
-     * _trash_or_restore_event
2105
-     *
2106
-     * @access protected
2107
-     * @param string $event_status
2108
-     * @param bool   $redirect_after
2109
-     * @throws EE_Error
2110
-     * @throws EE_Error
2111
-     * @throws ReflectionException
2112
-     */
2113
-    protected function _trash_or_restore_event($event_status = 'trash', $redirect_after = true)
2114
-    {
2115
-        // determine the event id and set to array.
2116
-        $EVT_ID = $this->request->getRequestParam('EVT_ID', 0, 'int');
2117
-        // loop thru events
2118
-        if ($EVT_ID) {
2119
-            // clean status
2120
-            $event_status = sanitize_key($event_status);
2121
-            // grab status
2122
-            if (! empty($event_status)) {
2123
-                $success = $this->_change_event_status($EVT_ID, $event_status);
2124
-            } else {
2125
-                $success = false;
2126
-                $msg     = esc_html__(
2127
-                    'An error occurred. The event could not be moved to the trash because a valid event status was not not supplied.',
2128
-                    'event_espresso'
2129
-                );
2130
-                EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2131
-            }
2132
-        } else {
2133
-            $success = false;
2134
-            $msg     = esc_html__(
2135
-                'An error occurred. The event could not be moved to the trash because a valid event ID was not not supplied.',
2136
-                'event_espresso'
2137
-            );
2138
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2139
-        }
2140
-        $action = $event_status === 'trash' ? 'moved to the trash' : 'restored from the trash';
2141
-        if ($redirect_after) {
2142
-            $this->_redirect_after_action($success, 'Event', $action, ['action' => 'default']);
2143
-        }
2144
-    }
2145
-
2146
-
2147
-    /**
2148
-     * _trash_or_restore_events
2149
-     *
2150
-     * @access protected
2151
-     * @param string $event_status
2152
-     * @return void
2153
-     * @throws EE_Error
2154
-     * @throws EE_Error
2155
-     * @throws ReflectionException
2156
-     */
2157
-    protected function _trash_or_restore_events($event_status = 'trash')
2158
-    {
2159
-        // clean status
2160
-        $event_status = sanitize_key($event_status);
2161
-        // grab status
2162
-        if (! empty($event_status)) {
2163
-            $success = true;
2164
-            // determine the event id and set to array.
2165
-            $EVT_IDs = $this->request->getRequestParam('EVT_IDs', [], 'int', true);
2166
-            // loop thru events
2167
-            foreach ($EVT_IDs as $EVT_ID) {
2168
-                if ($EVT_ID = absint($EVT_ID)) {
2169
-                    $results = $this->_change_event_status($EVT_ID, $event_status);
2170
-                    $success = $results !== false ? $success : false;
2171
-                } else {
2172
-                    $msg = sprintf(
2173
-                        esc_html__(
2174
-                            'An error occurred. Event #%d could not be moved to the trash because a valid event ID was not not supplied.',
2175
-                            'event_espresso'
2176
-                        ),
2177
-                        $EVT_ID
2178
-                    );
2179
-                    EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2180
-                    $success = false;
2181
-                }
2182
-            }
2183
-        } else {
2184
-            $success = false;
2185
-            $msg     = esc_html__(
2186
-                'An error occurred. The event could not be moved to the trash because a valid event status was not not supplied.',
2187
-                'event_espresso'
2188
-            );
2189
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2190
-        }
2191
-        // in order to force a pluralized result message we need to send back a success status greater than 1
2192
-        $success = $success ? 2 : false;
2193
-        $action  = $event_status === 'trash' ? 'moved to the trash' : 'restored from the trash';
2194
-        $this->_redirect_after_action($success, 'Events', $action, ['action' => 'default']);
2195
-    }
2196
-
2197
-
2198
-    /**
2199
-     * @param int    $EVT_ID
2200
-     * @param string $event_status
2201
-     * @return bool
2202
-     * @throws EE_Error
2203
-     * @throws ReflectionException
2204
-     */
2205
-    private function _change_event_status($EVT_ID = 0, $event_status = '')
2206
-    {
2207
-        // grab event id
2208
-        if (! $EVT_ID) {
2209
-            $msg = esc_html__(
2210
-                'An error occurred. No Event ID or an invalid Event ID was received.',
2211
-                'event_espresso'
2212
-            );
2213
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2214
-            return false;
2215
-        }
2216
-        $this->_cpt_model_obj = EEM_Event::instance()->get_one_by_ID($EVT_ID);
2217
-        // clean status
2218
-        $event_status = sanitize_key($event_status);
2219
-        // grab status
2220
-        if (empty($event_status)) {
2221
-            $msg = esc_html__(
2222
-                'An error occurred. No Event Status or an invalid Event Status was received.',
2223
-                'event_espresso'
2224
-            );
2225
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2226
-            return false;
2227
-        }
2228
-        // was event trashed or restored ?
2229
-        switch ($event_status) {
2230
-            case 'draft':
2231
-                $action = 'restored from the trash';
2232
-                $hook   = 'AHEE_event_restored_from_trash';
2233
-                break;
2234
-            case 'trash':
2235
-                $action = 'moved to the trash';
2236
-                $hook   = 'AHEE_event_moved_to_trash';
2237
-                break;
2238
-            default:
2239
-                $action = 'updated';
2240
-                $hook   = false;
2241
-        }
2242
-        // use class to change status
2243
-        $this->_cpt_model_obj->set_status($event_status);
2244
-        $success = $this->_cpt_model_obj->save();
2245
-        if (! $success) {
2246
-            $msg = sprintf(esc_html__('An error occurred. The event could not be %s.', 'event_espresso'), $action);
2247
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2248
-            return false;
2249
-        }
2250
-        if ($hook) {
2251
-            do_action($hook);
2252
-        }
2253
-        return true;
2254
-    }
2255
-
2256
-
2257
-    /**
2258
-     * @param array $event_ids
2259
-     * @return array
2260
-     * @since   4.10.23.p
2261
-     */
2262
-    private function cleanEventIds(array $event_ids)
2263
-    {
2264
-        return array_map('absint', $event_ids);
2265
-    }
2266
-
2267
-
2268
-    /**
2269
-     * @return array
2270
-     * @since   4.10.23.p
2271
-     */
2272
-    private function getEventIdsFromRequest()
2273
-    {
2274
-        if ($this->request->requestParamIsSet('EVT_IDs')) {
2275
-            return $this->request->getRequestParam('EVT_IDs', [], 'int', true);
2276
-        } else {
2277
-            return $this->request->getRequestParam('EVT_ID', [], 'int', true);
2278
-        }
2279
-    }
2280
-
2281
-
2282
-    /**
2283
-     * @param bool $preview_delete
2284
-     * @throws EE_Error
2285
-     */
2286
-    protected function _delete_event($preview_delete = true)
2287
-    {
2288
-        $this->_delete_events($preview_delete);
2289
-    }
2290
-
2291
-
2292
-    /**
2293
-     * Gets the tree traversal batch persister.
2294
-     *
2295
-     * @return NodeGroupDao
2296
-     * @throws InvalidArgumentException
2297
-     * @throws InvalidDataTypeException
2298
-     * @throws InvalidInterfaceException
2299
-     * @since 4.10.12.p
2300
-     */
2301
-    protected function getModelObjNodeGroupPersister()
2302
-    {
2303
-        if (! $this->model_obj_node_group_persister instanceof NodeGroupDao) {
2304
-            $this->model_obj_node_group_persister =
2305
-                $this->getLoader()->load('\EventEspresso\core\services\orm\tree_traversal\NodeGroupDao');
2306
-        }
2307
-        return $this->model_obj_node_group_persister;
2308
-    }
2309
-
2310
-
2311
-    /**
2312
-     * @param bool $preview_delete
2313
-     * @return void
2314
-     * @throws EE_Error
2315
-     */
2316
-    protected function _delete_events($preview_delete = true)
2317
-    {
2318
-        $event_ids = $this->getEventIdsFromRequest();
2319
-        if ($preview_delete) {
2320
-            $this->generateDeletionPreview($event_ids);
2321
-        } else {
2322
-            EEM_Event::instance()->delete_permanently([['EVT_ID' => ['IN', $event_ids]]]);
2323
-        }
2324
-    }
2325
-
2326
-
2327
-    /**
2328
-     * @param array $event_ids
2329
-     */
2330
-    protected function generateDeletionPreview(array $event_ids)
2331
-    {
2332
-        $event_ids = $this->cleanEventIds($event_ids);
2333
-        // Set a code we can use to reference this deletion task in the batch jobs and preview page.
2334
-        $deletion_job_code = $this->getModelObjNodeGroupPersister()->generateGroupCode();
2335
-        $return_url        = EE_Admin_Page::add_query_args_and_nonce(
2336
-            [
2337
-                'action'            => 'preview_deletion',
2338
-                'deletion_job_code' => $deletion_job_code,
2339
-            ],
2340
-            $this->_admin_base_url
2341
-        );
2342
-        EEH_URL::safeRedirectAndExit(
2343
-            EE_Admin_Page::add_query_args_and_nonce(
2344
-                [
2345
-                    'page'              => EED_Batch::PAGE_SLUG,
2346
-                    'batch'             => EED_Batch::batch_job,
2347
-                    'EVT_IDs'           => $event_ids,
2348
-                    'deletion_job_code' => $deletion_job_code,
2349
-                    'job_handler'       => urlencode('EventEspressoBatchRequest\JobHandlers\PreviewEventDeletion'),
2350
-                    'return_url'        => urlencode($return_url),
2351
-                ],
2352
-                admin_url()
2353
-            )
2354
-        );
2355
-    }
2356
-
2357
-
2358
-    /**
2359
-     * Checks for a POST submission
2360
-     *
2361
-     * @since 4.10.12.p
2362
-     */
2363
-    protected function confirmDeletion()
2364
-    {
2365
-        $deletion_redirect_logic =
2366
-            $this->getLoader()->getShared('\EventEspresso\core\domain\services\admin\events\data\ConfirmDeletion');
2367
-        $deletion_redirect_logic->handle($this->get_request_data(), $this->admin_base_url());
2368
-    }
2369
-
2370
-
2371
-    /**
2372
-     * A page for users to preview what exactly will be deleted, and confirm they want to delete it.
2373
-     *
2374
-     * @throws EE_Error
2375
-     * @since 4.10.12.p
2376
-     */
2377
-    protected function previewDeletion()
2378
-    {
2379
-        $preview_deletion_logic =
2380
-            $this->getLoader()->getShared('\EventEspresso\core\domain\services\admin\events\data\PreviewDeletion');
2381
-        $this->set_template_args($preview_deletion_logic->handle($this->get_request_data(), $this->admin_base_url()));
2382
-        $this->display_admin_page_with_no_sidebar();
2383
-    }
2384
-
2385
-
2386
-    /**
2387
-     * get total number of events
2388
-     *
2389
-     * @access public
2390
-     * @return int
2391
-     * @throws EE_Error
2392
-     * @throws EE_Error
2393
-     */
2394
-    public function total_events()
2395
-    {
2396
-        return EEM_Event::instance()->count(
2397
-            ['caps' => 'read_admin'],
2398
-            'EVT_ID',
2399
-            true
2400
-        );
2401
-    }
2402
-
2403
-
2404
-    /**
2405
-     * get total number of draft events
2406
-     *
2407
-     * @access public
2408
-     * @return int
2409
-     * @throws EE_Error
2410
-     * @throws EE_Error
2411
-     */
2412
-    public function total_events_draft()
2413
-    {
2414
-        return EEM_Event::instance()->count(
2415
-            [
2416
-                ['status' => ['IN', ['draft', 'auto-draft']]],
2417
-                'caps' => 'read_admin',
2418
-            ],
2419
-            'EVT_ID',
2420
-            true
2421
-        );
2422
-    }
2423
-
2424
-
2425
-    /**
2426
-     * get total number of trashed events
2427
-     *
2428
-     * @access public
2429
-     * @return int
2430
-     * @throws EE_Error
2431
-     * @throws EE_Error
2432
-     */
2433
-    public function total_trashed_events()
2434
-    {
2435
-        return EEM_Event::instance()->count(
2436
-            [
2437
-                ['status' => 'trash'],
2438
-                'caps' => 'read_admin',
2439
-            ],
2440
-            'EVT_ID',
2441
-            true
2442
-        );
2443
-    }
2444
-
2445
-
2446
-    /**
2447
-     *    _default_event_settings
2448
-     *    This generates the Default Settings Tab
2449
-     *
2450
-     * @return void
2451
-     * @throws DomainException
2452
-     * @throws EE_Error
2453
-     * @throws InvalidArgumentException
2454
-     * @throws InvalidDataTypeException
2455
-     * @throws InvalidInterfaceException
2456
-     */
2457
-    protected function _default_event_settings()
2458
-    {
2459
-        $this->_set_add_edit_form_tags('update_default_event_settings');
2460
-        $this->_set_publish_post_box_vars(null, false, false, null, false);
2461
-        $this->_template_args['admin_page_content'] = EEH_HTML::div(
2462
-            $this->_default_event_settings_form()->get_html(),
2463
-            '',
2464
-            'padding'
2465
-        );
2466
-        $this->display_admin_page_with_sidebar();
2467
-    }
2468
-
2469
-
2470
-    /**
2471
-     * Return the form for event settings.
2472
-     *
2473
-     * @return EE_Form_Section_Proper
2474
-     * @throws EE_Error
2475
-     */
2476
-    protected function _default_event_settings_form()
2477
-    {
2478
-        $registration_config              = EE_Registry::instance()->CFG->registration;
2479
-        $registration_stati_for_selection = EEM_Registration::reg_status_array(
2480
-        // exclude
2481
-            [
2482
-                EEM_Registration::status_id_cancelled,
2483
-                EEM_Registration::status_id_declined,
2484
-                EEM_Registration::status_id_incomplete,
2485
-                EEM_Registration::status_id_wait_list,
2486
-            ],
2487
-            true
2488
-        );
2489
-        // setup Advanced Editor ???
2490
-        if (
2491
-            $this->raw_req_action === 'default_event_settings'
2492
-            || $this->raw_req_action === 'update_default_event_settings'
2493
-        ) {
2494
-            $this->advanced_editor_admin_form = $this->loader->getShared(AdvancedEditorAdminFormSection::class);
2495
-        }
2496
-        return new EE_Form_Section_Proper(
2497
-            [
2498
-                'name'            => 'update_default_event_settings',
2499
-                'html_id'         => 'update_default_event_settings',
2500
-                'html_class'      => 'form-table',
2501
-                'layout_strategy' => new EE_Admin_Two_Column_Layout(),
2502
-                'subsections'     => apply_filters(
2503
-                    'FHEE__Events_Admin_Page___default_event_settings_form__form_subsections',
2504
-                    [
2505
-                        'defaults_section_header' => new EE_Form_Section_HTML(
2506
-                            EEH_HTML::h2(
2507
-                                esc_html__('Default Settings', 'event_espresso'),
2508
-                                '',
2509
-                                'ee-admin-settings-hdr'
2510
-                            )
2511
-                        ),
2512
-                        'default_reg_status'  => new EE_Select_Input(
2513
-                            $registration_stati_for_selection,
2514
-                            [
2515
-                                'default'         => isset($registration_config->default_STS_ID)
2516
-                                                     && array_key_exists(
2517
-                                                         $registration_config->default_STS_ID,
2518
-                                                         $registration_stati_for_selection
2519
-                                                     )
2520
-                                    ? sanitize_text_field($registration_config->default_STS_ID)
2521
-                                    : EEM_Registration::status_id_pending_payment,
2522
-                                'html_label_text' => esc_html__('Default Registration Status', 'event_espresso')
2523
-                                                     . EEH_Template::get_help_tab_link(
2524
-                                                         'default_settings_status_help_tab'
2525
-                                                     ),
2526
-                                'html_help_text'  => esc_html__(
2527
-                                    'This setting allows you to preselect what the default registration status setting is when creating an event.  Note that changing this setting does NOT retroactively apply it to existing events.',
2528
-                                    'event_espresso'
2529
-                                ),
2530
-                            ]
2531
-                        ),
2532
-                        'default_max_tickets' => new EE_Integer_Input(
2533
-                            [
2534
-                                'default'         => isset($registration_config->default_maximum_number_of_tickets)
2535
-                                    ? $registration_config->default_maximum_number_of_tickets
2536
-                                    : EEM_Event::get_default_additional_limit(),
2537
-                                'html_label_text' => esc_html__(
2538
-                                    'Default Maximum Tickets Allowed Per Order:',
2539
-                                    'event_espresso'
2540
-                                )
2541
-                                                     . EEH_Template::get_help_tab_link(
2542
-                                                         'default_maximum_tickets_help_tab"'
2543
-                                                     ),
2544
-                                'html_help_text'  => esc_html__(
2545
-                                    'This setting allows you to indicate what will be the default for the maximum number of tickets per order when creating new events.',
2546
-                                    'event_espresso'
2547
-                                ),
2548
-                            ]
2549
-                        ),
2550
-                    ]
2551
-                ),
2552
-            ]
2553
-        );
2554
-    }
2555
-
2556
-
2557
-    /**
2558
-     * @return void
2559
-     * @throws EE_Error
2560
-     * @throws InvalidArgumentException
2561
-     * @throws InvalidDataTypeException
2562
-     * @throws InvalidInterfaceException
2563
-     */
2564
-    protected function _update_default_event_settings()
2565
-    {
2566
-        $form = $this->_default_event_settings_form();
2567
-        if ($form->was_submitted()) {
2568
-            $form->receive_form_submission();
2569
-            if ($form->is_valid()) {
2570
-                $registration_config = EE_Registry::instance()->CFG->registration;
2571
-                $valid_data          = $form->valid_data();
2572
-                if (isset($valid_data['default_reg_status'])) {
2573
-                    $registration_config->default_STS_ID = $valid_data['default_reg_status'];
2574
-                }
2575
-                if (isset($valid_data['default_max_tickets'])) {
2576
-                    $registration_config->default_maximum_number_of_tickets = $valid_data['default_max_tickets'];
2577
-                }
2578
-                do_action(
2579
-                    'AHEE__Events_Admin_Page___update_default_event_settings',
2580
-                    $valid_data,
2581
-                    EE_Registry::instance()->CFG,
2582
-                    $this
2583
-                );
2584
-                // update because data was valid!
2585
-                EE_Registry::instance()->CFG->update_espresso_config();
2586
-                EE_Error::overwrite_success();
2587
-                EE_Error::add_success(
2588
-                    esc_html__('Default Event Settings were updated', 'event_espresso')
2589
-                );
2590
-            }
2591
-        }
2592
-        $this->_redirect_after_action(0, '', '', ['action' => 'default_event_settings'], true);
2593
-    }
2594
-
2595
-
2596
-    /*************        Templates        *************
2597
-     *
2598
-     * @throws EE_Error
2599
-     */
2600
-    protected function _template_settings()
2601
-    {
2602
-        $this->_admin_page_title              = esc_html__('Template Settings (Preview)', 'event_espresso');
2603
-        $this->_template_args['preview_img']  = '<img src="'
2604
-                                                . EVENTS_ASSETS_URL
2605
-                                                . '/images/'
2606
-                                                . 'caffeinated_template_features.jpg" alt="'
2607
-                                                . esc_attr__('Template Settings Preview screenshot', 'event_espresso')
2608
-                                                . '" />';
2609
-        $this->_template_args['preview_text'] = '<strong>'
2610
-                                                . esc_html__(
2611
-                                                    'Template Settings is a feature that is only available in the premium version of Event Espresso 4 which is available with a support license purchase on EventEspresso.com. Template Settings allow you to configure some of the appearance options for both the Event List and Event Details pages.',
2612
-                                                    'event_espresso'
2613
-                                                ) . '</strong>';
2614
-        $this->display_admin_caf_preview_page('template_settings_tab');
2615
-    }
2616
-
2617
-
2618
-    /** Event Category Stuff **/
2619
-    /**
2620
-     * set the _category property with the category object for the loaded page.
2621
-     *
2622
-     * @access private
2623
-     * @return void
2624
-     */
2625
-    private function _set_category_object()
2626
-    {
2627
-        if (isset($this->_category->id) && ! empty($this->_category->id)) {
2628
-            return;
2629
-        } //already have the category object so get out.
2630
-        // set default category object
2631
-        $this->_set_empty_category_object();
2632
-        // only set if we've got an id
2633
-        $category_ID = $this->request->getRequestParam('EVT_CAT_ID', 0, 'int');
2634
-        if (! $category_ID) {
2635
-            return;
2636
-        }
2637
-        $term = get_term($category_ID, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY);
2638
-        if (! empty($term)) {
2639
-            $this->_category->category_name       = $term->name;
2640
-            $this->_category->category_identifier = $term->slug;
2641
-            $this->_category->category_desc       = $term->description;
2642
-            $this->_category->id                  = $term->term_id;
2643
-            $this->_category->parent              = $term->parent;
2644
-        }
2645
-    }
2646
-
2647
-
2648
-    /**
2649
-     * Clears out category properties.
2650
-     */
2651
-    private function _set_empty_category_object()
2652
-    {
2653
-        $this->_category                = new stdClass();
2654
-        $this->_category->category_name = $this->_category->category_identifier = $this->_category->category_desc = '';
2655
-        $this->_category->id            = $this->_category->parent = 0;
2656
-    }
2657
-
2658
-
2659
-    /**
2660
-     * @throws DomainException
2661
-     * @throws EE_Error
2662
-     * @throws InvalidArgumentException
2663
-     * @throws InvalidDataTypeException
2664
-     * @throws InvalidInterfaceException
2665
-     */
2666
-    protected function _category_list_table()
2667
-    {
2668
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2669
-        $this->_search_btn_label = esc_html__('Categories', 'event_espresso');
2670
-        $this->_admin_page_title .= ' ';
2671
-        $this->_admin_page_title .= $this->get_action_link_or_button(
2672
-            'add_category',
2673
-            'add_category',
2674
-            [],
2675
-            'add-new-h2'
2676
-        );
2677
-        $this->display_admin_list_table_page_with_sidebar();
2678
-    }
2679
-
2680
-
2681
-    /**
2682
-     * Output category details view.
2683
-     *
2684
-     * @throws EE_Error
2685
-     * @throws EE_Error
2686
-     */
2687
-    protected function _category_details($view)
2688
-    {
2689
-        // load formatter helper
2690
-        // load field generator helper
2691
-        $route = $view === 'edit' ? 'update_category' : 'insert_category';
2692
-        $this->_set_add_edit_form_tags($route);
2693
-        $this->_set_category_object();
2694
-        $id            = ! empty($this->_category->id) ? $this->_category->id : '';
2695
-        $delete_action = 'delete_category';
2696
-        // custom redirect
2697
-        $redirect = EE_Admin_Page::add_query_args_and_nonce(
2698
-            ['action' => 'category_list'],
2699
-            $this->_admin_base_url
2700
-        );
2701
-        $this->_set_publish_post_box_vars('EVT_CAT_ID', $id, $delete_action, $redirect);
2702
-        // take care of contents
2703
-        $this->_template_args['admin_page_content'] = $this->_category_details_content();
2704
-        $this->display_admin_page_with_sidebar();
2705
-    }
2706
-
2707
-
2708
-    /**
2709
-     * Output category details content.
2710
-     *
2711
-     * @throws DomainException
2712
-     */
2713
-    protected function _category_details_content()
2714
-    {
2715
-        $editor_args['category_desc'] = [
2716
-            'type'          => 'wp_editor',
2717
-            'value'         => EEH_Formatter::admin_format_content($this->_category->category_desc),
2718
-            'class'         => 'my_editor_custom',
2719
-            'wpeditor_args' => ['media_buttons' => false],
2720
-        ];
2721
-        $_wp_editor                   = $this->_generate_admin_form_fields($editor_args, 'array');
2722
-        $all_terms                    = get_terms(
2723
-            [EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY],
2724
-            ['hide_empty' => 0, 'exclude' => [$this->_category->id]]
2725
-        );
2726
-        // setup category select for term parents.
2727
-        $category_select_values[] = [
2728
-            'text' => esc_html__('No Parent', 'event_espresso'),
2729
-            'id'   => 0,
2730
-        ];
2731
-        foreach ($all_terms as $term) {
2732
-            $category_select_values[] = [
2733
-                'text' => $term->name,
2734
-                'id'   => $term->term_id,
2735
-            ];
2736
-        }
2737
-        $category_select = EEH_Form_Fields::select_input(
2738
-            'category_parent',
2739
-            $category_select_values,
2740
-            $this->_category->parent
2741
-        );
2742
-        $template_args   = [
2743
-            'category'                 => $this->_category,
2744
-            'category_select'          => $category_select,
2745
-            'unique_id_info_help_link' => $this->_get_help_tab_link('unique_id_info'),
2746
-            'category_desc_editor'     => $_wp_editor['category_desc']['field'],
2747
-            'disable'                  => '',
2748
-            'disabled_message'         => false,
2749
-        ];
2750
-        $template        = EVENTS_TEMPLATE_PATH . 'event_category_details.template.php';
2751
-        return EEH_Template::display_template($template, $template_args, true);
2752
-    }
2753
-
2754
-
2755
-    /**
2756
-     * Handles deleting categories.
2757
-     *
2758
-     * @throws EE_Error
2759
-     */
2760
-    protected function _delete_categories()
2761
-    {
2762
-        $category_IDs = $this->request->getRequestParam('EVT_CAT_ID', 0, 'int', true);
2763
-        foreach ($category_IDs as $category_ID) {
2764
-            $this->_delete_category($category_ID);
2765
-        }
2766
-        // doesn't matter what page we're coming from... we're going to the same place after delete.
2767
-        $query_args = [
2768
-            'action' => 'category_list',
2769
-        ];
2770
-        $this->_redirect_after_action(0, '', '', $query_args);
2771
-    }
2772
-
2773
-
2774
-    /**
2775
-     * Handles deleting specific category.
2776
-     *
2777
-     * @param int $cat_id
2778
-     */
2779
-    protected function _delete_category($cat_id)
2780
-    {
2781
-        $cat_id = absint($cat_id);
2782
-        wp_delete_term($cat_id, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY);
2783
-    }
2784
-
2785
-
2786
-    /**
2787
-     * Handles triggering the update or insertion of a new category.
2788
-     *
2789
-     * @param bool $new_category true means we're triggering the insert of a new category.
2790
-     * @throws EE_Error
2791
-     * @throws EE_Error
2792
-     */
2793
-    protected function _insert_or_update_category($new_category)
2794
-    {
2795
-        $cat_id  = $new_category ? $this->_insert_category() : $this->_insert_category(true);
2796
-        $success = 0; // we already have a success message so lets not send another.
2797
-        if ($cat_id) {
2798
-            $query_args = [
2799
-                'action'     => 'edit_category',
2800
-                'EVT_CAT_ID' => $cat_id,
2801
-            ];
2802
-        } else {
2803
-            $query_args = ['action' => 'add_category'];
2804
-        }
2805
-        $this->_redirect_after_action($success, '', '', $query_args, true);
2806
-    }
2807
-
2808
-
2809
-    /**
2810
-     * Inserts or updates category
2811
-     *
2812
-     * @param bool $update (true indicates we're updating a category).
2813
-     * @return bool|mixed|string
2814
-     */
2815
-    private function _insert_category($update = false)
2816
-    {
2817
-        $category_ID         = $update ? $this->request->getRequestParam('EVT_CAT_ID', 0, 'int') : 0;
2818
-        $category_name       = $this->request->getRequestParam('category_name', '');
2819
-        $category_desc       = $this->request->getRequestParam('category_desc', '');
2820
-        $category_parent     = $this->request->getRequestParam('category_parent', 0, 'int');
2821
-        $category_identifier = $this->request->getRequestParam('category_identifier', '');
2822
-
2823
-        if (empty($category_name)) {
2824
-            $msg = esc_html__('You must add a name for the category.', 'event_espresso');
2825
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2826
-            return false;
2827
-        }
2828
-        $term_args = [
2829
-            'name'        => $category_name,
2830
-            'description' => $category_desc,
2831
-            'parent'      => $category_parent,
2832
-        ];
2833
-        // was the category_identifier input disabled?
2834
-        if ($category_identifier) {
2835
-            $term_args['slug'] = $category_identifier;
2836
-        }
2837
-        $insert_ids = $update
2838
-            ? wp_update_term($category_ID, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY, $term_args)
2839
-            : wp_insert_term($category_name, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY, $term_args);
2840
-        if (! is_array($insert_ids)) {
2841
-            $msg = esc_html__(
2842
-                'An error occurred and the category has not been saved to the database.',
2843
-                'event_espresso'
2844
-            );
2845
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2846
-        } else {
2847
-            $category_ID = $insert_ids['term_id'];
2848
-            $msg         = sprintf(
2849
-                esc_html__('The category %s was successfully saved', 'event_espresso'),
2850
-                $category_name
2851
-            );
2852
-            EE_Error::add_success($msg);
2853
-        }
2854
-        return $category_ID;
2855
-    }
2856
-
2857
-
2858
-    /**
2859
-     * Gets categories or count of categories matching the arguments in the request.
2860
-     *
2861
-     * @param int  $per_page
2862
-     * @param int  $current_page
2863
-     * @param bool $count
2864
-     * @return EE_Term_Taxonomy[]|int
2865
-     * @throws EE_Error
2866
-     */
2867
-    public function get_categories($per_page = 10, $current_page = 1, $count = false)
2868
-    {
2869
-        // testing term stuff
2870
-        $orderby     = $this->request->getRequestParam('orderby', 'Term.term_id');
2871
-        $order       = $this->request->getRequestParam('order', 'DESC');
2872
-        $limit       = ($current_page - 1) * $per_page;
2873
-        $where       = ['taxonomy' => EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY];
2874
-        $search_term = $this->request->getRequestParam('s');
2875
-        if ($search_term) {
2876
-            $search_term = '%' . $search_term . '%';
2877
-            $where['OR'] = [
2878
-                'Term.name'   => ['LIKE', $search_term],
2879
-                'description' => ['LIKE', $search_term],
2880
-            ];
2881
-        }
2882
-        $query_params = [
2883
-            $where,
2884
-            'order_by'   => [$orderby => $order],
2885
-            'limit'      => $limit . ',' . $per_page,
2886
-            'force_join' => ['Term'],
2887
-        ];
2888
-        return $count
2889
-            ? EEM_Term_Taxonomy::instance()->count($query_params, 'term_id')
2890
-            : EEM_Term_Taxonomy::instance()->get_all($query_params);
2891
-    }
2892
-
2893
-    /* end category stuff */
2894
-
2895
-
2896
-    /**************/
2897
-
2898
-
2899
-    /**
2900
-     * Callback for the `ee_save_timezone_setting` ajax action.
2901
-     *
2902
-     * @throws EE_Error
2903
-     * @throws InvalidArgumentException
2904
-     * @throws InvalidDataTypeException
2905
-     * @throws InvalidInterfaceException
2906
-     */
2907
-    public function saveTimezoneString()
2908
-    {
2909
-        $timezone_string = $this->request->getRequestParam('timezone_selected');
2910
-        if (empty($timezone_string) || ! EEH_DTT_Helper::validate_timezone($timezone_string, false)) {
2911
-            EE_Error::add_error(
2912
-                esc_html__('An invalid timezone string submitted.', 'event_espresso'),
2913
-                __FILE__,
2914
-                __FUNCTION__,
2915
-                __LINE__
2916
-            );
2917
-            $this->_template_args['error'] = true;
2918
-            $this->_return_json();
2919
-        }
2920
-
2921
-        update_option('timezone_string', $timezone_string);
2922
-        EE_Error::add_success(
2923
-            esc_html__('Your timezone string was updated.', 'event_espresso')
2924
-        );
2925
-        $this->_template_args['success'] = true;
2926
-        $this->_return_json(true, ['action' => 'create_new']);
2927
-    }
2928
-
2929
-
2930
-    /**
2931 2598
      * @throws EE_Error
2932
-     * @deprecated 4.10.25.p
2933 2599
      */
2934
-    public function save_timezonestring_setting()
2935
-    {
2936
-        $this->saveTimezoneString();
2937
-    }
2600
+	protected function _template_settings()
2601
+	{
2602
+		$this->_admin_page_title              = esc_html__('Template Settings (Preview)', 'event_espresso');
2603
+		$this->_template_args['preview_img']  = '<img src="'
2604
+												. EVENTS_ASSETS_URL
2605
+												. '/images/'
2606
+												. 'caffeinated_template_features.jpg" alt="'
2607
+												. esc_attr__('Template Settings Preview screenshot', 'event_espresso')
2608
+												. '" />';
2609
+		$this->_template_args['preview_text'] = '<strong>'
2610
+												. esc_html__(
2611
+													'Template Settings is a feature that is only available in the premium version of Event Espresso 4 which is available with a support license purchase on EventEspresso.com. Template Settings allow you to configure some of the appearance options for both the Event List and Event Details pages.',
2612
+													'event_espresso'
2613
+												) . '</strong>';
2614
+		$this->display_admin_caf_preview_page('template_settings_tab');
2615
+	}
2616
+
2617
+
2618
+	/** Event Category Stuff **/
2619
+	/**
2620
+	 * set the _category property with the category object for the loaded page.
2621
+	 *
2622
+	 * @access private
2623
+	 * @return void
2624
+	 */
2625
+	private function _set_category_object()
2626
+	{
2627
+		if (isset($this->_category->id) && ! empty($this->_category->id)) {
2628
+			return;
2629
+		} //already have the category object so get out.
2630
+		// set default category object
2631
+		$this->_set_empty_category_object();
2632
+		// only set if we've got an id
2633
+		$category_ID = $this->request->getRequestParam('EVT_CAT_ID', 0, 'int');
2634
+		if (! $category_ID) {
2635
+			return;
2636
+		}
2637
+		$term = get_term($category_ID, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY);
2638
+		if (! empty($term)) {
2639
+			$this->_category->category_name       = $term->name;
2640
+			$this->_category->category_identifier = $term->slug;
2641
+			$this->_category->category_desc       = $term->description;
2642
+			$this->_category->id                  = $term->term_id;
2643
+			$this->_category->parent              = $term->parent;
2644
+		}
2645
+	}
2646
+
2647
+
2648
+	/**
2649
+	 * Clears out category properties.
2650
+	 */
2651
+	private function _set_empty_category_object()
2652
+	{
2653
+		$this->_category                = new stdClass();
2654
+		$this->_category->category_name = $this->_category->category_identifier = $this->_category->category_desc = '';
2655
+		$this->_category->id            = $this->_category->parent = 0;
2656
+	}
2657
+
2658
+
2659
+	/**
2660
+	 * @throws DomainException
2661
+	 * @throws EE_Error
2662
+	 * @throws InvalidArgumentException
2663
+	 * @throws InvalidDataTypeException
2664
+	 * @throws InvalidInterfaceException
2665
+	 */
2666
+	protected function _category_list_table()
2667
+	{
2668
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2669
+		$this->_search_btn_label = esc_html__('Categories', 'event_espresso');
2670
+		$this->_admin_page_title .= ' ';
2671
+		$this->_admin_page_title .= $this->get_action_link_or_button(
2672
+			'add_category',
2673
+			'add_category',
2674
+			[],
2675
+			'add-new-h2'
2676
+		);
2677
+		$this->display_admin_list_table_page_with_sidebar();
2678
+	}
2679
+
2680
+
2681
+	/**
2682
+	 * Output category details view.
2683
+	 *
2684
+	 * @throws EE_Error
2685
+	 * @throws EE_Error
2686
+	 */
2687
+	protected function _category_details($view)
2688
+	{
2689
+		// load formatter helper
2690
+		// load field generator helper
2691
+		$route = $view === 'edit' ? 'update_category' : 'insert_category';
2692
+		$this->_set_add_edit_form_tags($route);
2693
+		$this->_set_category_object();
2694
+		$id            = ! empty($this->_category->id) ? $this->_category->id : '';
2695
+		$delete_action = 'delete_category';
2696
+		// custom redirect
2697
+		$redirect = EE_Admin_Page::add_query_args_and_nonce(
2698
+			['action' => 'category_list'],
2699
+			$this->_admin_base_url
2700
+		);
2701
+		$this->_set_publish_post_box_vars('EVT_CAT_ID', $id, $delete_action, $redirect);
2702
+		// take care of contents
2703
+		$this->_template_args['admin_page_content'] = $this->_category_details_content();
2704
+		$this->display_admin_page_with_sidebar();
2705
+	}
2706
+
2707
+
2708
+	/**
2709
+	 * Output category details content.
2710
+	 *
2711
+	 * @throws DomainException
2712
+	 */
2713
+	protected function _category_details_content()
2714
+	{
2715
+		$editor_args['category_desc'] = [
2716
+			'type'          => 'wp_editor',
2717
+			'value'         => EEH_Formatter::admin_format_content($this->_category->category_desc),
2718
+			'class'         => 'my_editor_custom',
2719
+			'wpeditor_args' => ['media_buttons' => false],
2720
+		];
2721
+		$_wp_editor                   = $this->_generate_admin_form_fields($editor_args, 'array');
2722
+		$all_terms                    = get_terms(
2723
+			[EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY],
2724
+			['hide_empty' => 0, 'exclude' => [$this->_category->id]]
2725
+		);
2726
+		// setup category select for term parents.
2727
+		$category_select_values[] = [
2728
+			'text' => esc_html__('No Parent', 'event_espresso'),
2729
+			'id'   => 0,
2730
+		];
2731
+		foreach ($all_terms as $term) {
2732
+			$category_select_values[] = [
2733
+				'text' => $term->name,
2734
+				'id'   => $term->term_id,
2735
+			];
2736
+		}
2737
+		$category_select = EEH_Form_Fields::select_input(
2738
+			'category_parent',
2739
+			$category_select_values,
2740
+			$this->_category->parent
2741
+		);
2742
+		$template_args   = [
2743
+			'category'                 => $this->_category,
2744
+			'category_select'          => $category_select,
2745
+			'unique_id_info_help_link' => $this->_get_help_tab_link('unique_id_info'),
2746
+			'category_desc_editor'     => $_wp_editor['category_desc']['field'],
2747
+			'disable'                  => '',
2748
+			'disabled_message'         => false,
2749
+		];
2750
+		$template        = EVENTS_TEMPLATE_PATH . 'event_category_details.template.php';
2751
+		return EEH_Template::display_template($template, $template_args, true);
2752
+	}
2753
+
2754
+
2755
+	/**
2756
+	 * Handles deleting categories.
2757
+	 *
2758
+	 * @throws EE_Error
2759
+	 */
2760
+	protected function _delete_categories()
2761
+	{
2762
+		$category_IDs = $this->request->getRequestParam('EVT_CAT_ID', 0, 'int', true);
2763
+		foreach ($category_IDs as $category_ID) {
2764
+			$this->_delete_category($category_ID);
2765
+		}
2766
+		// doesn't matter what page we're coming from... we're going to the same place after delete.
2767
+		$query_args = [
2768
+			'action' => 'category_list',
2769
+		];
2770
+		$this->_redirect_after_action(0, '', '', $query_args);
2771
+	}
2772
+
2773
+
2774
+	/**
2775
+	 * Handles deleting specific category.
2776
+	 *
2777
+	 * @param int $cat_id
2778
+	 */
2779
+	protected function _delete_category($cat_id)
2780
+	{
2781
+		$cat_id = absint($cat_id);
2782
+		wp_delete_term($cat_id, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY);
2783
+	}
2784
+
2785
+
2786
+	/**
2787
+	 * Handles triggering the update or insertion of a new category.
2788
+	 *
2789
+	 * @param bool $new_category true means we're triggering the insert of a new category.
2790
+	 * @throws EE_Error
2791
+	 * @throws EE_Error
2792
+	 */
2793
+	protected function _insert_or_update_category($new_category)
2794
+	{
2795
+		$cat_id  = $new_category ? $this->_insert_category() : $this->_insert_category(true);
2796
+		$success = 0; // we already have a success message so lets not send another.
2797
+		if ($cat_id) {
2798
+			$query_args = [
2799
+				'action'     => 'edit_category',
2800
+				'EVT_CAT_ID' => $cat_id,
2801
+			];
2802
+		} else {
2803
+			$query_args = ['action' => 'add_category'];
2804
+		}
2805
+		$this->_redirect_after_action($success, '', '', $query_args, true);
2806
+	}
2807
+
2808
+
2809
+	/**
2810
+	 * Inserts or updates category
2811
+	 *
2812
+	 * @param bool $update (true indicates we're updating a category).
2813
+	 * @return bool|mixed|string
2814
+	 */
2815
+	private function _insert_category($update = false)
2816
+	{
2817
+		$category_ID         = $update ? $this->request->getRequestParam('EVT_CAT_ID', 0, 'int') : 0;
2818
+		$category_name       = $this->request->getRequestParam('category_name', '');
2819
+		$category_desc       = $this->request->getRequestParam('category_desc', '');
2820
+		$category_parent     = $this->request->getRequestParam('category_parent', 0, 'int');
2821
+		$category_identifier = $this->request->getRequestParam('category_identifier', '');
2822
+
2823
+		if (empty($category_name)) {
2824
+			$msg = esc_html__('You must add a name for the category.', 'event_espresso');
2825
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2826
+			return false;
2827
+		}
2828
+		$term_args = [
2829
+			'name'        => $category_name,
2830
+			'description' => $category_desc,
2831
+			'parent'      => $category_parent,
2832
+		];
2833
+		// was the category_identifier input disabled?
2834
+		if ($category_identifier) {
2835
+			$term_args['slug'] = $category_identifier;
2836
+		}
2837
+		$insert_ids = $update
2838
+			? wp_update_term($category_ID, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY, $term_args)
2839
+			: wp_insert_term($category_name, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY, $term_args);
2840
+		if (! is_array($insert_ids)) {
2841
+			$msg = esc_html__(
2842
+				'An error occurred and the category has not been saved to the database.',
2843
+				'event_espresso'
2844
+			);
2845
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2846
+		} else {
2847
+			$category_ID = $insert_ids['term_id'];
2848
+			$msg         = sprintf(
2849
+				esc_html__('The category %s was successfully saved', 'event_espresso'),
2850
+				$category_name
2851
+			);
2852
+			EE_Error::add_success($msg);
2853
+		}
2854
+		return $category_ID;
2855
+	}
2856
+
2857
+
2858
+	/**
2859
+	 * Gets categories or count of categories matching the arguments in the request.
2860
+	 *
2861
+	 * @param int  $per_page
2862
+	 * @param int  $current_page
2863
+	 * @param bool $count
2864
+	 * @return EE_Term_Taxonomy[]|int
2865
+	 * @throws EE_Error
2866
+	 */
2867
+	public function get_categories($per_page = 10, $current_page = 1, $count = false)
2868
+	{
2869
+		// testing term stuff
2870
+		$orderby     = $this->request->getRequestParam('orderby', 'Term.term_id');
2871
+		$order       = $this->request->getRequestParam('order', 'DESC');
2872
+		$limit       = ($current_page - 1) * $per_page;
2873
+		$where       = ['taxonomy' => EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY];
2874
+		$search_term = $this->request->getRequestParam('s');
2875
+		if ($search_term) {
2876
+			$search_term = '%' . $search_term . '%';
2877
+			$where['OR'] = [
2878
+				'Term.name'   => ['LIKE', $search_term],
2879
+				'description' => ['LIKE', $search_term],
2880
+			];
2881
+		}
2882
+		$query_params = [
2883
+			$where,
2884
+			'order_by'   => [$orderby => $order],
2885
+			'limit'      => $limit . ',' . $per_page,
2886
+			'force_join' => ['Term'],
2887
+		];
2888
+		return $count
2889
+			? EEM_Term_Taxonomy::instance()->count($query_params, 'term_id')
2890
+			: EEM_Term_Taxonomy::instance()->get_all($query_params);
2891
+	}
2892
+
2893
+	/* end category stuff */
2894
+
2895
+
2896
+	/**************/
2897
+
2898
+
2899
+	/**
2900
+	 * Callback for the `ee_save_timezone_setting` ajax action.
2901
+	 *
2902
+	 * @throws EE_Error
2903
+	 * @throws InvalidArgumentException
2904
+	 * @throws InvalidDataTypeException
2905
+	 * @throws InvalidInterfaceException
2906
+	 */
2907
+	public function saveTimezoneString()
2908
+	{
2909
+		$timezone_string = $this->request->getRequestParam('timezone_selected');
2910
+		if (empty($timezone_string) || ! EEH_DTT_Helper::validate_timezone($timezone_string, false)) {
2911
+			EE_Error::add_error(
2912
+				esc_html__('An invalid timezone string submitted.', 'event_espresso'),
2913
+				__FILE__,
2914
+				__FUNCTION__,
2915
+				__LINE__
2916
+			);
2917
+			$this->_template_args['error'] = true;
2918
+			$this->_return_json();
2919
+		}
2920
+
2921
+		update_option('timezone_string', $timezone_string);
2922
+		EE_Error::add_success(
2923
+			esc_html__('Your timezone string was updated.', 'event_espresso')
2924
+		);
2925
+		$this->_template_args['success'] = true;
2926
+		$this->_return_json(true, ['action' => 'create_new']);
2927
+	}
2928
+
2929
+
2930
+	/**
2931
+	 * @throws EE_Error
2932
+	 * @deprecated 4.10.25.p
2933
+	 */
2934
+	public function save_timezonestring_setting()
2935
+	{
2936
+		$this->saveTimezoneString();
2937
+	}
2938 2938
 }
Please login to merge, or discard this patch.
Spacing   +90 added lines, -90 removed lines patch added patch discarded remove patch
@@ -434,7 +434,7 @@  discard block
 block discarded – undo
434 434
             // template settings
435 435
             'template_settings'      => [
436 436
                 'nav'           => [
437
-                    'label' => esc_html__( 'Templates', 'event_espresso'),
437
+                    'label' => esc_html__('Templates', 'event_espresso'),
438 438
                     'icon' => 'dashicons-layout',
439 439
                     'order' => 30,
440 440
                 ],
@@ -580,13 +580,13 @@  discard block
 block discarded – undo
580 580
     {
581 581
         wp_register_style(
582 582
             'events-admin-css',
583
-            EVENTS_ASSETS_URL . 'events-admin-page.css',
583
+            EVENTS_ASSETS_URL.'events-admin-page.css',
584 584
             [],
585 585
             EVENT_ESPRESSO_VERSION
586 586
         );
587 587
         wp_register_style(
588 588
             'ee-cat-admin',
589
-            EVENTS_ASSETS_URL . 'ee-cat-admin.css',
589
+            EVENTS_ASSETS_URL.'ee-cat-admin.css',
590 590
             [],
591 591
             EVENT_ESPRESSO_VERSION
592 592
         );
@@ -595,7 +595,7 @@  discard block
 block discarded – undo
595 595
         // scripts
596 596
         wp_register_script(
597 597
             'event_editor_js',
598
-            EVENTS_ASSETS_URL . 'event_editor.js',
598
+            EVENTS_ASSETS_URL.'event_editor.js',
599 599
             ['ee_admin_js', 'jquery-ui-slider', 'jquery-ui-timepicker-addon'],
600 600
             EVENT_ESPRESSO_VERSION,
601 601
             true
@@ -621,16 +621,16 @@  discard block
 block discarded – undo
621 621
         wp_enqueue_style('espresso-ui-theme');
622 622
         wp_register_style(
623 623
             'event-editor-css',
624
-            EVENTS_ASSETS_URL . 'event-editor.css',
624
+            EVENTS_ASSETS_URL.'event-editor.css',
625 625
             ['ee-admin-css'],
626 626
             EVENT_ESPRESSO_VERSION
627 627
         );
628 628
         wp_enqueue_style('event-editor-css');
629 629
         // scripts
630
-        if (! $this->admin_config->useAdvancedEditor()) {
630
+        if ( ! $this->admin_config->useAdvancedEditor()) {
631 631
             wp_register_script(
632 632
                 'event-datetime-metabox',
633
-                EVENTS_ASSETS_URL . 'event-datetime-metabox.js',
633
+                EVENTS_ASSETS_URL.'event-datetime-metabox.js',
634 634
                 ['event_editor_js', 'ee-datepicker'],
635 635
                 EVENT_ESPRESSO_VERSION
636 636
             );
@@ -700,15 +700,15 @@  discard block
 block discarded – undo
700 700
     public function verify_event_edit($event = null, $req_type = '')
701 701
     {
702 702
         // don't need to do this when processing
703
-        if (! empty($req_type)) {
703
+        if ( ! empty($req_type)) {
704 704
             return;
705 705
         }
706 706
         // no event?
707
-        if (! $event instanceof EE_Event) {
707
+        if ( ! $event instanceof EE_Event) {
708 708
             $event = $this->_cpt_model_obj;
709 709
         }
710 710
         // STILL no event?
711
-        if (! $event instanceof EE_Event) {
711
+        if ( ! $event instanceof EE_Event) {
712 712
             return;
713 713
         }
714 714
         $orig_status = $event->status();
@@ -748,7 +748,7 @@  discard block
 block discarded – undo
748 748
             );
749 749
         }
750 750
         // now we need to determine if the event has any tickets on sale.  If not then we dont' show the error
751
-        if (! $event->tickets_on_sale()) {
751
+        if ( ! $event->tickets_on_sale()) {
752 752
             return;
753 753
         }
754 754
         // made it here so show warning
@@ -796,7 +796,7 @@  discard block
 block discarded – undo
796 796
     {
797 797
         $has_timezone_string = get_option('timezone_string');
798 798
         // only nag them about setting their timezone if it's their first event, and they haven't already done it
799
-        if (! $has_timezone_string && ! EEM_Event::instance()->exists([])) {
799
+        if ( ! $has_timezone_string && ! EEM_Event::instance()->exists([])) {
800 800
             EE_Error::add_attention(
801 801
                 sprintf(
802 802
                     esc_html__(
@@ -865,7 +865,7 @@  discard block
 block discarded – undo
865 865
      */
866 866
     protected function _event_legend_items()
867 867
     {
868
-        $items    = [
868
+        $items = [
869 869
             'view_details'   => [
870 870
                 'class' => 'dashicons dashicons-visibility',
871 871
                 'desc'  => esc_html__('View Event', 'event_espresso'),
@@ -882,31 +882,31 @@  discard block
 block discarded – undo
882 882
         $items    = apply_filters('FHEE__Events_Admin_Page___event_legend_items__items', $items);
883 883
         $statuses = [
884 884
             'sold_out_status'  => [
885
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::sold_out,
885
+                'class' => 'ee-status-legend ee-status-bg--'.EE_Datetime::sold_out,
886 886
                 'desc'  => EEH_Template::pretty_status(EE_Datetime::sold_out, false, 'sentence'),
887 887
             ],
888 888
             'active_status'    => [
889
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::active,
889
+                'class' => 'ee-status-legend ee-status-bg--'.EE_Datetime::active,
890 890
                 'desc'  => EEH_Template::pretty_status(EE_Datetime::active, false, 'sentence'),
891 891
             ],
892 892
             'upcoming_status'  => [
893
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::upcoming,
893
+                'class' => 'ee-status-legend ee-status-bg--'.EE_Datetime::upcoming,
894 894
                 'desc'  => EEH_Template::pretty_status(EE_Datetime::upcoming, false, 'sentence'),
895 895
             ],
896 896
             'postponed_status' => [
897
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::postponed,
897
+                'class' => 'ee-status-legend ee-status-bg--'.EE_Datetime::postponed,
898 898
                 'desc'  => EEH_Template::pretty_status(EE_Datetime::postponed, false, 'sentence'),
899 899
             ],
900 900
             'cancelled_status' => [
901
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::cancelled,
901
+                'class' => 'ee-status-legend ee-status-bg--'.EE_Datetime::cancelled,
902 902
                 'desc'  => EEH_Template::pretty_status(EE_Datetime::cancelled, false, 'sentence'),
903 903
             ],
904 904
             'expired_status'   => [
905
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::expired,
905
+                'class' => 'ee-status-legend ee-status-bg--'.EE_Datetime::expired,
906 906
                 'desc'  => EEH_Template::pretty_status(EE_Datetime::expired, false, 'sentence'),
907 907
             ],
908 908
             'inactive_status'  => [
909
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::inactive,
909
+                'class' => 'ee-status-legend ee-status-bg--'.EE_Datetime::inactive,
910 910
                 'desc'  => EEH_Template::pretty_status(EE_Datetime::inactive, false, 'sentence'),
911 911
             ],
912 912
         ];
@@ -925,7 +925,7 @@  discard block
 block discarded – undo
925 925
      */
926 926
     private function _event_model()
927 927
     {
928
-        if (! $this->_event_model instanceof EEM_Event) {
928
+        if ( ! $this->_event_model instanceof EEM_Event) {
929 929
             $this->_event_model = EE_Registry::instance()->load_model('Event');
930 930
         }
931 931
         return $this->_event_model;
@@ -945,7 +945,7 @@  discard block
 block discarded – undo
945 945
     public function extra_permalink_field_buttons($return, $id, $new_title, $new_slug)
946 946
     {
947 947
         // make sure this is only when editing
948
-        if (! empty($id)) {
948
+        if ( ! empty($id)) {
949 949
             $post = get_post($id);
950 950
             $return .= '<a class="button button--small button--secondary" onclick="prompt(\'Shortcode:\', jQuery(\'#shortcode\').val()); return false;" href="#"  tabindex="-1">'
951 951
                        . esc_html__('Shortcode', 'event_espresso')
@@ -972,7 +972,7 @@  discard block
 block discarded – undo
972 972
      */
973 973
     protected function _events_overview_list_table()
974 974
     {
975
-        $after_list_table                           = [];
975
+        $after_list_table = [];
976 976
         $links_html = EEH_HTML::div('', '', 'ee-admin-section ee-layout-stack');
977 977
         $links_html .= EEH_HTML::h3(esc_html__('Links', 'event_espresso'));
978 978
         $links_html .= EEH_HTML::div(
@@ -989,14 +989,14 @@  discard block
 block discarded – undo
989 989
         $after_list_table['view_event_list_button'] = $links_html;
990 990
 
991 991
         $after_list_table['legend'] = $this->_display_legend($this->_event_legend_items());
992
-        $this->_admin_page_title                    .= ' ' . $this->get_action_link_or_button(
992
+        $this->_admin_page_title .= ' '.$this->get_action_link_or_button(
993 993
             'create_new',
994 994
             'add',
995 995
             [],
996 996
             'add-new-h2'
997 997
         );
998 998
 
999
-        $this->_template_args['after_list_table']   = array_merge(
999
+        $this->_template_args['after_list_table'] = array_merge(
1000 1000
             (array) $this->_template_args['after_list_table'],
1001 1001
             $after_list_table
1002 1002
         );
@@ -1053,13 +1053,13 @@  discard block
 block discarded – undo
1053 1053
             'EVT_timezone_string' => $this->request->getRequestParam('timezone_string'),
1054 1054
         ];
1055 1055
         // check if the new EDTR reg options meta box is being used, and if so, don't run updates for legacy version
1056
-        if (! $this->admin_config->useAdvancedEditor() || ! $this->feature->allowed('use_reg_options_meta_box')) {
1057
-            $event_values['EVT_display_ticket_selector']     = $this->request->getRequestParam(
1056
+        if ( ! $this->admin_config->useAdvancedEditor() || ! $this->feature->allowed('use_reg_options_meta_box')) {
1057
+            $event_values['EVT_display_ticket_selector'] = $this->request->getRequestParam(
1058 1058
                 'display_ticket_selector',
1059 1059
                 false,
1060 1060
                 'bool'
1061 1061
             );
1062
-            $event_values['EVT_additional_limit']            = min(
1062
+            $event_values['EVT_additional_limit'] = min(
1063 1063
                 apply_filters('FHEE__EE_Events_Admin__insert_update_cpt_item__EVT_additional_limit_max', 255),
1064 1064
                 $this->request->getRequestParam('additional_limit', null, 'int')
1065 1065
             );
@@ -1095,7 +1095,7 @@  discard block
 block discarded – undo
1095 1095
         // the following are default callbacks for event attachment updates
1096 1096
         // that can be overridden by caffeinated functionality and/or addons.
1097 1097
         $event_update_callbacks = [];
1098
-        if (! $this->admin_config->useAdvancedEditor()) {
1098
+        if ( ! $this->admin_config->useAdvancedEditor()) {
1099 1099
             $event_update_callbacks['_default_venue_update']   = [$this, '_default_venue_update'];
1100 1100
             $event_update_callbacks['_default_tickets_update'] = [$this, '_default_tickets_update'];
1101 1101
         }
@@ -1166,7 +1166,7 @@  discard block
 block discarded – undo
1166 1166
      */
1167 1167
     protected function _default_venue_update(EE_Event $event, $data)
1168 1168
     {
1169
-        require_once(EE_MODELS . 'EEM_Venue.model.php');
1169
+        require_once(EE_MODELS.'EEM_Venue.model.php');
1170 1170
         $venue_model = EE_Registry::instance()->load_model('Venue');
1171 1171
         $venue_id    = ! empty($data['venue_id']) ? $data['venue_id'] : null;
1172 1172
         // very important.  If we don't have a venue name...
@@ -1197,7 +1197,7 @@  discard block
 block discarded – undo
1197 1197
             'status'              => 'publish',
1198 1198
         ];
1199 1199
         // if we've got the venue_id then we're just updating the existing venue so let's do that and then get out.
1200
-        if (! empty($venue_id)) {
1200
+        if ( ! empty($venue_id)) {
1201 1201
             $update_where  = [$venue_model->primary_key_name() => $venue_id];
1202 1202
             $rows_affected = $venue_model->update($venue_array, [$update_where]);
1203 1203
             // we've gotta make sure that the venue is always attached to a revision..
@@ -1239,7 +1239,7 @@  discard block
 block discarded – undo
1239 1239
                 isset($datetime_data['DTT_EVT_end']) && ! empty($datetime_data['DTT_EVT_end'])
1240 1240
                     ? $datetime_data['DTT_EVT_end']
1241 1241
                     : $datetime_data['DTT_EVT_start'];
1242
-            $datetime_values              = [
1242
+            $datetime_values = [
1243 1243
                 'DTT_ID'        => ! empty($datetime_data['DTT_ID']) ? $datetime_data['DTT_ID'] : null,
1244 1244
                 'DTT_EVT_start' => $datetime_data['DTT_EVT_start'],
1245 1245
                 'DTT_EVT_end'   => $datetime_data['DTT_EVT_end'],
@@ -1248,9 +1248,9 @@  discard block
 block discarded – undo
1248 1248
             ];
1249 1249
             // if we have an id then let's get existing object first and then set the new values.
1250 1250
             //  Otherwise we instantiate a new object for save.
1251
-            if (! empty($datetime_data['DTT_ID'])) {
1251
+            if ( ! empty($datetime_data['DTT_ID'])) {
1252 1252
                 $datetime = EEM_Datetime::instance($event_timezone)->get_one_by_ID($datetime_data['DTT_ID']);
1253
-                if (! $datetime instanceof EE_Datetime) {
1253
+                if ( ! $datetime instanceof EE_Datetime) {
1254 1254
                     throw new RuntimeException(
1255 1255
                         sprintf(
1256 1256
                             esc_html__(
@@ -1269,7 +1269,7 @@  discard block
 block discarded – undo
1269 1269
             } else {
1270 1270
                 $datetime = EE_Datetime::new_instance($datetime_values, $event_timezone, $date_formats);
1271 1271
             }
1272
-            if (! $datetime instanceof EE_Datetime) {
1272
+            if ( ! $datetime instanceof EE_Datetime) {
1273 1273
                 throw new RuntimeException(
1274 1274
                     sprintf(
1275 1275
                         esc_html__(
@@ -1295,7 +1295,7 @@  discard block
 block discarded – undo
1295 1295
 
1296 1296
         // set up some default start and end dates in case those are not present in the incoming data
1297 1297
         $default_start_date = new DateTime('now', new DateTimeZone($event->get_timezone()));
1298
-        $default_start_date = $default_start_date->format($date_formats[0] . ' ' . $date_formats[1]);
1298
+        $default_start_date = $default_start_date->format($date_formats[0].' '.$date_formats[1]);
1299 1299
         // use the start date of the first datetime for the end date
1300 1300
         $first_datetime   = $event->first_datetime();
1301 1301
         $default_end_date = $first_datetime->start_date_and_time($date_formats[0], $date_formats[1]);
@@ -1303,8 +1303,8 @@  discard block
 block discarded – undo
1303 1303
         // now process the incoming data
1304 1304
         foreach ($data['edit_tickets'] as $row => $ticket_data) {
1305 1305
             $update_prices = false;
1306
-            $ticket_price  = isset($data['edit_prices'][ $row ][1]['PRC_amount'])
1307
-                ? $data['edit_prices'][ $row ][1]['PRC_amount']
1306
+            $ticket_price  = isset($data['edit_prices'][$row][1]['PRC_amount'])
1307
+                ? $data['edit_prices'][$row][1]['PRC_amount']
1308 1308
                 : 0;
1309 1309
             // trim inputs to ensure any excess whitespace is removed.
1310 1310
             $ticket_data   = array_map('trim', $ticket_data);
@@ -1345,9 +1345,9 @@  discard block
 block discarded – undo
1345 1345
             // ticket didn't get removed or added to any datetime in the session but DID have it's items modified.
1346 1346
             // keep in mind that if the ticket has been sold (and we have changed pricing information),
1347 1347
             // then we won't be updating the tkt but instead a new tkt will be created and the old one archived.
1348
-            if (! empty($ticket_data['TKT_ID'])) {
1348
+            if ( ! empty($ticket_data['TKT_ID'])) {
1349 1349
                 $existing_ticket = EEM_Ticket::instance($event_timezone)->get_one_by_ID($ticket_data['TKT_ID']);
1350
-                if (! $existing_ticket instanceof EE_Ticket) {
1350
+                if ( ! $existing_ticket instanceof EE_Ticket) {
1351 1351
                     throw new RuntimeException(
1352 1352
                         sprintf(
1353 1353
                             esc_html__(
@@ -1396,7 +1396,7 @@  discard block
 block discarded – undo
1396 1396
                     $existing_ticket->save();
1397 1397
                     // make sure this ticket is still recorded in our $saved_tickets
1398 1398
                     // so we don't run it through the regular trash routine.
1399
-                    $saved_tickets[ $existing_ticket->ID() ] = $existing_ticket;
1399
+                    $saved_tickets[$existing_ticket->ID()] = $existing_ticket;
1400 1400
                     // create new ticket that's a copy of the existing except,
1401 1401
                     // (a new id of course and not archived) AND has the new TKT_price associated with it.
1402 1402
                     $new_ticket = clone $existing_ticket;
@@ -1413,7 +1413,7 @@  discard block
 block discarded – undo
1413 1413
                 $ticket                     = EE_Ticket::new_instance($ticket_values, $event_timezone, $date_formats);
1414 1414
                 $update_prices              = true;
1415 1415
             }
1416
-            if (! $ticket instanceof EE_Ticket) {
1416
+            if ( ! $ticket instanceof EE_Ticket) {
1417 1417
                 throw new RuntimeException(
1418 1418
                     sprintf(
1419 1419
                         esc_html__(
@@ -1437,10 +1437,10 @@  discard block
 block discarded – undo
1437 1437
             }
1438 1438
             // initially let's add the ticket to the datetime
1439 1439
             $datetime->_add_relation_to($ticket, 'Ticket');
1440
-            $saved_tickets[ $ticket->ID() ] = $ticket;
1440
+            $saved_tickets[$ticket->ID()] = $ticket;
1441 1441
             // add prices to ticket
1442
-            $prices_data = isset($data['edit_prices'][ $row ]) && is_array($data['edit_prices'][ $row ])
1443
-                ? $data['edit_prices'][ $row ]
1442
+            $prices_data = isset($data['edit_prices'][$row]) && is_array($data['edit_prices'][$row])
1443
+                ? $data['edit_prices'][$row]
1444 1444
                 : [];
1445 1445
             $this->_add_prices_to_ticket($prices_data, $ticket, $update_prices);
1446 1446
         }
@@ -1454,7 +1454,7 @@  discard block
 block discarded – undo
1454 1454
             $id = absint($id);
1455 1455
             // get the ticket for this id
1456 1456
             $ticket_to_remove = EEM_Ticket::instance()->get_one_by_ID($id);
1457
-            if (! $ticket_to_remove instanceof EE_Ticket) {
1457
+            if ( ! $ticket_to_remove instanceof EE_Ticket) {
1458 1458
                 continue;
1459 1459
             }
1460 1460
             // need to get all the related datetimes on this ticket and remove from every single one of them
@@ -1511,7 +1511,7 @@  discard block
 block discarded – undo
1511 1511
                     $price->set($field, $new_price);
1512 1512
                 }
1513 1513
             }
1514
-            if (! $price instanceof EE_Price) {
1514
+            if ( ! $price instanceof EE_Price) {
1515 1515
                 throw new RuntimeException(
1516 1516
                     sprintf(
1517 1517
                         esc_html__(
@@ -1553,13 +1553,13 @@  discard block
 block discarded – undo
1553 1553
     {
1554 1554
         // load formatter helper
1555 1555
         // args for getting related registrations
1556
-        $approved_query_args        = [
1556
+        $approved_query_args = [
1557 1557
             [
1558 1558
                 'REG_deleted' => 0,
1559 1559
                 'STS_ID'      => EEM_Registration::status_id_approved,
1560 1560
             ],
1561 1561
         ];
1562
-        $not_approved_query_args    = [
1562
+        $not_approved_query_args = [
1563 1563
             [
1564 1564
                 'REG_deleted' => 0,
1565 1565
                 'STS_ID'      => EEM_Registration::status_id_not_approved,
@@ -1622,7 +1622,7 @@  discard block
 block discarded – undo
1622 1622
         $publish_box_extra_args['event_editor_overview_add'] = ob_get_clean();
1623 1623
         // load template
1624 1624
         EEH_Template::display_template(
1625
-            EVENTS_TEMPLATE_PATH . 'event_publish_box_extras.template.php',
1625
+            EVENTS_TEMPLATE_PATH.'event_publish_box_extras.template.php',
1626 1626
             $publish_box_extra_args
1627 1627
         );
1628 1628
     }
@@ -1653,7 +1653,7 @@  discard block
 block discarded – undo
1653 1653
         $this->verify_cpt_object();
1654 1654
         $use_advanced_editor = $this->admin_config->useAdvancedEditor();
1655 1655
         // check if the new EDTR reg options meta box is being used, and if so, don't load the legacy version
1656
-        if (! $use_advanced_editor || ! $this->feature->allowed('use_reg_options_meta_box')) {
1656
+        if ( ! $use_advanced_editor || ! $this->feature->allowed('use_reg_options_meta_box')) {
1657 1657
             $this->addMetaBox(
1658 1658
                 'espresso_event_editor_event_options',
1659 1659
                 esc_html__('Event Registration Options', 'event_espresso'),
@@ -1662,7 +1662,7 @@  discard block
 block discarded – undo
1662 1662
                 'side'
1663 1663
             );
1664 1664
         }
1665
-        if (! $use_advanced_editor) {
1665
+        if ( ! $use_advanced_editor) {
1666 1666
             $this->addMetaBox(
1667 1667
                 'espresso_event_editor_tickets',
1668 1668
                 esc_html__('Event Datetime & Ticket', 'event_espresso'),
@@ -1674,7 +1674,7 @@  discard block
 block discarded – undo
1674 1674
         } elseif ($this->feature->allowed('use_reg_options_meta_box')) {
1675 1675
             add_action(
1676 1676
                 'add_meta_boxes_espresso_events',
1677
-                function () {
1677
+                function() {
1678 1678
                     global $current_screen;
1679 1679
                     remove_meta_box('authordiv', $current_screen, 'normal');
1680 1680
                 },
@@ -1709,7 +1709,7 @@  discard block
 block discarded – undo
1709 1709
             'trash_icon'               => 'dashicons dashicons-lock',
1710 1710
             'disabled'                 => '',
1711 1711
         ];
1712
-        $event_id      = is_object($this->_cpt_model_obj) ? $this->_cpt_model_obj->ID() : null;
1712
+        $event_id = is_object($this->_cpt_model_obj) ? $this->_cpt_model_obj->ID() : null;
1713 1713
         /**
1714 1714
          * 1. Start with retrieving Datetimes
1715 1715
          * 2. Fore each datetime get related tickets
@@ -1735,24 +1735,24 @@  discard block
 block discarded – undo
1735 1735
                     'default_where_conditions' => 'none',
1736 1736
                 ]
1737 1737
             );
1738
-            if (! empty($related_tickets)) {
1738
+            if ( ! empty($related_tickets)) {
1739 1739
                 $template_args['total_ticket_rows'] = count($related_tickets);
1740 1740
                 $row                                = 0;
1741 1741
                 foreach ($related_tickets as $ticket) {
1742
-                    $existing_ticket_ids[]        = $ticket->get('TKT_ID');
1742
+                    $existing_ticket_ids[] = $ticket->get('TKT_ID');
1743 1743
                     $template_args['ticket_rows'] .= $this->_get_ticket_row($ticket, false, $row);
1744 1744
                     $row++;
1745 1745
                 }
1746 1746
             } else {
1747 1747
                 $template_args['total_ticket_rows'] = 1;
1748 1748
                 /** @type EE_Ticket $ticket */
1749
-                $ticket                       = $ticket_model->create_default_object();
1749
+                $ticket = $ticket_model->create_default_object();
1750 1750
                 $template_args['ticket_rows'] .= $this->_get_ticket_row($ticket);
1751 1751
             }
1752 1752
         } else {
1753 1753
             $template_args['time'] = $times[0];
1754 1754
             /** @type EE_Ticket[] $tickets */
1755
-            $tickets                      = $ticket_model->get_all_default_tickets();
1755
+            $tickets = $ticket_model->get_all_default_tickets();
1756 1756
             $template_args['ticket_rows'] .= $this->_get_ticket_row($tickets[1]);
1757 1757
             // NOTE: we're just sending the first default row
1758 1758
             // (decaf can't manage default tickets so this should be sufficient);
@@ -1767,9 +1767,9 @@  discard block
 block discarded – undo
1767 1767
             $ticket_model->create_default_object(),
1768 1768
             true
1769 1769
         );
1770
-        $template                                  = apply_filters(
1770
+        $template = apply_filters(
1771 1771
             'FHEE__Events_Admin_Page__ticket_metabox__template',
1772
-            EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_main.template.php'
1772
+            EVENTS_TEMPLATE_PATH.'event_tickets_metabox_main.template.php'
1773 1773
         );
1774 1774
         EEH_Template::display_template($template, $template_args);
1775 1775
     }
@@ -1789,7 +1789,7 @@  discard block
 block discarded – undo
1789 1789
     private function _get_ticket_row($ticket, $skeleton = false, $row = 0)
1790 1790
     {
1791 1791
         $template_args = [
1792
-            'tkt_status_class'    => ' tkt-status-' . $ticket->ticket_status(),
1792
+            'tkt_status_class'    => ' tkt-status-'.$ticket->ticket_status(),
1793 1793
             'tkt_archive_class'   => $ticket->ticket_status() === EE_Ticket::archived && ! $skeleton ? ' tkt-archived'
1794 1794
                 : '',
1795 1795
             'ticketrow'           => $skeleton ? 'TICKETNUM' : $row,
@@ -1801,10 +1801,10 @@  discard block
 block discarded – undo
1801 1801
             'TKT_qty'             => $ticket->get_pretty('TKT_qty', 'input'),
1802 1802
             'edit_ticketrow_name' => $skeleton ? 'TICKETNAMEATTR' : 'edit_tickets',
1803 1803
             'TKT_sold'            => $skeleton ? 0 : $ticket->get('TKT_sold'),
1804
-            'trash_icon'          => ($skeleton || (! empty($ticket) && ! $ticket->get('TKT_deleted')))
1805
-                                     && (! empty($ticket) && $ticket->get('TKT_sold') === 0)
1804
+            'trash_icon'          => ($skeleton || ( ! empty($ticket) && ! $ticket->get('TKT_deleted')))
1805
+                                     && ( ! empty($ticket) && $ticket->get('TKT_sold') === 0)
1806 1806
                 ? 'trash-icon dashicons dashicons-post-trash clickable' : 'dashicons dashicons-lock',
1807
-            'disabled'            => $skeleton || (! empty($ticket) && ! $ticket->get('TKT_deleted')) ? ''
1807
+            'disabled'            => $skeleton || ( ! empty($ticket) && ! $ticket->get('TKT_deleted')) ? ''
1808 1808
                 : ' disabled=disabled',
1809 1809
         ];
1810 1810
         $price         = $ticket->ID() !== 0
@@ -1828,7 +1828,7 @@  discard block
 block discarded – undo
1828 1828
         }
1829 1829
         if (empty($template_args['TKT_end_date'])) {
1830 1830
             // get the earliest datetime (if present);
1831
-            $earliest_datetime             = $this->_cpt_model_obj->ID() > 0
1831
+            $earliest_datetime = $this->_cpt_model_obj->ID() > 0
1832 1832
                 ? $this->_cpt_model_obj->get_first_related(
1833 1833
                     'Datetime',
1834 1834
                     ['order_by' => ['DTT_EVT_start' => 'ASC']]
@@ -1841,7 +1841,7 @@  discard block
 block discarded – undo
1841 1841
         $template_args = array_merge($template_args, $price_args);
1842 1842
         $template      = apply_filters(
1843 1843
             'FHEE__Events_Admin_Page__get_ticket_row__template',
1844
-            EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_ticket_row.template.php',
1844
+            EVENTS_TEMPLATE_PATH.'event_tickets_metabox_ticket_row.template.php',
1845 1845
             $ticket
1846 1846
         );
1847 1847
         return EEH_Template::display_template($template, $template_args, true);
@@ -1854,7 +1854,7 @@  discard block
 block discarded – undo
1854 1854
      */
1855 1855
     public function registration_options_meta_box()
1856 1856
     {
1857
-        $yes_no_values             = [
1857
+        $yes_no_values = [
1858 1858
             ['id' => true, 'text' => esc_html__('Yes', 'event_espresso')],
1859 1859
             ['id' => false, 'text' => esc_html__('No', 'event_espresso')],
1860 1860
         ];
@@ -1876,12 +1876,12 @@  discard block
 block discarded – undo
1876 1876
             $default_reg_status_values,
1877 1877
             $this->_cpt_model_obj->default_registration_status()
1878 1878
         );
1879
-        $template_args['display_description']             = EEH_Form_Fields::select_input(
1879
+        $template_args['display_description'] = EEH_Form_Fields::select_input(
1880 1880
             'display_desc',
1881 1881
             $yes_no_values,
1882 1882
             $this->_cpt_model_obj->display_description()
1883 1883
         );
1884
-        $template_args['display_ticket_selector']         = EEH_Form_Fields::select_input(
1884
+        $template_args['display_ticket_selector'] = EEH_Form_Fields::select_input(
1885 1885
             'display_ticket_selector',
1886 1886
             $yes_no_values,
1887 1887
             $this->_cpt_model_obj->display_ticket_selector(),
@@ -1897,7 +1897,7 @@  discard block
 block discarded – undo
1897 1897
             $default_reg_status_values
1898 1898
         );
1899 1899
         EEH_Template::display_template(
1900
-            EVENTS_TEMPLATE_PATH . 'event_registration_options.template.php',
1900
+            EVENTS_TEMPLATE_PATH.'event_registration_options.template.php',
1901 1901
             $template_args
1902 1902
         );
1903 1903
     }
@@ -1920,7 +1920,7 @@  discard block
 block discarded – undo
1920 1920
     {
1921 1921
         $EEM_Event   = $this->_event_model();
1922 1922
         $offset      = ($current_page - 1) * $per_page;
1923
-        $limit       = $count ? null : $offset . ',' . $per_page;
1923
+        $limit       = $count ? null : $offset.','.$per_page;
1924 1924
         $orderby     = $this->request->getRequestParam('orderby', 'EVT_ID');
1925 1925
         $order       = $this->request->getRequestParam('order', 'DESC');
1926 1926
         $month_range = $this->request->getRequestParam('month_range');
@@ -1957,10 +1957,10 @@  discard block
 block discarded – undo
1957 1957
         $start_formats = EEM_Datetime::instance()->get_formats_for('DTT_EVT_start');
1958 1958
         if ($month_range) {
1959 1959
             $DateTime = new DateTime(
1960
-                $year_r . '-' . $month_r . '-01 00:00:00',
1960
+                $year_r.'-'.$month_r.'-01 00:00:00',
1961 1961
                 new DateTimeZone('UTC')
1962 1962
             );
1963
-            $start    = $DateTime->getTimestamp();
1963
+            $start = $DateTime->getTimestamp();
1964 1964
             // set the datetime to be the end of the month
1965 1965
             $DateTime->setDate(
1966 1966
                 $year_r,
@@ -1985,11 +1985,11 @@  discard block
 block discarded – undo
1985 1985
                                                         ->format(implode(' ', $start_formats));
1986 1986
             $where['Datetime.DTT_EVT_start'] = ['BETWEEN', [$start, $end]];
1987 1987
         }
1988
-        if (! EE_Registry::instance()->CAP->current_user_can('ee_read_others_events', 'get_events')) {
1988
+        if ( ! EE_Registry::instance()->CAP->current_user_can('ee_read_others_events', 'get_events')) {
1989 1989
             $where['EVT_wp_user'] = get_current_user_id();
1990 1990
         } else {
1991
-            if (! isset($where['status'])) {
1992
-                if (! EE_Registry::instance()->CAP->current_user_can('ee_read_private_events', 'get_events')) {
1991
+            if ( ! isset($where['status'])) {
1992
+                if ( ! EE_Registry::instance()->CAP->current_user_can('ee_read_private_events', 'get_events')) {
1993 1993
                     $where['OR'] = [
1994 1994
                         'status*restrict_private' => ['!=', 'private'],
1995 1995
                         'AND'                     => [
@@ -2011,7 +2011,7 @@  discard block
 block discarded – undo
2011 2011
         // search query handling
2012 2012
         $search_term = $this->request->getRequestParam('s');
2013 2013
         if ($search_term) {
2014
-            $search_term = '%' . $search_term . '%';
2014
+            $search_term = '%'.$search_term.'%';
2015 2015
             $where['OR'] = [
2016 2016
                 'EVT_name'       => ['LIKE', $search_term],
2017 2017
                 'EVT_desc'       => ['LIKE', $search_term],
@@ -2119,7 +2119,7 @@  discard block
 block discarded – undo
2119 2119
             // clean status
2120 2120
             $event_status = sanitize_key($event_status);
2121 2121
             // grab status
2122
-            if (! empty($event_status)) {
2122
+            if ( ! empty($event_status)) {
2123 2123
                 $success = $this->_change_event_status($EVT_ID, $event_status);
2124 2124
             } else {
2125 2125
                 $success = false;
@@ -2159,7 +2159,7 @@  discard block
 block discarded – undo
2159 2159
         // clean status
2160 2160
         $event_status = sanitize_key($event_status);
2161 2161
         // grab status
2162
-        if (! empty($event_status)) {
2162
+        if ( ! empty($event_status)) {
2163 2163
             $success = true;
2164 2164
             // determine the event id and set to array.
2165 2165
             $EVT_IDs = $this->request->getRequestParam('EVT_IDs', [], 'int', true);
@@ -2205,7 +2205,7 @@  discard block
 block discarded – undo
2205 2205
     private function _change_event_status($EVT_ID = 0, $event_status = '')
2206 2206
     {
2207 2207
         // grab event id
2208
-        if (! $EVT_ID) {
2208
+        if ( ! $EVT_ID) {
2209 2209
             $msg = esc_html__(
2210 2210
                 'An error occurred. No Event ID or an invalid Event ID was received.',
2211 2211
                 'event_espresso'
@@ -2242,7 +2242,7 @@  discard block
 block discarded – undo
2242 2242
         // use class to change status
2243 2243
         $this->_cpt_model_obj->set_status($event_status);
2244 2244
         $success = $this->_cpt_model_obj->save();
2245
-        if (! $success) {
2245
+        if ( ! $success) {
2246 2246
             $msg = sprintf(esc_html__('An error occurred. The event could not be %s.', 'event_espresso'), $action);
2247 2247
             EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2248 2248
             return false;
@@ -2300,7 +2300,7 @@  discard block
 block discarded – undo
2300 2300
      */
2301 2301
     protected function getModelObjNodeGroupPersister()
2302 2302
     {
2303
-        if (! $this->model_obj_node_group_persister instanceof NodeGroupDao) {
2303
+        if ( ! $this->model_obj_node_group_persister instanceof NodeGroupDao) {
2304 2304
             $this->model_obj_node_group_persister =
2305 2305
                 $this->getLoader()->load('\EventEspresso\core\services\orm\tree_traversal\NodeGroupDao');
2306 2306
         }
@@ -2610,7 +2610,7 @@  discard block
 block discarded – undo
2610 2610
                                                 . esc_html__(
2611 2611
                                                     'Template Settings is a feature that is only available in the premium version of Event Espresso 4 which is available with a support license purchase on EventEspresso.com. Template Settings allow you to configure some of the appearance options for both the Event List and Event Details pages.',
2612 2612
                                                     'event_espresso'
2613
-                                                ) . '</strong>';
2613
+                                                ).'</strong>';
2614 2614
         $this->display_admin_caf_preview_page('template_settings_tab');
2615 2615
     }
2616 2616
 
@@ -2631,11 +2631,11 @@  discard block
 block discarded – undo
2631 2631
         $this->_set_empty_category_object();
2632 2632
         // only set if we've got an id
2633 2633
         $category_ID = $this->request->getRequestParam('EVT_CAT_ID', 0, 'int');
2634
-        if (! $category_ID) {
2634
+        if ( ! $category_ID) {
2635 2635
             return;
2636 2636
         }
2637 2637
         $term = get_term($category_ID, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY);
2638
-        if (! empty($term)) {
2638
+        if ( ! empty($term)) {
2639 2639
             $this->_category->category_name       = $term->name;
2640 2640
             $this->_category->category_identifier = $term->slug;
2641 2641
             $this->_category->category_desc       = $term->description;
@@ -2739,7 +2739,7 @@  discard block
 block discarded – undo
2739 2739
             $category_select_values,
2740 2740
             $this->_category->parent
2741 2741
         );
2742
-        $template_args   = [
2742
+        $template_args = [
2743 2743
             'category'                 => $this->_category,
2744 2744
             'category_select'          => $category_select,
2745 2745
             'unique_id_info_help_link' => $this->_get_help_tab_link('unique_id_info'),
@@ -2747,7 +2747,7 @@  discard block
 block discarded – undo
2747 2747
             'disable'                  => '',
2748 2748
             'disabled_message'         => false,
2749 2749
         ];
2750
-        $template        = EVENTS_TEMPLATE_PATH . 'event_category_details.template.php';
2750
+        $template = EVENTS_TEMPLATE_PATH.'event_category_details.template.php';
2751 2751
         return EEH_Template::display_template($template, $template_args, true);
2752 2752
     }
2753 2753
 
@@ -2837,7 +2837,7 @@  discard block
 block discarded – undo
2837 2837
         $insert_ids = $update
2838 2838
             ? wp_update_term($category_ID, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY, $term_args)
2839 2839
             : wp_insert_term($category_name, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY, $term_args);
2840
-        if (! is_array($insert_ids)) {
2840
+        if ( ! is_array($insert_ids)) {
2841 2841
             $msg = esc_html__(
2842 2842
                 'An error occurred and the category has not been saved to the database.',
2843 2843
                 'event_espresso'
@@ -2873,7 +2873,7 @@  discard block
 block discarded – undo
2873 2873
         $where       = ['taxonomy' => EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY];
2874 2874
         $search_term = $this->request->getRequestParam('s');
2875 2875
         if ($search_term) {
2876
-            $search_term = '%' . $search_term . '%';
2876
+            $search_term = '%'.$search_term.'%';
2877 2877
             $where['OR'] = [
2878 2878
                 'Term.name'   => ['LIKE', $search_term],
2879 2879
                 'description' => ['LIKE', $search_term],
@@ -2882,7 +2882,7 @@  discard block
 block discarded – undo
2882 2882
         $query_params = [
2883 2883
             $where,
2884 2884
             'order_by'   => [$orderby => $order],
2885
-            'limit'      => $limit . ',' . $per_page,
2885
+            'limit'      => $limit.','.$per_page,
2886 2886
             'force_join' => ['Term'],
2887 2887
         ];
2888 2888
         return $count
Please login to merge, or discard this patch.
admin_pages/messages/Messages_Admin_Page.core.php 1 patch
Indentation   +4650 added lines, -4650 removed lines patch added patch discarded remove patch
@@ -17,2690 +17,2690 @@  discard block
 block discarded – undo
17 17
  */
18 18
 class Messages_Admin_Page extends EE_Admin_Page
19 19
 {
20
-    /**
21
-     * @var EEM_Message
22
-     */
23
-    private $MSG_MODEL;
24
-
25
-    /**
26
-     * @var EEM_Message_Template
27
-     */
28
-    private $MTP_MODEL;
29
-
30
-    /**
31
-     * @var EEM_Message_Template_Group
32
-     */
33
-    private $MTG_MODEL;
34
-
35
-    /**
36
-     * @var EE_Message_Resource_Manager $_message_resource_manager
37
-     */
38
-    protected $_message_resource_manager;
39
-
40
-    /**
41
-     * @var string
42
-     */
43
-    protected $_active_message_type_name = '';
44
-
45
-    /**
46
-     * @var string
47
-     */
48
-    protected $_active_messenger_name = '';
49
-
50
-    /**
51
-     * @var EE_messenger $_active_messenger
52
-     */
53
-    protected $_active_messenger;
54
-
55
-    protected $_activate_meta_box_type;
56
-
57
-    protected $_current_message_meta_box;
58
-
59
-    protected $_current_message_meta_box_object;
60
-
61
-    protected $_context_switcher;
62
-
63
-    protected $_shortcodes           = [];
64
-
65
-    protected $_active_messengers    = [];
66
-
67
-    protected $_active_message_types = [];
68
-
69
-    /**
70
-     * @var EE_Message_Template_Group $_message_template_group
71
-     */
72
-    protected $_message_template_group;
73
-
74
-    protected $_m_mt_settings = [];
75
-
76
-
77
-    /**
78
-     * This is set via the _set_message_template_group method and holds whatever the template pack for the group is.
79
-     * IF there is no group then it gets automatically set to the Default template pack.
80
-     *
81
-     * @since 4.5.0
82
-     *
83
-     * @var EE_Messages_Template_Pack
84
-     */
85
-    protected $_template_pack;
86
-
87
-
88
-    /**
89
-     * This is set via the _set_message_template_group method and holds whatever the template pack variation for the
90
-     * group is.  If there is no group then it automatically gets set to default.
91
-     *
92
-     * @since 4.5.0
93
-     *
94
-     * @var string
95
-     */
96
-    protected $_variation;
97
-
98
-
99
-    /**
100
-     * @param bool $routing
101
-     * @throws EE_Error
102
-     * @throws ReflectionException
103
-     */
104
-    public function __construct($routing = true)
105
-    {
106
-        // make sure messages autoloader is running
107
-        EED_Messages::set_autoloaders();
108
-        parent::__construct($routing);
109
-    }
110
-
111
-
112
-    /**
113
-     * @return EEM_Message
114
-     * @throws EE_Error
115
-     */
116
-    public function getMsgModel()
117
-    {
118
-        if (! $this->MSG_MODEL instanceof EEM_Message) {
119
-            $this->MSG_MODEL = EEM_Message::instance();
120
-        }
121
-        return $this->MSG_MODEL;
122
-    }
123
-
124
-
125
-    /**
126
-     * @return EEM_Message_Template
127
-     * @throws EE_Error
128
-     */
129
-    public function getMtpModel()
130
-    {
131
-        if (! $this->MTP_MODEL instanceof EEM_Message_Template) {
132
-            $this->MTP_MODEL = EEM_Message_Template::instance();
133
-        }
134
-        return $this->MTP_MODEL;
135
-    }
136
-
137
-
138
-    /**
139
-     * @return EEM_Message_Template_Group
140
-     * @throws EE_Error
141
-     */
142
-    public function getMtgModel()
143
-    {
144
-        if (! $this->MTG_MODEL instanceof EEM_Message_Template_Group) {
145
-            $this->MTG_MODEL = EEM_Message_Template_Group::instance();
146
-        }
147
-        return $this->MTG_MODEL;
148
-    }
149
-
150
-
151
-    /**
152
-     * @throws EE_Error
153
-     * @throws ReflectionException
154
-     */
155
-    protected function _init_page_props()
156
-    {
157
-        $this->page_slug        = EE_MSG_PG_SLUG;
158
-        $this->page_label       = esc_html__('Messages Settings', 'event_espresso');
159
-        $this->_admin_base_url  = EE_MSG_ADMIN_URL;
160
-        $this->_admin_base_path = EE_MSG_ADMIN;
161
-
162
-        $messenger    = $this->request->getRequestParam('messenger', '');
163
-        $message_type = $this->request->getRequestParam('message_type', '');
164
-        $this->_active_messenger_name    = $this->request->getRequestParam('MTP_messenger', $messenger);
165
-        $this->_active_message_type_name = $this->request->getRequestParam('MTP_message_type', $message_type);
166
-
167
-        $this->_load_message_resource_manager();
168
-    }
169
-
170
-
171
-    /**
172
-     * loads messenger objects into the $_active_messengers property (so we can access the needed methods)
173
-     *
174
-     * @throws EE_Error
175
-     * @throws InvalidDataTypeException
176
-     * @throws InvalidInterfaceException
177
-     * @throws InvalidArgumentException
178
-     * @throws ReflectionException
179
-     */
180
-    protected function _load_message_resource_manager()
181
-    {
182
-        $this->_message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
183
-    }
184
-
185
-
186
-    /**
187
-     * @return array
188
-     * @throws EE_Error
189
-     * @throws InvalidArgumentException
190
-     * @throws InvalidDataTypeException
191
-     * @throws InvalidInterfaceException
192
-     * @deprecated 4.9.9.rc.014
193
-     */
194
-    public function get_messengers_for_list_table()
195
-    {
196
-        EE_Error::doing_it_wrong(
197
-            __METHOD__,
198
-            sprintf(
199
-                esc_html__(
200
-                    'This method is no longer in use.  There is no replacement for it. The method was used to generate a set of values for use in creating a messenger filter dropdown which is now generated differently via %s',
201
-                    'event_espresso'
202
-                ),
203
-                'Messages_Admin_Page::get_messengers_select_input()'
204
-            ),
205
-            '4.9.9.rc.014'
206
-        );
207
-
208
-        $m_values          = [];
209
-        $active_messengers = $this->getMsgModel()->get_all(['group_by' => 'MSG_messenger']);
210
-        // setup messengers for selects
211
-        $i = 1;
212
-        foreach ($active_messengers as $active_messenger) {
213
-            if ($active_messenger instanceof EE_Message) {
214
-                $m_values[ $i ]['id']   = $active_messenger->messenger();
215
-                $m_values[ $i ]['text'] = ucwords($active_messenger->messenger_label());
216
-                $i++;
217
-            }
218
-        }
219
-
220
-        return $m_values;
221
-    }
222
-
223
-
224
-    /**
225
-     * @return array
226
-     * @throws EE_Error
227
-     * @throws InvalidArgumentException
228
-     * @throws InvalidDataTypeException
229
-     * @throws InvalidInterfaceException
230
-     * @deprecated 4.9.9.rc.014
231
-     */
232
-    public function get_message_types_for_list_table()
233
-    {
234
-        EE_Error::doing_it_wrong(
235
-            __METHOD__,
236
-            sprintf(
237
-                esc_html__(
238
-                    'This method is no longer in use.  There is no replacement for it. The method was used to generate a set of values for use in creating a message type filter dropdown which is now generated differently via %s',
239
-                    'event_espresso'
240
-                ),
241
-                'Messages_Admin_Page::get_message_types_select_input()'
242
-            ),
243
-            '4.9.9.rc.014'
244
-        );
245
-
246
-        $mt_values       = [];
247
-        $active_messages = $this->getMsgModel()->get_all(['group_by' => 'MSG_message_type']);
248
-        $i               = 1;
249
-        foreach ($active_messages as $active_message) {
250
-            if ($active_message instanceof EE_Message) {
251
-                $mt_values[ $i ]['id']   = $active_message->message_type();
252
-                $mt_values[ $i ]['text'] = ucwords($active_message->message_type_label());
253
-                $i++;
254
-            }
255
-        }
256
-
257
-        return $mt_values;
258
-    }
259
-
260
-
261
-    /**
262
-     * @return array
263
-     * @throws EE_Error
264
-     * @throws InvalidArgumentException
265
-     * @throws InvalidDataTypeException
266
-     * @throws InvalidInterfaceException
267
-     * @deprecated 4.9.9.rc.014
268
-     */
269
-    public function get_contexts_for_message_types_for_list_table()
270
-    {
271
-        EE_Error::doing_it_wrong(
272
-            __METHOD__,
273
-            sprintf(
274
-                esc_html__(
275
-                    'This method is no longer in use.  There is no replacement for it. The method was used to generate a set of values for use in creating a message type context filter dropdown which is now generated differently via %s',
276
-                    'event_espresso'
277
-                ),
278
-                'Messages_Admin_Page::get_contexts_for_message_types_select_input()'
279
-            ),
280
-            '4.9.9.rc.014'
281
-        );
282
-
283
-        $contexts                = [];
284
-        $active_message_contexts = $this->getMsgModel()->get_all(['group_by' => 'MSG_context']);
285
-        foreach ($active_message_contexts as $active_message) {
286
-            if ($active_message instanceof EE_Message) {
287
-                $message_type = $active_message->message_type_object();
288
-                if ($message_type instanceof EE_message_type) {
289
-                    $message_type_contexts = $message_type->get_contexts();
290
-                    foreach ($message_type_contexts as $context => $context_details) {
291
-                        $contexts[ $context ] = $context_details['label'];
292
-                    }
293
-                }
294
-            }
295
-        }
296
-
297
-        return $contexts;
298
-    }
299
-
300
-
301
-    /**
302
-     * Generate select input with provided messenger options array.
303
-     *
304
-     * @param array $messenger_options Array of messengers indexed by messenger slug and values are the messenger
305
-     *                                 labels.
306
-     * @return string
307
-     * @throws EE_Error
308
-     */
309
-    public function get_messengers_select_input($messenger_options)
310
-    {
311
-        // if empty or just one value then just return an empty string
312
-        if (
313
-            empty($messenger_options)
314
-            || ! is_array($messenger_options)
315
-            || count($messenger_options) === 1
316
-        ) {
317
-            return '';
318
-        }
319
-        // merge in default
320
-        $messenger_options = array_merge(
321
-            ['none_selected' => esc_html__('Show All Messengers', 'event_espresso')],
322
-            $messenger_options
323
-        );
324
-        $input             = new EE_Select_Input(
325
-            $messenger_options,
326
-            [
327
-                'html_name'  => 'ee_messenger_filter_by',
328
-                'html_id'    => 'ee_messenger_filter_by',
329
-                'html_class' => 'wide',
330
-                'default'    => $this->request->getRequestParam('ee_messenger_filter_by', 'none_selected', 'title'),
331
-            ]
332
-        );
333
-
334
-        return $input->get_html_for_input();
335
-    }
336
-
337
-
338
-    /**
339
-     * Generate select input with provided message type options array.
340
-     *
341
-     * @param array $message_type_options Array of message types indexed by message type slug, and values are the
342
-     *                                    message type labels
343
-     * @return string
344
-     * @throws EE_Error
345
-     */
346
-    public function get_message_types_select_input($message_type_options)
347
-    {
348
-        // if empty or count of options is 1 then just return an empty string
349
-        if (
350
-            empty($message_type_options)
351
-            || ! is_array($message_type_options)
352
-            || count($message_type_options) === 1
353
-        ) {
354
-            return '';
355
-        }
356
-        // merge in default
357
-        $message_type_options = array_merge(
358
-            ['none_selected' => esc_html__('Show All Message Types', 'event_espresso')],
359
-            $message_type_options
360
-        );
361
-        $input                = new EE_Select_Input(
362
-            $message_type_options,
363
-            [
364
-                'html_name'  => 'ee_message_type_filter_by',
365
-                'html_id'    => 'ee_message_type_filter_by',
366
-                'html_class' => 'wide',
367
-                'default'    => $this->request->getRequestParam('ee_message_type_filter_by', 'none_selected', 'title'),
368
-            ]
369
-        );
370
-
371
-        return $input->get_html_for_input();
372
-    }
373
-
374
-
375
-    /**
376
-     * Generate select input with provide message type contexts array.
377
-     *
378
-     * @param array $context_options Array of message type contexts indexed by context slug, and values are the
379
-     *                               context label.
380
-     * @return string
381
-     * @throws EE_Error
382
-     */
383
-    public function get_contexts_for_message_types_select_input($context_options)
384
-    {
385
-        // if empty or count of options is one then just return empty string
386
-        if (
387
-            empty($context_options)
388
-            || ! is_array($context_options)
389
-            || count($context_options) === 1
390
-        ) {
391
-            return '';
392
-        }
393
-        // merge in default
394
-        $context_options = array_merge(
395
-            ['none_selected' => esc_html__('Show all Contexts', 'event_espresso')],
396
-            $context_options
397
-        );
398
-        $input           = new EE_Select_Input(
399
-            $context_options,
400
-            [
401
-                'html_name'  => 'ee_context_filter_by',
402
-                'html_id'    => 'ee_context_filter_by',
403
-                'html_class' => 'wide',
404
-                'default'    => $this->request->getRequestParam('ee_context_filter_by', 'none_selected', 'title'),
405
-            ]
406
-        );
407
-
408
-        return $input->get_html_for_input();
409
-    }
410
-
411
-
412
-    protected function _ajax_hooks()
413
-    {
414
-        add_action('wp_ajax_activate_messenger', [$this, 'activate_messenger_toggle']);
415
-        add_action('wp_ajax_activate_mt', [$this, 'activate_mt_toggle']);
416
-        add_action('wp_ajax_ee_msgs_save_settings', [$this, 'save_settings']);
417
-        add_action('wp_ajax_ee_msgs_update_mt_form', [$this, 'update_mt_form']);
418
-        add_action('wp_ajax_switch_template_pack', [$this, 'switch_template_pack']);
419
-        add_action('wp_ajax_toggle_context_template', [$this, 'toggle_context_template']);
420
-    }
421
-
422
-
423
-    protected function _define_page_props()
424
-    {
425
-        $this->_admin_page_title = $this->page_label;
426
-        $this->_labels           = [
427
-            'buttons'    => [
428
-                'add'    => esc_html__('Add New Message Template', 'event_espresso'),
429
-                'edit'   => esc_html__('Edit Message Template', 'event_espresso'),
430
-                'delete' => esc_html__('Delete Message Template', 'event_espresso'),
431
-            ],
432
-            'publishbox' => esc_html__('Update Actions', 'event_espresso'),
433
-        ];
434
-    }
435
-
436
-
437
-    /**
438
-     *        an array for storing key => value pairs of request actions and their corresponding methods
439
-     *
440
-     * @access protected
441
-     * @return void
442
-     */
443
-    protected function _set_page_routes()
444
-    {
445
-        $GRP_ID = $this->request->getRequestParam('GRP_ID', 0, 'int');
446
-        $GRP_ID = $this->request->getRequestParam('id', $GRP_ID, 'int');
447
-        $MSG_ID = $this->request->getRequestParam('MSG_ID', 0, 'int');
448
-
449
-        $this->_page_routes = [
450
-            'default'                          => [
451
-                'func'       => '_message_queue_list_table',
452
-                'capability' => 'ee_read_global_messages',
453
-            ],
454
-            'global_mtps'                      => [
455
-                'func'       => '_ee_default_messages_overview_list_table',
456
-                'capability' => 'ee_read_global_messages',
457
-            ],
458
-            'custom_mtps'                      => [
459
-                'func'       => '_custom_mtps_preview',
460
-                'capability' => 'ee_read_messages',
461
-            ],
462
-            'add_new_message_template'         => [
463
-                'func'       => 'add_message_template',
464
-                'capability' => 'ee_edit_messages',
465
-                'noheader'   => true,
466
-            ],
467
-            'edit_message_template'            => [
468
-                'func'       => '_edit_message_template',
469
-                'capability' => 'ee_edit_message',
470
-                'obj_id'     => $GRP_ID,
471
-            ],
472
-            'preview_message'                  => [
473
-                'func'               => '_preview_message',
474
-                'capability'         => 'ee_read_message',
475
-                'obj_id'             => $GRP_ID,
476
-                'noheader'           => true,
477
-                'headers_sent_route' => 'display_preview_message',
478
-            ],
479
-            'display_preview_message'          => [
480
-                'func'       => '_display_preview_message',
481
-                'capability' => 'ee_read_message',
482
-                'obj_id'     => $GRP_ID,
483
-            ],
484
-            'insert_message_template'          => [
485
-                'func'       => '_insert_or_update_message_template',
486
-                'capability' => 'ee_edit_messages',
487
-                'args'       => ['new' => true],
488
-                'noheader'   => true,
489
-            ],
490
-            'update_message_template'          => [
491
-                'func'       => '_insert_or_update_message_template',
492
-                'capability' => 'ee_edit_message',
493
-                'obj_id'     => $GRP_ID,
494
-                'args'       => ['new' => false],
495
-                'noheader'   => true,
496
-            ],
497
-            'trash_message_template'           => [
498
-                'func'       => '_trash_or_restore_message_template',
499
-                'capability' => 'ee_delete_message',
500
-                'obj_id'     => $GRP_ID,
501
-                'args'       => ['trash' => true, 'all' => true],
502
-                'noheader'   => true,
503
-            ],
504
-            'trash_message_template_context'   => [
505
-                'func'       => '_trash_or_restore_message_template',
506
-                'capability' => 'ee_delete_message',
507
-                'obj_id'     => $GRP_ID,
508
-                'args'       => ['trash' => true],
509
-                'noheader'   => true,
510
-            ],
511
-            'restore_message_template'         => [
512
-                'func'       => '_trash_or_restore_message_template',
513
-                'capability' => 'ee_delete_message',
514
-                'obj_id'     => $GRP_ID,
515
-                'args'       => ['trash' => false, 'all' => true],
516
-                'noheader'   => true,
517
-            ],
518
-            'restore_message_template_context' => [
519
-                'func'       => '_trash_or_restore_message_template',
520
-                'capability' => 'ee_delete_message',
521
-                'obj_id'     => $GRP_ID,
522
-                'args'       => ['trash' => false],
523
-                'noheader'   => true,
524
-            ],
525
-            'delete_message_template'          => [
526
-                'func'       => '_delete_message_template',
527
-                'capability' => 'ee_delete_message',
528
-                'obj_id'     => $GRP_ID,
529
-                'noheader'   => true,
530
-            ],
531
-            'reset_to_default'                 => [
532
-                'func'       => '_reset_to_default_template',
533
-                'capability' => 'ee_edit_message',
534
-                'obj_id'     => $GRP_ID,
535
-                'noheader'   => true,
536
-            ],
537
-            'settings'                         => [
538
-                'func'       => '_settings',
539
-                'capability' => 'manage_options',
540
-            ],
541
-            'update_global_settings'           => [
542
-                'func'       => '_update_global_settings',
543
-                'capability' => 'manage_options',
544
-                'noheader'   => true,
545
-            ],
546
-            'generate_now'                     => [
547
-                'func'       => '_generate_now',
548
-                'capability' => 'ee_send_message',
549
-                'noheader'   => true,
550
-            ],
551
-            'generate_and_send_now'            => [
552
-                'func'       => '_generate_and_send_now',
553
-                'capability' => 'ee_send_message',
554
-                'noheader'   => true,
555
-            ],
556
-            'queue_for_resending'              => [
557
-                'func'       => '_queue_for_resending',
558
-                'capability' => 'ee_send_message',
559
-                'noheader'   => true,
560
-            ],
561
-            'send_now'                         => [
562
-                'func'       => '_send_now',
563
-                'capability' => 'ee_send_message',
564
-                'noheader'   => true,
565
-            ],
566
-            'delete_ee_message'                => [
567
-                'func'       => '_delete_ee_messages',
568
-                'capability' => 'ee_delete_messages',
569
-                'noheader'   => true,
570
-            ],
571
-            'delete_ee_messages'               => [
572
-                'func'       => '_delete_ee_messages',
573
-                'capability' => 'ee_delete_messages',
574
-                'noheader'   => true,
575
-                'obj_id'     => $MSG_ID,
576
-            ],
577
-        ];
578
-    }
579
-
580
-
581
-    protected function _set_page_config()
582
-    {
583
-        $this->_page_config = [
584
-            'default'                  => [
585
-                'nav'           => [
586
-                    'label' => esc_html__('Message Activity', 'event_espresso'),
587
-                    'icon' => 'dashicons-email',
588
-                    'order' => 10,
589
-                ],
590
-                'list_table'    => 'EE_Message_List_Table',
591
-                // 'qtips' => array( 'EE_Message_List_Table_Tips' ),
592
-                'require_nonce' => false,
593
-            ],
594
-            'global_mtps'              => [
595
-                'nav'           => [
596
-                    'label' => esc_html__('Default Message Templates', 'event_espresso'),
597
-                    'icon' => 'dashicons-layout',
598
-                    'order' => 20,
599
-                ],
600
-                'list_table'    => 'Messages_Template_List_Table',
601
-                'help_tabs'     => [
602
-                    'messages_overview_help_tab'                                => [
603
-                        'title'    => esc_html__('Messages Overview', 'event_espresso'),
604
-                        'filename' => 'messages_overview',
605
-                    ],
606
-                    'messages_overview_messages_table_column_headings_help_tab' => [
607
-                        'title'    => esc_html__('Messages Table Column Headings', 'event_espresso'),
608
-                        'filename' => 'messages_overview_table_column_headings',
609
-                    ],
610
-                    'messages_overview_messages_filters_help_tab'               => [
611
-                        'title'    => esc_html__('Message Filters', 'event_espresso'),
612
-                        'filename' => 'messages_overview_filters',
613
-                    ],
614
-                    'messages_overview_messages_views_help_tab'                 => [
615
-                        'title'    => esc_html__('Message Views', 'event_espresso'),
616
-                        'filename' => 'messages_overview_views',
617
-                    ],
618
-                    'message_overview_message_types_help_tab'                   => [
619
-                        'title'    => esc_html__('Message Types', 'event_espresso'),
620
-                        'filename' => 'messages_overview_types',
621
-                    ],
622
-                    'messages_overview_messengers_help_tab'                     => [
623
-                        'title'    => esc_html__('Messengers', 'event_espresso'),
624
-                        'filename' => 'messages_overview_messengers',
625
-                    ],
626
-                ],
627
-                'require_nonce' => false,
628
-            ],
629
-            'custom_mtps'              => [
630
-                'nav'           => [
631
-                    'label' => esc_html__('Custom Message Templates', 'event_espresso'),
632
-                    'icon' => 'dashicons-admin-customizer',
633
-                    'order' => 30,
634
-                ],
635
-                'help_tabs'     => [],
636
-                'require_nonce' => false,
637
-            ],
638
-            'add_new_message_template' => [
639
-                'nav'           => [
640
-                    'label'      => esc_html__('Add New Message Templates', 'event_espresso'),
641
-                    'icon' => 'dashicons-plus-alt',
642
-                    'order'      => 5,
643
-                    'persistent' => false,
644
-                ],
645
-                'require_nonce' => false,
646
-            ],
647
-            'edit_message_template'    => [
648
-                'labels'        => [
649
-                    'buttons'    => [
650
-                        'reset' => esc_html__('Reset Templates', 'event_espresso'),
651
-                    ],
652
-                    'publishbox' => esc_html__('Update Actions', 'event_espresso'),
653
-                ],
654
-                'nav'           => [
655
-                    'label'      => esc_html__('Edit Message Templates', 'event_espresso'),
656
-                    'icon' => 'dashicons-edit-large',
657
-                    'order'      => 5,
658
-                    'persistent' => false,
659
-                    'url'        => '',
660
-                ],
661
-                'metaboxes'     => ['_publish_post_box', '_register_edit_meta_boxes'],
662
-                'has_metaboxes' => true,
663
-                'help_tabs'     => [
664
-                    'edit_message_template'            => [
665
-                        'title'    => esc_html__('Message Template Editor', 'event_espresso'),
666
-                        'callback' => 'edit_message_template_help_tab',
667
-                    ],
668
-                    'message_templates_help_tab'       => [
669
-                        'title'    => esc_html__('Message Templates', 'event_espresso'),
670
-                        'filename' => 'messages_templates',
671
-                    ],
672
-                    'message_template_shortcodes'      => [
673
-                        'title'    => esc_html__('Message Shortcodes', 'event_espresso'),
674
-                        'callback' => 'message_template_shortcodes_help_tab',
675
-                    ],
676
-                    'message_preview_help_tab'         => [
677
-                        'title'    => esc_html__('Message Preview', 'event_espresso'),
678
-                        'filename' => 'messages_preview',
679
-                    ],
680
-                    'messages_overview_other_help_tab' => [
681
-                        'title'    => esc_html__('Messages Other', 'event_espresso'),
682
-                        'filename' => 'messages_overview_other',
683
-                    ],
684
-                ],
685
-                'require_nonce' => false,
686
-            ],
687
-            'display_preview_message'  => [
688
-                'nav'           => [
689
-                    'label'      => esc_html__('Message Preview', 'event_espresso'),
690
-                    'icon' => 'dashicons-visibility-bar',
691
-                    'order'      => 5,
692
-                    'url'        => '',
693
-                    'persistent' => false,
694
-                ],
695
-                'help_tabs'     => [
696
-                    'preview_message' => [
697
-                        'title'    => esc_html__('About Previews', 'event_espresso'),
698
-                        'callback' => 'preview_message_help_tab',
699
-                    ],
700
-                ],
701
-                'require_nonce' => false,
702
-            ],
703
-            'settings'                 => [
704
-                'nav'           => [
705
-                    'label' => esc_html__('Settings', 'event_espresso'),
706
-                    'icon' => 'dashicons-admin-generic',
707
-                    'order' => 40,
708
-                ],
709
-                'metaboxes'     => ['_messages_settings_metaboxes'],
710
-                'help_tabs'     => [
711
-                    'messages_settings_help_tab'               => [
712
-                        'title'    => esc_html__('Messages Settings', 'event_espresso'),
713
-                        'filename' => 'messages_settings',
714
-                    ],
715
-                    'messages_settings_message_types_help_tab' => [
716
-                        'title'    => esc_html__('Activating / Deactivating Message Types', 'event_espresso'),
717
-                        'filename' => 'messages_settings_message_types',
718
-                    ],
719
-                    'messages_settings_messengers_help_tab'    => [
720
-                        'title'    => esc_html__('Activating / Deactivating Messengers', 'event_espresso'),
721
-                        'filename' => 'messages_settings_messengers',
722
-                    ],
723
-                ],
724
-                'require_nonce' => false,
725
-            ],
726
-        ];
727
-    }
728
-
729
-
730
-    protected function _add_screen_options()
731
-    {
732
-        // todo
733
-    }
734
-
735
-
736
-    protected function _add_screen_options_global_mtps()
737
-    {
738
-        /**
739
-         * Note: the reason for the value swap here on $this->_admin_page_title is because $this->_per_page_screen_options
740
-         * uses the $_admin_page_title property and we want different outputs in the different spots.
741
-         */
742
-        $page_title              = $this->_admin_page_title;
743
-        $this->_admin_page_title = esc_html__('Global Message Templates', 'event_espresso');
744
-        $this->_per_page_screen_option();
745
-        $this->_admin_page_title = $page_title;
746
-    }
747
-
748
-
749
-    protected function _add_screen_options_default()
750
-    {
751
-        $this->_admin_page_title = esc_html__('Message Activity', 'event_espresso');
752
-        $this->_per_page_screen_option();
753
-    }
754
-
755
-
756
-    // none of the below group are currently used for Messages
757
-    protected function _add_feature_pointers()
758
-    {
759
-    }
760
-
761
-
762
-    public function admin_init()
763
-    {
764
-    }
765
-
766
-
767
-    public function admin_notices()
768
-    {
769
-    }
770
-
771
-
772
-    public function admin_footer_scripts()
773
-    {
774
-    }
775
-
776
-
777
-    public function messages_help_tab()
778
-    {
779
-        EEH_Template::display_template(EE_MSG_TEMPLATE_PATH . 'ee_msg_messages_help_tab.template.php');
780
-    }
781
-
782
-
783
-    public function messengers_help_tab()
784
-    {
785
-        EEH_Template::display_template(EE_MSG_TEMPLATE_PATH . 'ee_msg_messenger_help_tab.template.php');
786
-    }
787
-
788
-
789
-    public function message_types_help_tab()
790
-    {
791
-        EEH_Template::display_template(EE_MSG_TEMPLATE_PATH . 'ee_msg_message_type_help_tab.template.php');
792
-    }
793
-
794
-
795
-    public function messages_overview_help_tab()
796
-    {
797
-        EEH_Template::display_template(EE_MSG_TEMPLATE_PATH . 'ee_msg_overview_help_tab.template.php');
798
-    }
799
-
800
-
801
-    public function message_templates_help_tab()
802
-    {
803
-        EEH_Template::display_template(EE_MSG_TEMPLATE_PATH . 'ee_msg_message_templates_help_tab.template.php');
804
-    }
805
-
806
-
807
-    public function edit_message_template_help_tab()
808
-    {
809
-        $args['img1'] = '<img src="' . EE_MSG_ASSETS_URL . 'images/editor.png' . '" alt="'
810
-                        . esc_attr__('Editor Title', 'event_espresso')
811
-                        . '" />';
812
-        $args['img2'] = '<img src="' . EE_MSG_ASSETS_URL . 'images/switch-context.png' . '" alt="'
813
-                        . esc_attr__('Context Switcher and Preview', 'event_espresso')
814
-                        . '" />';
815
-        $args['img3'] = '<img class="left" src="' . EE_MSG_ASSETS_URL . 'images/form-fields.png' . '" alt="'
816
-                        . esc_attr__('Message Template Form Fields', 'event_espresso')
817
-                        . '" />';
818
-        $args['img4'] = '<img class="right" src="' . EE_MSG_ASSETS_URL . 'images/shortcodes-metabox.png' . '" alt="'
819
-                        . esc_attr__('Shortcodes Metabox', 'event_espresso')
820
-                        . '" />';
821
-        $args['img5'] = '<img class="right" src="' . EE_MSG_ASSETS_URL . 'images/publish-meta-box.png' . '" alt="'
822
-                        . esc_attr__('Publish Metabox', 'event_espresso')
823
-                        . '" />';
824
-        EEH_Template::display_template(
825
-            EE_MSG_TEMPLATE_PATH . 'ee_msg_messages_templates_editor_help_tab.template.php',
826
-            $args
827
-        );
828
-    }
829
-
830
-
831
-    /**
832
-     * @throws ReflectionException
833
-     * @throws EE_Error
834
-     */
835
-    public function message_template_shortcodes_help_tab()
836
-    {
837
-        $this->_set_shortcodes();
838
-        $args['shortcodes'] = $this->_shortcodes;
839
-        EEH_Template::display_template(
840
-            EE_MSG_TEMPLATE_PATH . 'ee_msg_messages_shortcodes_help_tab.template.php',
841
-            $args
842
-        );
843
-    }
844
-
845
-
846
-    public function preview_message_help_tab()
847
-    {
848
-        EEH_Template::display_template(EE_MSG_TEMPLATE_PATH . 'ee_msg_preview_help_tab.template.php');
849
-    }
850
-
851
-
852
-    public function settings_help_tab()
853
-    {
854
-        $args['img1'] = '<img class="inline-text" src="' . EE_MSG_ASSETS_URL . 'images/email-tab-active.png'
855
-                        . '" alt="' . esc_attr__('Active Email Tab', 'event_espresso') . '" />';
856
-        $args['img2'] = '<img class="inline-text" src="' . EE_MSG_ASSETS_URL . 'images/email-tab-inactive.png'
857
-                        . '" alt="' . esc_attr__('Inactive Email Tab', 'event_espresso') . '" />';
858
-        $args['img3'] = '<div class="switch">'
859
-                        . '<input class="ee-on-off-toggle ee-toggle-round-flat"'
860
-                        . ' type="checkbox" checked>'
861
-                        . '<label for="ee-on-off-toggle-on"></label>'
862
-                        . '</div>';
863
-        $args['img4'] = '<div class="switch">'
864
-                        . '<input class="ee-on-off-toggle ee-toggle-round-flat"'
865
-                        . ' type="checkbox">'
866
-                        . '<label for="ee-on-off-toggle-on"></label>'
867
-                        . '</div>';
868
-        EEH_Template::display_template(EE_MSG_TEMPLATE_PATH . 'ee_msg_messages_settings_help_tab.template.php', $args);
869
-    }
870
-
871
-
872
-    public function load_scripts_styles()
873
-    {
874
-        wp_register_style('espresso_ee_msg', EE_MSG_ASSETS_URL . 'ee_message_admin.css', EVENT_ESPRESSO_VERSION);
875
-        wp_enqueue_style('espresso_ee_msg');
876
-
877
-        wp_register_script(
878
-            'ee-messages-settings',
879
-            EE_MSG_ASSETS_URL . 'ee-messages-settings.js',
880
-            ['jquery-ui-droppable', 'ee-serialize-full-array'],
881
-            EVENT_ESPRESSO_VERSION,
882
-            true
883
-        );
884
-        wp_register_script(
885
-            'ee-msg-list-table-js',
886
-            EE_MSG_ASSETS_URL . 'ee_message_admin_list_table.js',
887
-            ['ee-dialog'],
888
-            EVENT_ESPRESSO_VERSION
889
-        );
890
-    }
891
-
892
-
893
-    public function load_scripts_styles_default()
894
-    {
895
-        wp_enqueue_script('ee-msg-list-table-js');
896
-    }
897
-
898
-
899
-    public function wp_editor_css($mce_css)
900
-    {
901
-        // if we're on the edit_message_template route
902
-        if ($this->_req_action === 'edit_message_template' && $this->_active_messenger instanceof EE_messenger) {
903
-            $message_type_name = $this->_active_message_type_name;
904
-
905
-            // we're going to REPLACE the existing mce css
906
-            // we need to get the css file location from the active messenger
907
-            $mce_css = $this->_active_messenger->get_variation(
908
-                $this->_template_pack,
909
-                $message_type_name,
910
-                true,
911
-                'wpeditor',
912
-                $this->_variation
913
-            );
914
-        }
915
-
916
-        return $mce_css;
917
-    }
918
-
919
-
920
-    /**
921
-     * @throws EE_Error
922
-     * @throws ReflectionException
923
-     */
924
-    public function load_scripts_styles_edit_message_template()
925
-    {
926
-
927
-        $this->_set_shortcodes();
928
-
929
-        EE_Registry::$i18n_js_strings['confirm_default_reset']        = sprintf(
930
-            esc_html__(
931
-                'Are you sure you want to reset the %s %s message templates?  Remember continuing will reset the templates for all contexts in this messenger and message type group.',
932
-                'event_espresso'
933
-            ),
934
-            $this->_message_template_group->messenger_obj()->label['singular'],
935
-            $this->_message_template_group->message_type_obj()->label['singular']
936
-        );
937
-        EE_Registry::$i18n_js_strings['confirm_switch_template_pack'] = esc_html__(
938
-            'Switching the template pack for a messages template will reset the content for the template so the new layout is loaded.  Any custom content in the existing template will be lost. Are you sure you wish to do this?',
939
-            'event_espresso'
940
-        );
941
-        EE_Registry::$i18n_js_strings['server_error']                 = esc_html__(
942
-            'An unknown error occurred on the server while attempting to process your request. Please refresh the page and try again or contact support.',
943
-            'event_espresso'
944
-        );
945
-
946
-        wp_register_script(
947
-            'ee_msgs_edit_js',
948
-            EE_MSG_ASSETS_URL . 'ee_message_editor.js',
949
-            ['jquery'],
950
-            EVENT_ESPRESSO_VERSION
951
-        );
952
-
953
-        wp_enqueue_script('ee_admin_js');
954
-        wp_enqueue_script('ee_msgs_edit_js');
955
-
956
-        // add in special css for tiny_mce
957
-        add_filter('mce_css', [$this, 'wp_editor_css']);
958
-    }
959
-
960
-
961
-    /**
962
-     * @throws EE_Error
963
-     * @throws ReflectionException
964
-     */
965
-    public function load_scripts_styles_display_preview_message()
966
-    {
967
-        $this->_set_message_template_group();
968
-        if ($this->_active_messenger_name) {
969
-            $this->_active_messenger = $this->_message_resource_manager->get_active_messenger(
970
-                $this->_active_messenger_name
971
-            );
972
-        }
973
-
974
-        wp_enqueue_style(
975
-            'espresso_preview_css',
976
-            $this->_active_messenger->get_variation(
977
-                $this->_template_pack,
978
-                $this->_active_message_type_name,
979
-                true,
980
-                'preview',
981
-                $this->_variation
982
-            )
983
-        );
984
-    }
985
-
986
-
987
-    public function load_scripts_styles_settings()
988
-    {
989
-        wp_register_style(
990
-            'ee-message-settings',
991
-            EE_MSG_ASSETS_URL . 'ee_message_settings.css',
992
-            [],
993
-            EVENT_ESPRESSO_VERSION
994
-        );
995
-        wp_enqueue_style('ee-text-links');
996
-        wp_enqueue_style('ee-message-settings');
997
-        wp_enqueue_script('ee-messages-settings');
998
-    }
999
-
1000
-
1001
-    /**
1002
-     * set views array for List Table
1003
-     */
1004
-    public function _set_list_table_views_global_mtps()
1005
-    {
1006
-        $this->_views = [
1007
-            'in_use' => [
1008
-                'slug'  => 'in_use',
1009
-                'label' => esc_html__('In Use', 'event_espresso'),
1010
-                'count' => 0,
1011
-            ],
1012
-        ];
1013
-    }
1014
-
1015
-
1016
-    /**
1017
-     * Set views array for the Custom Template List Table
1018
-     */
1019
-    public function _set_list_table_views_custom_mtps()
1020
-    {
1021
-        $this->_set_list_table_views_global_mtps();
1022
-        $this->_views['in_use']['bulk_action'] = [
1023
-            'trash_message_template' => esc_html__('Move to Trash', 'event_espresso'),
1024
-        ];
1025
-    }
1026
-
1027
-
1028
-    /**
1029
-     * set views array for message queue list table
1030
-     *
1031
-     * @throws InvalidDataTypeException
1032
-     * @throws InvalidInterfaceException
1033
-     * @throws InvalidArgumentException
1034
-     * @throws EE_Error
1035
-     * @throws ReflectionException
1036
-     */
1037
-    public function _set_list_table_views_default()
1038
-    {
1039
-        EE_Registry::instance()->load_helper('Template');
1040
-
1041
-        $common_bulk_actions = EE_Registry::instance()->CAP->current_user_can(
1042
-            'ee_send_message',
1043
-            'message_list_table_bulk_actions'
1044
-        )
1045
-            ? [
1046
-                'generate_now'          => esc_html__('Generate Now', 'event_espresso'),
1047
-                'generate_and_send_now' => esc_html__('Generate and Send Now', 'event_espresso'),
1048
-                'queue_for_resending'   => esc_html__('Queue for Resending', 'event_espresso'),
1049
-                'send_now'              => esc_html__('Send Now', 'event_espresso'),
1050
-            ]
1051
-            : [];
1052
-
1053
-        $delete_bulk_action = EE_Registry::instance()->CAP->current_user_can(
1054
-            'ee_delete_messages',
1055
-            'message_list_table_bulk_actions'
1056
-        )
1057
-            ? ['delete_ee_messages' => esc_html__('Delete Messages', 'event_espresso')]
1058
-            : [];
1059
-
1060
-
1061
-        $this->_views = [
1062
-            'all' => [
1063
-                'slug'        => 'all',
1064
-                'label'       => esc_html__('All', 'event_espresso'),
1065
-                'count'       => 0,
1066
-                'bulk_action' => array_merge($common_bulk_actions, $delete_bulk_action),
1067
-            ],
1068
-        ];
1069
-
1070
-
1071
-        foreach ($this->getMsgModel()->all_statuses() as $status) {
1072
-            if ($status === EEM_Message::status_debug_only && ! EEM_Message::debug()) {
1073
-                continue;
1074
-            }
1075
-            $status_bulk_actions = $common_bulk_actions;
1076
-            // unset bulk actions not applying to status
1077
-            if (! empty($status_bulk_actions)) {
1078
-                switch ($status) {
1079
-                    case EEM_Message::status_idle:
1080
-                    case EEM_Message::status_resend:
1081
-                        $status_bulk_actions['send_now'] = $common_bulk_actions['send_now'];
1082
-                        break;
1083
-
1084
-                    case EEM_Message::status_failed:
1085
-                    case EEM_Message::status_debug_only:
1086
-                    case EEM_Message::status_messenger_executing:
1087
-                        $status_bulk_actions = [];
1088
-                        break;
1089
-
1090
-                    case EEM_Message::status_incomplete:
1091
-                        unset($status_bulk_actions['queue_for_resending'], $status_bulk_actions['send_now']);
1092
-                        break;
1093
-
1094
-                    case EEM_Message::status_retry:
1095
-                    case EEM_Message::status_sent:
1096
-                        unset($status_bulk_actions['generate_now'], $status_bulk_actions['generate_and_send_now']);
1097
-                        break;
1098
-                }
1099
-            }
1100
-
1101
-            // skip adding messenger executing status to views because it will be included with the Failed view.
1102
-            if ($status === EEM_Message::status_messenger_executing) {
1103
-                continue;
1104
-            }
1105
-
1106
-            $this->_views[ strtolower($status) ] = [
1107
-                'slug'        => strtolower($status),
1108
-                'label'       => EEH_Template::pretty_status($status, false, 'sentence'),
1109
-                'count'       => 0,
1110
-                'bulk_action' => array_merge($status_bulk_actions, $delete_bulk_action),
1111
-            ];
1112
-        }
1113
-    }
1114
-
1115
-
1116
-    /**
1117
-     * @throws EE_Error
1118
-     */
1119
-    protected function _ee_default_messages_overview_list_table()
1120
-    {
1121
-        $this->_admin_page_title = esc_html__('Default Message Templates', 'event_espresso');
1122
-        $this->display_admin_list_table_page_with_no_sidebar();
1123
-    }
1124
-
1125
-
1126
-    /**
1127
-     * @throws EE_Error
1128
-     * @throws ReflectionException
1129
-     */
1130
-    protected function _message_queue_list_table()
1131
-    {
1132
-        $this->_search_btn_label                   = esc_html__('Message Activity', 'event_espresso');
1133
-        $this->_template_args['per_column']        = 6;
1134
-        $this->_template_args['after_list_table']  = $this->_display_legend($this->_message_legend_items());
1135
-        $message_results = trim(EEM_Message::instance()->get_pretty_label_for_results());
1136
-        $this->_template_args['before_list_table'] = ! empty($message_results) ? "<h3>{$message_results}</h3>" : '';
1137
-        $this->display_admin_list_table_page_with_no_sidebar();
1138
-    }
1139
-
1140
-
1141
-    /**
1142
-     * @throws EE_Error
1143
-     */
1144
-    protected function _message_legend_items()
1145
-    {
1146
-
1147
-        $action_css_classes = EEH_MSG_Template::get_message_action_icons();
1148
-        $action_items       = [];
1149
-
1150
-        foreach ($action_css_classes as $action_item => $action_details) {
1151
-            if ($action_item === 'see_notifications_for') {
1152
-                continue;
1153
-            }
1154
-            $action_items[ $action_item ] = [
1155
-                'class' => $action_details['css_class'],
1156
-                'desc'  => $action_details['label'],
1157
-            ];
1158
-        }
1159
-
1160
-        /** @var array $status_items status legend setup */
1161
-        $status_items = [
1162
-            'sent_status'                => [
1163
-                'class' => 'ee-status-legend ee-status-bg--' . EEM_Message::status_sent,
1164
-                'desc'  => EEH_Template::pretty_status(EEM_Message::status_sent, false, 'sentence'),
1165
-            ],
1166
-            'idle_status'                => [
1167
-                'class' => 'ee-status-legend ee-status-bg--' . EEM_Message::status_idle,
1168
-                'desc'  => EEH_Template::pretty_status(EEM_Message::status_idle, false, 'sentence'),
1169
-            ],
1170
-            'failed_status'              => [
1171
-                'class' => 'ee-status-legend ee-status-bg--' . EEM_Message::status_failed,
1172
-                'desc'  => EEH_Template::pretty_status(EEM_Message::status_failed, false, 'sentence'),
1173
-            ],
1174
-            'messenger_executing_status' => [
1175
-                'class' => 'ee-status-legend ee-status-bg--' . EEM_Message::status_messenger_executing,
1176
-                'desc'  => EEH_Template::pretty_status(EEM_Message::status_messenger_executing, false, 'sentence'),
1177
-            ],
1178
-            'resend_status'              => [
1179
-                'class' => 'ee-status-legend ee-status-bg--' . EEM_Message::status_resend,
1180
-                'desc'  => EEH_Template::pretty_status(EEM_Message::status_resend, false, 'sentence'),
1181
-            ],
1182
-            'incomplete_status'          => [
1183
-                'class' => 'ee-status-legend ee-status-bg--' . EEM_Message::status_incomplete,
1184
-                'desc'  => EEH_Template::pretty_status(EEM_Message::status_incomplete, false, 'sentence'),
1185
-            ],
1186
-            'retry_status'               => [
1187
-                'class' => 'ee-status-legend ee-status-bg--' . EEM_Message::status_retry,
1188
-                'desc'  => EEH_Template::pretty_status(EEM_Message::status_retry, false, 'sentence'),
1189
-            ],
1190
-        ];
1191
-        if (EEM_Message::debug()) {
1192
-            $status_items['debug_only_status'] = [
1193
-                'class' => 'ee-status-legend ee-status-bg--' . EEM_Message::status_debug_only,
1194
-                'desc'  => EEH_Template::pretty_status(EEM_Message::status_debug_only, false, 'sentence'),
1195
-            ];
1196
-        }
1197
-
1198
-        return array_merge($action_items, $status_items);
1199
-    }
1200
-
1201
-
1202
-    /**
1203
-     * @throws EE_Error
1204
-     */
1205
-    protected function _custom_mtps_preview()
1206
-    {
1207
-        $this->_admin_page_title              = esc_html__('Custom Message Templates (Preview)', 'event_espresso');
1208
-        $this->_template_args['preview_img']  = '<img src="' . EE_MSG_ASSETS_URL . 'images/custom_mtps_preview.png"'
1209
-                                                . ' alt="' . esc_attr__(
1210
-                                                    'Preview Custom Message Templates screenshot',
1211
-                                                    'event_espresso'
1212
-                                                ) . '" />';
1213
-        $this->_template_args['preview_text'] = '<strong>'
1214
-                                                . esc_html__(
1215
-                                                    'Custom Message Templates is a feature that is only available in the premium version of Event Espresso 4 which is available with a support license purchase on EventEspresso.com. With the Custom Message Templates feature, you are able to create custom message templates and assign them on a per-event basis.',
1216
-                                                    'event_espresso'
1217
-                                                )
1218
-                                                . '</strong>';
1219
-
1220
-        $this->display_admin_caf_preview_page('custom_message_types', false);
1221
-    }
1222
-
1223
-
1224
-    /**
1225
-     * get_message_templates
1226
-     * This gets all the message templates for listing on the overview list.
1227
-     *
1228
-     * @access public
1229
-     * @param int    $per_page the amount of templates groups to show per page
1230
-     * @param string $type     the current _view we're getting templates for
1231
-     * @param bool   $count    return count?
1232
-     * @param bool   $all      disregard any paging info (get all data);
1233
-     * @param bool   $global   whether to return just global (true) or custom templates (false)
1234
-     * @return array
1235
-     * @throws EE_Error
1236
-     * @throws InvalidArgumentException
1237
-     * @throws InvalidDataTypeException
1238
-     * @throws InvalidInterfaceException
1239
-     */
1240
-    public function get_message_templates(
1241
-        $per_page = 10,
1242
-        $type = 'in_use',
1243
-        $count = false,
1244
-        $all = false,
1245
-        $global = true
1246
-    ) {
1247
-        $orderby = $this->request->getRequestParam('orderby', 'GRP_ID');
1248
-        $this->request->setRequestParam('orderby', $orderby);
1249
-
1250
-        $order        = $this->request->getRequestParam('order', 'ASC');
1251
-        $current_page = $this->request->getRequestParam('paged', 1, 'int');
1252
-        $per_page     = $this->request->getRequestParam('perpage', $per_page, 'int');
1253
-
1254
-        $offset = ($current_page - 1) * $per_page;
1255
-        $limit  = $all ? null : [$offset, $per_page];
1256
-
1257
-        // options will match what is in the _views array property
1258
-        return $type === 'in_use'
1259
-            ? $this->getMtgModel()->get_all_active_message_templates(
1260
-                $orderby,
1261
-                $order,
1262
-                $limit,
1263
-                $count,
1264
-                $global,
1265
-                true
1266
-            )
1267
-            : $this->getMtgModel()->get_all_trashed_grouped_message_templates(
1268
-                $orderby,
1269
-                $order,
1270
-                $limit,
1271
-                $count,
1272
-                $global
1273
-            );
1274
-    }
1275
-
1276
-
1277
-    /**
1278
-     * filters etc might need a list of installed message_types
1279
-     *
1280
-     * @return array an array of message type objects
1281
-     */
1282
-    public function get_installed_message_types()
1283
-    {
1284
-        $installed_message_types = $this->_message_resource_manager->installed_message_types();
1285
-        $installed               = [];
1286
-
1287
-        foreach ($installed_message_types as $message_type) {
1288
-            $installed[ $message_type->name ] = $message_type;
1289
-        }
1290
-
1291
-        return $installed;
1292
-    }
1293
-
1294
-
1295
-    /**
1296
-     * This is used when creating a custom template. All Custom Templates start based off another template.
1297
-     *
1298
-     * @param string $message_type
1299
-     * @param string $messenger
1300
-     * @param string $GRP_ID
1301
-     *
1302
-     * @throws EE_error
1303
-     * @throws ReflectionException
1304
-     */
1305
-    public function add_message_template($message_type = '', $messenger = '', $GRP_ID = '')
1306
-    {
1307
-        // set values override any request data
1308
-        $message_type = ! empty($message_type) ? $message_type : $this->_active_message_type_name;
1309
-        $messenger    = ! empty($messenger) ? $messenger : $this->_active_messenger_name;
1310
-        $GRP_ID       = ! empty($GRP_ID) ? $GRP_ID : $this->request->getRequestParam('GRP_ID', 0, 'int');
1311
-
1312
-        // we need messenger and message type.  They should be coming from the event editor. If not here then return error
1313
-        if (empty($message_type) || empty($messenger)) {
1314
-            throw new EE_Error(
1315
-                esc_html__(
1316
-                    'Sorry, but we can\'t create new templates because we\'re missing the messenger or message type',
1317
-                    'event_espresso'
1318
-                )
1319
-            );
1320
-        }
1321
-
1322
-        // we need the GRP_ID for the template being used as the base for the new template
1323
-        if (empty($GRP_ID)) {
1324
-            throw new EE_Error(
1325
-                esc_html__(
1326
-                    'In order to create a custom message template the GRP_ID of the template being used as a base is needed',
1327
-                    'event_espresso'
1328
-                )
1329
-            );
1330
-        }
1331
-
1332
-        // let's just make sure the template gets generated!
1333
-
1334
-        // we need to reassign some variables for what the insert is expecting
1335
-        $this->request->setRequestParam('MTP_messenger', $messenger);
1336
-        $this->request->setRequestParam('MTP_message_type', $message_type);
1337
-        $this->request->setRequestParam('GRP_ID', $GRP_ID);
1338
-
1339
-        $this->_insert_or_update_message_template(true);
1340
-    }
1341
-
1342
-
1343
-    /**
1344
-     * @param string $message_type     message type slug
1345
-     * @param string $messenger        messenger slug
1346
-     * @param int    $GRP_ID           GRP_ID for the related message template group this new template will be based
1347
-     *                                 off of.
1348
-     * @throws EE_error
1349
-     * @throws ReflectionException
1350
-     * @deprecated 4.10.29.p
1351
-     */
1352
-    protected function _add_message_template($message_type, $messenger, $GRP_ID)
1353
-    {
1354
-        $this->add_message_template($message_type, $messenger, $GRP_ID);
1355
-    }
1356
-
1357
-
1358
-    /**
1359
-     * _edit_message_template
1360
-     *
1361
-     * @access protected
1362
-     * @return void
1363
-     * @throws InvalidIdentifierException
1364
-     * @throws DomainException
1365
-     * @throws EE_Error
1366
-     * @throws InvalidArgumentException
1367
-     * @throws ReflectionException
1368
-     * @throws InvalidDataTypeException
1369
-     * @throws InvalidInterfaceException
1370
-     */
1371
-    protected function _edit_message_template()
1372
-    {
1373
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
1374
-        $template_fields = '';
1375
-        $sidebar_fields  = '';
1376
-        // we filter the tinyMCE settings to remove the validation since message templates by their nature will not have
1377
-        // valid html in the templates.
1378
-        add_filter('tiny_mce_before_init', [$this, 'filter_tinymce_init'], 10, 2);
1379
-
1380
-        $GRP_ID = $this->request->getRequestParam('id', 0, 'int');
1381
-        $EVT_ID = $this->request->getRequestParam('evt_id', 0, 'int');
1382
-
1383
-        $this->_set_shortcodes(); // this also sets the _message_template property.
1384
-        $message_template_group = $this->_message_template_group;
1385
-        $c_label                = $message_template_group->context_label();
1386
-        $c_config               = $message_template_group->contexts_config();
1387
-
1388
-        reset($c_config);
1389
-        $context = $this->request->getRequestParam('context', key($c_config));
1390
-        $context = strtolower($context);
1391
-
1392
-        $action = empty($GRP_ID) ? 'insert_message_template' : 'update_message_template';
1393
-
1394
-        $edit_message_template_form_url = add_query_arg(
1395
-            ['action' => $action, 'noheader' => true],
1396
-            EE_MSG_ADMIN_URL
1397
-        );
1398
-
1399
-        // set active messenger for this view
1400
-        $this->_active_messenger         = $this->_message_resource_manager->get_active_messenger(
1401
-            $message_template_group->messenger()
1402
-        );
1403
-        $this->_active_message_type_name = $message_template_group->message_type();
1404
-
1405
-
1406
-        // Do we have any validation errors?
1407
-        $validators = $this->_get_transient();
1408
-        $v_fields   = ! empty($validators) ? array_keys($validators) : [];
1409
-
1410
-
1411
-        // we need to assemble the title from Various details
1412
-        $context_label = sprintf(
1413
-            esc_html__('(%s %s)', 'event_espresso'),
1414
-            $c_config[ $context ]['label'],
1415
-            ucwords($c_label['label'])
1416
-        );
1417
-
1418
-        $title = sprintf(
1419
-            esc_html__(' %s %s Template %s', 'event_espresso'),
1420
-            ucwords($message_template_group->messenger_obj()->label['singular']),
1421
-            ucwords($message_template_group->message_type_obj()->label['singular']),
1422
-            $context_label
1423
-        );
1424
-
1425
-        $this->_template_args['GRP_ID']           = $GRP_ID;
1426
-        $this->_template_args['message_template'] = $message_template_group;
1427
-        $this->_template_args['is_extra_fields']  = false;
1428
-
1429
-
1430
-        // let's get EEH_MSG_Template so we can get template form fields
1431
-        $template_field_structure = EEH_MSG_Template::get_fields(
1432
-            $message_template_group->messenger(),
1433
-            $message_template_group->message_type()
1434
-        );
1435
-
1436
-        if (! $template_field_structure) {
1437
-            $template_field_structure = false;
1438
-            $template_fields          = esc_html__(
1439
-                'There was an error in assembling the fields for this display (you should see an error message)',
1440
-                'event_espresso'
1441
-            );
1442
-        }
1443
-
1444
-
1445
-        $message_templates = $message_template_group->context_templates();
1446
-
1447
-
1448
-        // if we have the extra key.. then we need to remove the content index from the template_field_structure as it
1449
-        // will get handled in the "extra" array.
1450
-        if (is_array($template_field_structure[ $context ]) && isset($template_field_structure[ $context ]['extra'])) {
1451
-            foreach ($template_field_structure[ $context ]['extra'] as $reference_field => $new_fields) {
1452
-                unset($template_field_structure[ $context ][ $reference_field ]);
1453
-            }
1454
-        }
1455
-
1456
-        // let's loop through the template_field_structure and actually assemble the input fields!
1457
-        if (! empty($template_field_structure)) {
1458
-            foreach ($template_field_structure[ $context ] as $template_field => $field_setup_array) {
1459
-                // if this is an 'extra' template field then we need to remove any existing fields that are keyed up in
1460
-                // the extra array and reset them.
1461
-                if ($template_field === 'extra') {
1462
-                    $this->_template_args['is_extra_fields'] = true;
1463
-                    foreach ($field_setup_array as $reference_field => $new_fields_array) {
1464
-                        $message_template = $message_templates[ $context ][ $reference_field ];
1465
-                        $content          = $message_template instanceof EE_Message_Template
1466
-                            ? $message_template->get('MTP_content')
1467
-                            : '';
1468
-                        foreach ($new_fields_array as $extra_field => $extra_array) {
1469
-                            // let's verify if we need this extra field via the shortcodes parameter.
1470
-                            $continue = false;
1471
-                            if (isset($extra_array['shortcodes_required'])) {
1472
-                                foreach ((array) $extra_array['shortcodes_required'] as $shortcode) {
1473
-                                    if (! array_key_exists($shortcode, $this->_shortcodes)) {
1474
-                                        $continue = true;
1475
-                                    }
1476
-                                }
1477
-                                if ($continue) {
1478
-                                    continue;
1479
-                                }
1480
-                            }
1481
-
1482
-                            $field_id = $reference_field . '-' . $extra_field . '-content';
1483
-
1484
-                            $template_form_fields[ $field_id ]         = $extra_array;
1485
-                            $template_form_fields[ $field_id ]['name'] = 'MTP_template_fields['
1486
-                                                                         . $reference_field
1487
-                                                                         . '][content]['
1488
-                                                                         . $extra_field . ']';
1489
-                            $css_class                                 = isset($extra_array['css_class'])
1490
-                                ? $extra_array['css_class']
1491
-                                : '';
1492
-
1493
-                            $template_form_fields[ $field_id ]['css_class'] = ! empty($v_fields)
1494
-                                                                              && in_array($extra_field, $v_fields, true)
1495
-                                                                              && (
1496
-                                                                                  is_array($validators[ $extra_field ])
1497
-                                                                                  && isset($validators[ $extra_field ]['msg'])
1498
-                                                                              )
1499
-                                ? 'validate-error ' . $css_class
1500
-                                : $css_class;
1501
-
1502
-                            $template_form_fields[ $field_id ]['value'] = ! empty($message_templates)
1503
-                                                                          && isset($content[ $extra_field ])
1504
-                                ? $content[ $extra_field ]
1505
-                                : '';
1506
-
1507
-                            // do we have a validation error?  if we do then let's use that value instead
1508
-                            $template_form_fields[ $field_id ]['value'] = isset($validators[ $extra_field ])
1509
-                                ? $validators[ $extra_field ]['value']
1510
-                                : $template_form_fields[ $field_id ]['value'];
1511
-
1512
-
1513
-                            $template_form_fields[ $field_id ]['db-col'] = 'MTP_content';
1514
-
1515
-                            // shortcode selector
1516
-                            $field_name_to_use                                   = $extra_field === 'main'
1517
-                                ? 'content'
1518
-                                : $extra_field;
1519
-                            $template_form_fields[ $field_id ]['append_content'] = $this->_get_shortcode_selector(
1520
-                                $field_name_to_use,
1521
-                                $field_id
1522
-                            );
1523
-                        }
1524
-                        $template_field_MTP_id           = $reference_field . '-MTP_ID';
1525
-                        $template_field_template_name_id = $reference_field . '-name';
1526
-
1527
-                        $template_form_fields[ $template_field_MTP_id ] = [
1528
-                            'name'       => 'MTP_template_fields[' . $reference_field . '][MTP_ID]',
1529
-                            'label'      => null,
1530
-                            'input'      => 'hidden',
1531
-                            'type'       => 'int',
1532
-                            'required'   => false,
1533
-                            'validation' => false,
1534
-                            'value'      => ! empty($message_templates) ? $message_template->ID() : '',
1535
-                            'css_class'  => '',
1536
-                            'format'     => '%d',
1537
-                            'db-col'     => 'MTP_ID',
1538
-                        ];
1539
-
1540
-                        $template_form_fields[ $template_field_template_name_id ] = [
1541
-                            'name'       => 'MTP_template_fields[' . $reference_field . '][name]',
1542
-                            'label'      => null,
1543
-                            'input'      => 'hidden',
1544
-                            'type'       => 'string',
1545
-                            'required'   => false,
1546
-                            'validation' => true,
1547
-                            'value'      => $reference_field,
1548
-                            'css_class'  => '',
1549
-                            'format'     => '%s',
1550
-                            'db-col'     => 'MTP_template_field',
1551
-                        ];
1552
-                    }
1553
-                    continue; // skip the next stuff, we got the necessary fields here for this dataset.
1554
-                } else {
1555
-                    $field_id                                   = $template_field . '-content';
1556
-                    $template_form_fields[ $field_id ]          = $field_setup_array;
1557
-                    $template_form_fields[ $field_id ]['name']  =
1558
-                        'MTP_template_fields[' . $template_field . '][content]';
1559
-                    $message_template                           =
1560
-                        isset($message_templates[ $context ][ $template_field ])
1561
-                            ? $message_templates[ $context ][ $template_field ]
1562
-                            : null;
1563
-                    $template_form_fields[ $field_id ]['value'] = ! empty($message_templates)
1564
-                                                                  && is_array($message_templates[ $context ])
1565
-                                                                  && $message_template instanceof EE_Message_Template
1566
-                        ? $message_template->get('MTP_content')
1567
-                        : '';
1568
-
1569
-                    // do we have a validator error for this field?  if we do then we'll use that value instead
1570
-                    $template_form_fields[ $field_id ]['value'] = isset($validators[ $template_field ])
1571
-                        ? $validators[ $template_field ]['value']
1572
-                        : $template_form_fields[ $field_id ]['value'];
1573
-
1574
-
1575
-                    $template_form_fields[ $field_id ]['db-col']    = 'MTP_content';
1576
-                    $css_class                                      = isset($field_setup_array['css_class'])
1577
-                        ? $field_setup_array['css_class']
1578
-                        : '';
1579
-                    $template_form_fields[ $field_id ]['css_class'] = ! empty($v_fields)
1580
-                                                                      && in_array($template_field, $v_fields, true)
1581
-                                                                      && isset($validators[ $template_field ]['msg'])
1582
-                        ? 'validate-error ' . $css_class
1583
-                        : $css_class;
1584
-
1585
-                    // shortcode selector
1586
-                    $template_form_fields[ $field_id ]['append_content'] = $this->_get_shortcode_selector(
1587
-                        $template_field,
1588
-                        $field_id
1589
-                    );
1590
-                }
1591
-
1592
-                // k took care of content field(s) now let's take care of others.
1593
-
1594
-                $template_field_MTP_id                 = $template_field . '-MTP_ID';
1595
-                $template_field_field_template_name_id = $template_field . '-name';
1596
-
1597
-                // foreach template field there are actually two form fields created
1598
-                $template_form_fields[ $template_field_MTP_id ] = [
1599
-                    'name'       => 'MTP_template_fields[' . $template_field . '][MTP_ID]',
1600
-                    'label'      => null,
1601
-                    'input'      => 'hidden',
1602
-                    'type'       => 'int',
1603
-                    'required'   => false,
1604
-                    'validation' => true,
1605
-                    'value'      => $message_template instanceof EE_Message_Template ? $message_template->ID() : '',
1606
-                    'css_class'  => '',
1607
-                    'format'     => '%d',
1608
-                    'db-col'     => 'MTP_ID',
1609
-                ];
1610
-
1611
-                $template_form_fields[ $template_field_field_template_name_id ] = [
1612
-                    'name'       => 'MTP_template_fields[' . $template_field . '][name]',
1613
-                    'label'      => null,
1614
-                    'input'      => 'hidden',
1615
-                    'type'       => 'string',
1616
-                    'required'   => false,
1617
-                    'validation' => true,
1618
-                    'value'      => $template_field,
1619
-                    'css_class'  => '',
1620
-                    'format'     => '%s',
1621
-                    'db-col'     => 'MTP_template_field',
1622
-                ];
1623
-            }
1624
-
1625
-            // add other fields
1626
-            $template_form_fields['ee-msg-current-context'] = [
1627
-                'name'       => 'MTP_context',
1628
-                'label'      => null,
1629
-                'input'      => 'hidden',
1630
-                'type'       => 'string',
1631
-                'required'   => false,
1632
-                'validation' => true,
1633
-                'value'      => $context,
1634
-                'css_class'  => '',
1635
-                'format'     => '%s',
1636
-                'db-col'     => 'MTP_context',
1637
-            ];
1638
-
1639
-            $template_form_fields['ee-msg-grp-id'] = [
1640
-                'name'       => 'GRP_ID',
1641
-                'label'      => null,
1642
-                'input'      => 'hidden',
1643
-                'type'       => 'int',
1644
-                'required'   => false,
1645
-                'validation' => true,
1646
-                'value'      => $GRP_ID,
1647
-                'css_class'  => '',
1648
-                'format'     => '%d',
1649
-                'db-col'     => 'GRP_ID',
1650
-            ];
1651
-
1652
-            $template_form_fields['ee-msg-messenger'] = [
1653
-                'name'       => 'MTP_messenger',
1654
-                'label'      => null,
1655
-                'input'      => 'hidden',
1656
-                'type'       => 'string',
1657
-                'required'   => false,
1658
-                'validation' => true,
1659
-                'value'      => $message_template_group->messenger(),
1660
-                'css_class'  => '',
1661
-                'format'     => '%s',
1662
-                'db-col'     => 'MTP_messenger',
1663
-            ];
1664
-
1665
-            $template_form_fields['ee-msg-message-type'] = [
1666
-                'name'       => 'MTP_message_type',
1667
-                'label'      => null,
1668
-                'input'      => 'hidden',
1669
-                'type'       => 'string',
1670
-                'required'   => false,
1671
-                'validation' => true,
1672
-                'value'      => $message_template_group->message_type(),
1673
-                'css_class'  => '',
1674
-                'format'     => '%s',
1675
-                'db-col'     => 'MTP_message_type',
1676
-            ];
1677
-
1678
-            $sidebar_form_fields['ee-msg-is-global'] = [
1679
-                'name'       => 'MTP_is_global',
1680
-                'label'      => esc_html__('Global Template', 'event_espresso'),
1681
-                'input'      => 'hidden',
1682
-                'type'       => 'int',
1683
-                'required'   => false,
1684
-                'validation' => true,
1685
-                'value'      => $message_template_group->get('MTP_is_global'),
1686
-                'css_class'  => '',
1687
-                'format'     => '%d',
1688
-                'db-col'     => 'MTP_is_global',
1689
-            ];
1690
-
1691
-            $sidebar_form_fields['ee-msg-is-override'] = [
1692
-                'name'       => 'MTP_is_override',
1693
-                'label'      => esc_html__('Override all custom', 'event_espresso'),
1694
-                'input'      => $message_template_group->is_global() ? 'checkbox' : 'hidden',
1695
-                'type'       => 'int',
1696
-                'required'   => false,
1697
-                'validation' => true,
1698
-                'value'      => $message_template_group->get('MTP_is_override'),
1699
-                'css_class'  => '',
1700
-                'format'     => '%d',
1701
-                'db-col'     => 'MTP_is_override',
1702
-            ];
1703
-
1704
-            $sidebar_form_fields['ee-msg-is-active'] = [
1705
-                'name'       => 'MTP_is_active',
1706
-                'label'      => esc_html__('Active Template', 'event_espresso'),
1707
-                'input'      => 'hidden',
1708
-                'type'       => 'int',
1709
-                'required'   => false,
1710
-                'validation' => true,
1711
-                'value'      => $message_template_group->is_active(),
1712
-                'css_class'  => '',
1713
-                'format'     => '%d',
1714
-                'db-col'     => 'MTP_is_active',
1715
-            ];
1716
-
1717
-            $sidebar_form_fields['ee-msg-deleted'] = [
1718
-                'name'       => 'MTP_deleted',
1719
-                'label'      => null,
1720
-                'input'      => 'hidden',
1721
-                'type'       => 'int',
1722
-                'required'   => false,
1723
-                'validation' => true,
1724
-                'value'      => $message_template_group->get('MTP_deleted'),
1725
-                'css_class'  => '',
1726
-                'format'     => '%d',
1727
-                'db-col'     => 'MTP_deleted',
1728
-            ];
1729
-            $sidebar_form_fields['ee-msg-author']  = [
1730
-                'name'       => 'MTP_user_id',
1731
-                'label'      => esc_html__('Author', 'event_espresso'),
1732
-                'input'      => 'hidden',
1733
-                'type'       => 'int',
1734
-                'required'   => false,
1735
-                'validation' => false,
1736
-                'value'      => $message_template_group->user(),
1737
-                'format'     => '%d',
1738
-                'db-col'     => 'MTP_user_id',
1739
-            ];
1740
-
1741
-            $sidebar_form_fields['ee-msg-route'] = [
1742
-                'name'  => 'action',
1743
-                'input' => 'hidden',
1744
-                'type'  => 'string',
1745
-                'value' => $action,
1746
-            ];
1747
-
1748
-            $sidebar_form_fields['ee-msg-id']        = [
1749
-                'name'  => 'id',
1750
-                'input' => 'hidden',
1751
-                'type'  => 'int',
1752
-                'value' => $GRP_ID,
1753
-            ];
1754
-            $sidebar_form_fields['ee-msg-evt-nonce'] = [
1755
-                'name'  => $action . '_nonce',
1756
-                'input' => 'hidden',
1757
-                'type'  => 'string',
1758
-                'value' => wp_create_nonce($action . '_nonce'),
1759
-            ];
1760
-
1761
-            $template_switch = $this->request->getRequestParam('template_switch');
1762
-            if ($template_switch) {
1763
-                $sidebar_form_fields['ee-msg-template-switch'] = [
1764
-                    'name'  => 'template_switch',
1765
-                    'input' => 'hidden',
1766
-                    'type'  => 'int',
1767
-                    'value' => 1,
1768
-                ];
1769
-            }
1770
-
1771
-
1772
-            $template_fields = $this->_generate_admin_form_fields($template_form_fields);
1773
-            $sidebar_fields  = $this->_generate_admin_form_fields($sidebar_form_fields);
1774
-        } //end if ( !empty($template_field_structure) )
1775
-
1776
-        // set extra content for publish box
1777
-        $this->_template_args['publish_box_extra_content'] = $sidebar_fields;
1778
-        $this->_set_publish_post_box_vars(
1779
-            'id',
1780
-            $GRP_ID,
1781
-            false,
1782
-            add_query_arg(
1783
-                ['action' => 'global_mtps'],
1784
-                $this->_admin_base_url
1785
-            )
1786
-        );
1787
-
1788
-        // add preview button
1789
-        $preview_url    = parent::add_query_args_and_nonce(
1790
-            [
1791
-                'message_type' => $message_template_group->message_type(),
1792
-                'messenger'    => $message_template_group->messenger(),
1793
-                'context'      => $context,
1794
-                'GRP_ID'       => $GRP_ID,
1795
-                'evt_id'       => $EVT_ID ?: false,
1796
-                'action'       => 'preview_message',
1797
-            ],
1798
-            $this->_admin_base_url
1799
-        );
1800
-        $preview_button = '<a href="' . $preview_url . '" class="button--secondary messages-preview-button">'
1801
-                          . esc_html__('Preview', 'event_espresso')
1802
-                          . '</a>';
1803
-
1804
-
1805
-        // setup context switcher
1806
-        $this->_set_context_switcher(
1807
-            $message_template_group,
1808
-            [
1809
-                'page'    => 'espresso_messages',
1810
-                'action'  => 'edit_message_template',
1811
-                'id'      => $GRP_ID,
1812
-                'evt_id'  => $EVT_ID,
1813
-                'context' => $context,
1814
-                'extra'   => $preview_button,
1815
-            ]
1816
-        );
1817
-
1818
-
1819
-        // main box
1820
-        $this->_template_args['template_fields']                         = $template_fields;
1821
-        $this->_template_args['sidebar_box_id']                          = 'details';
1822
-        $this->_template_args['action']                                  = $action;
1823
-        $this->_template_args['context']                                 = $context;
1824
-        $this->_template_args['edit_message_template_form_url']          = $edit_message_template_form_url;
1825
-        $this->_template_args['learn_more_about_message_templates_link'] =
1826
-            $this->_learn_more_about_message_templates_link();
1827
-
1828
-
1829
-        $this->_template_args['before_admin_page_content'] = '<div class="ee-msg-admin-header">';
1830
-        $this->_template_args['before_admin_page_content'] .= $this->add_active_context_element(
1831
-            $message_template_group,
1832
-            $context,
1833
-            $context_label
1834
-        );
1835
-        $this->_template_args['before_admin_page_content'] .= $this->add_context_switcher();
1836
-        $this->_template_args['before_admin_page_content'] .= '</div>';
1837
-        $this->_template_args['before_admin_page_content'] .= $this->_add_form_element_before();
1838
-        $this->_template_args['after_admin_page_content']  = $this->_add_form_element_after();
1839
-
1840
-        $this->_template_path = $this->_template_args['GRP_ID']
1841
-            ? EE_MSG_TEMPLATE_PATH . 'ee_msg_details_main_edit_meta_box.template.php'
1842
-            : EE_MSG_TEMPLATE_PATH . 'ee_msg_details_main_add_meta_box.template.php';
1843
-
1844
-        // send along EE_Message_Template_Group object for further template use.
1845
-        $this->_template_args['MTP'] = $message_template_group;
1846
-
1847
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
1848
-            $this->_template_path,
1849
-            $this->_template_args,
1850
-            true
1851
-        );
1852
-
1853
-
1854
-        // finally, let's set the admin_page title
1855
-        $this->_admin_page_title = sprintf(esc_html__('Editing %s', 'event_espresso'), $title);
1856
-
1857
-
1858
-        // we need to take care of setting the shortcodes property for use elsewhere.
1859
-        $this->_set_shortcodes();
1860
-
1861
-
1862
-        // final template wrapper
1863
-        $this->display_admin_page_with_sidebar();
1864
-    }
1865
-
1866
-
1867
-    public function filter_tinymce_init($mceInit, $editor_id)
1868
-    {
1869
-        return $mceInit;
1870
-    }
1871
-
1872
-
1873
-    public function add_context_switcher()
1874
-    {
1875
-        return $this->_context_switcher;
1876
-    }
1877
-
1878
-
1879
-    /**
1880
-     * Adds the activation/deactivation toggle for the message template context.
1881
-     *
1882
-     * @param EE_Message_Template_Group $message_template_group
1883
-     * @param string                    $context
1884
-     * @param string                    $context_label
1885
-     * @return string
1886
-     * @throws DomainException
1887
-     * @throws EE_Error
1888
-     * @throws InvalidIdentifierException
1889
-     * @throws ReflectionException
1890
-     */
1891
-    protected function add_active_context_element(
1892
-        EE_Message_Template_Group $message_template_group,
1893
-        $context,
1894
-        $context_label
1895
-    ) {
1896
-        $template_args = [
1897
-            'context'                   => $context,
1898
-            'nonce'                     => wp_create_nonce('activate_' . $context . '_toggle_nonce'),
1899
-            'is_active'                 => $message_template_group->is_context_active($context),
1900
-            'on_off_action'             => $message_template_group->is_context_active($context)
1901
-                ? 'context-off'
1902
-                : 'context-on',
1903
-            'context_label'             => str_replace(['(', ')'], '', $context_label),
1904
-            'message_template_group_id' => $message_template_group->ID(),
1905
-        ];
1906
-        return EEH_Template::display_template(
1907
-            EE_MSG_TEMPLATE_PATH . 'ee_msg_editor_active_context_element.template.php',
1908
-            $template_args,
1909
-            true
1910
-        );
1911
-    }
1912
-
1913
-
1914
-    /**
1915
-     * Ajax callback for `toggle_context_template` ajax action.
1916
-     * Handles toggling the message context on or off.
1917
-     *
1918
-     * @throws EE_Error
1919
-     * @throws InvalidArgumentException
1920
-     * @throws InvalidDataTypeException
1921
-     * @throws InvalidIdentifierException
1922
-     * @throws InvalidInterfaceException
1923
-     */
1924
-    public function toggle_context_template()
1925
-    {
1926
-        $success = true;
1927
-        // check for required data
1928
-        if (
1929
-            ! (
1930
-                $this->request->requestParamIsSet('message_template_group_id')
1931
-                && $this->request->requestParamIsSet('context')
1932
-                && $this->request->requestParamIsSet('status')
1933
-            )
1934
-        ) {
1935
-            EE_Error::add_error(
1936
-                esc_html__('Required data for doing this action is not available.', 'event_espresso'),
1937
-                __FILE__,
1938
-                __FUNCTION__,
1939
-                __LINE__
1940
-            );
1941
-            $success = false;
1942
-        }
1943
-
1944
-        $nonce   = $this->request->getRequestParam('toggle_context_nonce', '');
1945
-        $context = $this->request->getRequestParam('context', '');
1946
-        $status  = $this->request->getRequestParam('status', '');
1947
-
1948
-        $this->_verify_nonce($nonce, "activate_{$context}_toggle_nonce");
1949
-
1950
-        if ($status !== 'off' && $status !== 'on') {
1951
-            EE_Error::add_error(
1952
-                sprintf(
1953
-                    esc_html__('The given status (%s) is not valid. Must be "off" or "on"', 'event_espresso'),
1954
-                    $status
1955
-                ),
1956
-                __FILE__,
1957
-                __FUNCTION__,
1958
-                __LINE__
1959
-            );
1960
-            $success = false;
1961
-        }
1962
-        $message_template_group_id = $this->request->getRequestParam('message_template_group_id', 0, 'int');
1963
-        $message_template_group    = $this->getMtgModel()->get_one_by_ID($message_template_group_id);
1964
-        if (! $message_template_group instanceof EE_Message_Template_Group) {
1965
-            EE_Error::add_error(
1966
-                sprintf(
1967
-                    esc_html__(
1968
-                        'Unable to change the active state because the given id "%1$d" does not match a valid "%2$s"',
1969
-                        'event_espresso'
1970
-                    ),
1971
-                    $message_template_group_id,
1972
-                    'EE_Message_Template_Group'
1973
-                ),
1974
-                __FILE__,
1975
-                __FUNCTION__,
1976
-                __LINE__
1977
-            );
1978
-            $success = false;
1979
-        }
1980
-        if ($success) {
1981
-            $success = $status === 'off'
1982
-                ? $message_template_group->deactivate_context($context)
1983
-                : $message_template_group->activate_context($context);
1984
-        }
1985
-        $this->_template_args['success'] = $success;
1986
-        $this->_return_json();
1987
-    }
1988
-
1989
-
1990
-    public function _add_form_element_before()
1991
-    {
1992
-        return '<form method="post" action="'
1993
-               . $this->_template_args['edit_message_template_form_url']
1994
-               . '" id="ee-msg-edit-frm">';
1995
-    }
1996
-
1997
-
1998
-    public function _add_form_element_after()
1999
-    {
2000
-        return '</form>';
2001
-    }
2002
-
2003
-
2004
-    /**
2005
-     * This executes switching the template pack for a message template.
2006
-     *
2007
-     * @throws EE_Error
2008
-     * @throws InvalidDataTypeException
2009
-     * @throws InvalidInterfaceException
2010
-     * @throws InvalidArgumentException
2011
-     * @throws ReflectionException
2012
-     * @since 4.5.0
2013
-     */
2014
-    public function switch_template_pack()
2015
-    {
2016
-
2017
-        $GRP_ID        = $this->request->getRequestParam('GRP_ID', 0, 'int');
2018
-        $template_pack = $this->request->getRequestParam('template_pack', '');
2019
-
2020
-        // verify we have needed values.
2021
-        if (empty($GRP_ID) || empty($template_pack)) {
2022
-            $this->_template_args['error'] = true;
2023
-            EE_Error::add_error(
2024
-                esc_html__('The required date for switching templates is not available.', 'event_espresso'),
2025
-                __FILE__,
2026
-                __FUNCTION__,
2027
-                __LINE__
2028
-            );
2029
-        } else {
2030
-            // get template, set the new template_pack and then reset to default
2031
-            /** @var EE_Message_Template_Group $message_template_group */
2032
-            $message_template_group = $this->getMtgModel()->get_one_by_ID($GRP_ID);
2033
-
2034
-            $message_template_group->set_template_pack_name($template_pack);
2035
-            $this->request->setRequestParam('msgr', $message_template_group->messenger());
2036
-            $this->request->setRequestParam('mt', $message_template_group->message_type());
2037
-
2038
-            $query_args = $this->_reset_to_default_template();
2039
-
2040
-            if (empty($query_args['id'])) {
2041
-                EE_Error::add_error(
2042
-                    esc_html__(
2043
-                        'Something went wrong with switching the template pack. Please try again or contact EE support',
2044
-                        'event_espresso'
2045
-                    ),
2046
-                    __FILE__,
2047
-                    __FUNCTION__,
2048
-                    __LINE__
2049
-                );
2050
-                $this->_template_args['error'] = true;
2051
-            } else {
2052
-                $template_label       = $message_template_group->get_template_pack()->label;
2053
-                $template_pack_labels = $message_template_group->messenger_obj()->get_supports_labels();
2054
-                EE_Error::add_success(
2055
-                    sprintf(
2056
-                        esc_html__(
2057
-                            'This message template has been successfully switched to use the %1$s %2$s.  Please wait while the page reloads with your new template.',
2058
-                            'event_espresso'
2059
-                        ),
2060
-                        $template_label,
2061
-                        $template_pack_labels->template_pack
2062
-                    )
2063
-                );
2064
-                // generate the redirect url for js.
2065
-                $url = self::add_query_args_and_nonce($query_args, $this->_admin_base_url);
2066
-
2067
-                $this->_template_args['data']['redirect_url'] = $url;
2068
-                $this->_template_args['success']              = true;
2069
-            }
2070
-
2071
-            $this->_return_json();
2072
-        }
2073
-    }
2074
-
2075
-
2076
-    /**
2077
-     * This handles resetting the template for the given messenger/message_type so that users can start from scratch if
2078
-     * they want.
2079
-     *
2080
-     * @access protected
2081
-     * @return array|void
2082
-     * @throws EE_Error
2083
-     * @throws InvalidArgumentException
2084
-     * @throws InvalidDataTypeException
2085
-     * @throws InvalidInterfaceException
2086
-     * @throws ReflectionException
2087
-     */
2088
-    protected function _reset_to_default_template()
2089
-    {
2090
-        $templates    = [];
2091
-        $GRP_ID       = $this->request->getRequestParam('GRP_ID', 0, 'int');
2092
-        $messenger    = $this->request->getRequestParam('msgr');
2093
-        $message_type = $this->request->getRequestParam('mt');
2094
-        // we need to make sure we've got the info we need.
2095
-        if (! ($GRP_ID && $messenger && $message_type)) {
2096
-            EE_Error::add_error(
2097
-                esc_html__(
2098
-                    'In order to reset the template to its default we require the messenger, message type, and message template GRP_ID to know what is being reset.  At least one of these is missing.',
2099
-                    'event_espresso'
2100
-                ),
2101
-                __FILE__,
2102
-                __FUNCTION__,
2103
-                __LINE__
2104
-            );
2105
-        }
2106
-
2107
-        // all templates will be reset to whatever the defaults are
2108
-        // for the global template matching the messenger and message type.
2109
-        $success = ! empty($GRP_ID);
2110
-
2111
-        if ($success) {
2112
-            // let's first determine if the incoming template is a global template,
2113
-            // if it isn't then we need to get the global template matching messenger and message type.
2114
-            // $MTPG = $this->getMtgModel()->get_one_by_ID( $GRP_ID );
2115
-
2116
-
2117
-            // note this is ONLY deleting the template fields (Message Template rows) NOT the message template group.
2118
-            $success = $this->_delete_mtp_permanently($GRP_ID, false);
2119
-
2120
-            if ($success) {
2121
-                // if successfully deleted, lets generate the new ones.
2122
-                // Note. We set GLOBAL to true, because resets on ANY template
2123
-                // will use the related global template defaults for regeneration.
2124
-                // This means that if a custom template is reset it resets to whatever the related global template is.
2125
-                // HOWEVER, we DO keep the template pack and template variation set
2126
-                // for the current custom template when resetting.
2127
-                $templates = $this->_generate_new_templates($messenger, $message_type, $GRP_ID, true);
2128
-            }
2129
-        }
2130
-
2131
-        // any error messages?
2132
-        if (! $success) {
2133
-            EE_Error::add_error(
2134
-                esc_html__(
2135
-                    'Something went wrong with deleting existing templates. Unable to reset to default',
2136
-                    'event_espresso'
2137
-                ),
2138
-                __FILE__,
2139
-                __FUNCTION__,
2140
-                __LINE__
2141
-            );
2142
-        }
2143
-
2144
-        // all good, let's add a success message!
2145
-        if ($success && ! empty($templates)) {
2146
-            // the info for the template we generated is the first element in the returned array
2147
-            EE_Error::overwrite_success();
2148
-            EE_Error::add_success(esc_html__('Templates have been reset to defaults.', 'event_espresso'));
2149
-        }
2150
-
2151
-
2152
-        $query_args = [
2153
-            'id'      => isset($templates['GRP_ID']) ? $templates['GRP_ID'] : null,
2154
-            'context' => isset($templates['MTP_context']) ? $templates['MTP_context'] : null,
2155
-            'action'  => isset($templates['GRP_ID']) ? 'edit_message_template' : 'global_mtps',
2156
-        ];
2157
-
2158
-        // if called via ajax then we return query args otherwise redirect
2159
-        if ($this->request->isAjax()) {
2160
-            return $query_args;
2161
-        }
2162
-        $this->_redirect_after_action(false, '', '', $query_args, true);
2163
-    }
2164
-
2165
-
2166
-    /**
2167
-     * Retrieve and set the message preview for display.
2168
-     *
2169
-     * @param bool $send if TRUE then we are doing an actual TEST send with the results of the preview.
2170
-     * @return string
2171
-     * @throws ReflectionException
2172
-     * @throws EE_Error
2173
-     * @throws InvalidArgumentException
2174
-     * @throws InvalidDataTypeException
2175
-     * @throws InvalidInterfaceException
2176
-     */
2177
-    public function _preview_message($send = false)
2178
-    {
2179
-        // first make sure we've got the necessary parameters
2180
-        $GRP_ID = $this->request->getRequestParam('GRP_ID', 0, 'int');
2181
-        if (! ($GRP_ID && $this->_active_messenger_name && $this->_active_message_type_name)) {
2182
-            EE_Error::add_error(
2183
-                esc_html__('Missing necessary parameters for displaying preview', 'event_espresso'),
2184
-                __FILE__,
2185
-                __FUNCTION__,
2186
-                __LINE__
2187
-            );
2188
-        }
2189
-
2190
-        $context = $this->request->getRequestParam('context');
2191
-        // get the preview!
2192
-        $preview = EED_Messages::preview_message(
2193
-            $this->_active_message_type_name,
2194
-            $context,
2195
-            $this->_active_messenger_name,
2196
-            $send
2197
-        );
2198
-
2199
-        if ($send) {
2200
-            return $preview;
2201
-        }
2202
-
2203
-        // if we have an evt_id set on the request, use it.
2204
-        $EVT_ID = $this->request->getRequestParam('evt_id', 0, 'int');
2205
-
2206
-        // let's add a button to go back to the edit view
2207
-        $query_args             = [
2208
-            'id'      => $GRP_ID,
2209
-            'evt_id'  => $EVT_ID,
2210
-            'context' => $context,
2211
-            'action'  => 'edit_message_template',
2212
-        ];
2213
-        $go_back_url            = parent::add_query_args_and_nonce($query_args, $this->_admin_base_url);
2214
-        $preview_button         = '<a href="'
2215
-                                  . $go_back_url
2216
-                                  . '" class="button--secondary messages-preview-go-back-button">'
2217
-                                  . esc_html__('Go Back to Edit', 'event_espresso')
2218
-                                  . '</a>';
2219
-        $message_types          = $this->get_installed_message_types();
2220
-        $active_messenger       = $this->_message_resource_manager->get_active_messenger($this->_active_messenger_name);
2221
-        $active_messenger_label = $active_messenger instanceof EE_messenger
2222
-            ? ucwords($active_messenger->label['singular'])
2223
-            : esc_html__('Unknown Messenger', 'event_espresso');
2224
-        // let's provide a helpful title for context
2225
-        $preview_title = sprintf(
2226
-            esc_html__('Viewing Preview for %s %s Message Template', 'event_espresso'),
2227
-            $active_messenger_label,
2228
-            ucwords($message_types[ $this->_active_message_type_name ]->label['singular'])
2229
-        );
2230
-        if (empty($preview)) {
2231
-            $this->noEventsErrorMessage();
2232
-        }
2233
-        // setup display of preview.
2234
-        $this->_admin_page_title                    = $preview_title;
2235
-        $this->_template_args['admin_page_title']   = $preview_title;
2236
-        $this->_template_args['admin_page_content'] = $preview_button . '<br />' . $preview;
2237
-        $this->_template_args['data']['force_json'] = true;
2238
-
2239
-        return '';
2240
-    }
2241
-
2242
-
2243
-    /**
2244
-     * Used to set an error if there are no events available for generating a preview/test send.
2245
-     *
2246
-     * @param bool $test_send Whether the error should be generated for the context of a test send.
2247
-     */
2248
-    protected function noEventsErrorMessage($test_send = false)
2249
-    {
2250
-        $events_url = parent::add_query_args_and_nonce(
2251
-            [
2252
-                'action' => 'default',
2253
-                'page'   => 'espresso_events',
2254
-            ],
2255
-            admin_url('admin.php')
2256
-        );
2257
-        $message    = $test_send
2258
-            ? esc_html__(
2259
-                'A test message could not be sent for this message template because there are no events created yet. The preview system uses actual events for generating the test message. %1$sGo see your events%2$s!',
2260
-                'event_espresso'
2261
-            )
2262
-            : esc_html__(
2263
-                'There is no preview for this message template available because there are no events created yet. The preview system uses actual events for generating the preview. %1$sGo see your events%2$s!',
2264
-                'event_espresso'
2265
-            );
2266
-
2267
-        EE_Error::add_attention(
2268
-            sprintf(
2269
-                $message,
2270
-                "<a href='{$events_url}'>",
2271
-                '</a>'
2272
-            )
2273
-        );
2274
-    }
2275
-
2276
-
2277
-    /**
2278
-     * The initial _preview_message is on a no headers route.  It will optionally call this if necessary otherwise it
2279
-     * gets called automatically.
2280
-     *
2281
-     * @return void
2282
-     * @throws EE_Error
2283
-     * @since 4.5.0
2284
-     *
2285
-     */
2286
-    protected function _display_preview_message()
2287
-    {
2288
-        $this->display_admin_page_with_no_sidebar();
2289
-    }
2290
-
2291
-
2292
-    /**
2293
-     * registers metaboxes that should show up on the "edit_message_template" page
2294
-     *
2295
-     * @access protected
2296
-     * @return void
2297
-     */
2298
-    protected function _register_edit_meta_boxes()
2299
-    {
2300
-        $this->addMetaBox(
2301
-            'mtp_valid_shortcodes',
2302
-            esc_html__('Valid Shortcodes', 'event_espresso'),
2303
-            [$this, 'shortcode_meta_box'],
2304
-            $this->_current_screen->id,
2305
-            'side'
2306
-        );
2307
-        $this->addMetaBox(
2308
-            'mtp_extra_actions',
2309
-            esc_html__('Extra Actions', 'event_espresso'),
2310
-            [$this, 'extra_actions_meta_box'],
2311
-            $this->_current_screen->id,
2312
-            'side',
2313
-            'high'
2314
-        );
2315
-        $this->addMetaBox(
2316
-            'mtp_templates',
2317
-            esc_html__('Template Styles', 'event_espresso'),
2318
-            [$this, 'template_pack_meta_box'],
2319
-            $this->_current_screen->id,
2320
-            'side',
2321
-            'high'
2322
-        );
2323
-    }
2324
-
2325
-
2326
-    /**
2327
-     * metabox content for all template pack and variation selection.
2328
-     *
2329
-     * @return void
2330
-     * @throws DomainException
2331
-     * @throws EE_Error
2332
-     * @throws InvalidArgumentException
2333
-     * @throws ReflectionException
2334
-     * @throws InvalidDataTypeException
2335
-     * @throws InvalidInterfaceException
2336
-     * @since 4.5.0
2337
-     */
2338
-    public function template_pack_meta_box()
2339
-    {
2340
-        $this->_set_message_template_group();
2341
-
2342
-        $tp_collection = EEH_MSG_Template::get_template_pack_collection();
2343
-
2344
-        $tp_select_values = [];
2345
-
2346
-        foreach ($tp_collection as $tp) {
2347
-            // only include template packs that support this messenger and message type!
2348
-            $supports = $tp->get_supports();
2349
-            if (
2350
-                ! isset($supports[ $this->_message_template_group->messenger() ])
2351
-                || ! in_array(
2352
-                    $this->_message_template_group->message_type(),
2353
-                    $supports[ $this->_message_template_group->messenger() ],
2354
-                    true
2355
-                )
2356
-            ) {
2357
-                // not supported
2358
-                continue;
2359
-            }
2360
-
2361
-            $tp_select_values[] = [
2362
-                'text' => $tp->label,
2363
-                'id'   => $tp->dbref,
2364
-            ];
2365
-        }
2366
-
2367
-        // if empty $tp_select_values then we make sure default is set because EVERY message type should be supported by
2368
-        // the default template pack.  This still allows for the odd template pack to override.
2369
-        if (empty($tp_select_values)) {
2370
-            $tp_select_values[] = [
2371
-                'text' => esc_html__('Default', 'event_espresso'),
2372
-                'id'   => 'default',
2373
-            ];
2374
-        }
2375
-
2376
-        // setup variation select values for the currently selected template.
2377
-        $variations               = $this->_message_template_group->get_template_pack()->get_variations(
2378
-            $this->_message_template_group->messenger(),
2379
-            $this->_message_template_group->message_type()
2380
-        );
2381
-        $variations_select_values = [];
2382
-        foreach ($variations as $variation => $label) {
2383
-            $variations_select_values[] = [
2384
-                'text' => $label,
2385
-                'id'   => $variation,
2386
-            ];
2387
-        }
2388
-
2389
-        $template_pack_labels = $this->_message_template_group->messenger_obj()->get_supports_labels();
2390
-
2391
-        $template_args['template_packs_selector']        = EEH_Form_Fields::select_input(
2392
-            'MTP_template_pack',
2393
-            $tp_select_values,
2394
-            $this->_message_template_group->get_template_pack_name()
2395
-        );
2396
-        $template_args['variations_selector']            = EEH_Form_Fields::select_input(
2397
-            'MTP_template_variation',
2398
-            $variations_select_values,
2399
-            $this->_message_template_group->get_template_pack_variation()
2400
-        );
2401
-        $template_args['template_pack_label']            = $template_pack_labels->template_pack;
2402
-        $template_args['template_variation_label']       = $template_pack_labels->template_variation;
2403
-        $template_args['template_pack_description']      = $template_pack_labels->template_pack_description;
2404
-        $template_args['template_variation_description'] = $template_pack_labels->template_variation_description;
2405
-
2406
-        $template = EE_MSG_TEMPLATE_PATH . 'template_pack_and_variations_metabox.template.php';
2407
-
2408
-        EEH_Template::display_template($template, $template_args);
2409
-    }
2410
-
2411
-
2412
-    /**
2413
-     * This meta box holds any extra actions related to Message Templates
2414
-     * For now, this includes Resetting templates to defaults and sending a test email.
2415
-     *
2416
-     * @access  public
2417
-     * @return void
2418
-     * @throws EE_Error
2419
-     */
2420
-    public function extra_actions_meta_box()
2421
-    {
2422
-        $template_form_fields = [];
2423
-
2424
-        $extra_args = [
2425
-            'msgr'   => $this->_message_template_group->messenger(),
2426
-            'mt'     => $this->_message_template_group->message_type(),
2427
-            'GRP_ID' => $this->_message_template_group->GRP_ID(),
2428
-        ];
2429
-        // first we need to see if there are any fields
2430
-        $fields = $this->_message_template_group->messenger_obj()->get_test_settings_fields();
2431
-
2432
-        if (! empty($fields)) {
2433
-            // yup there be fields
2434
-            foreach ($fields as $field => $config) {
2435
-                $field_id = $this->_message_template_group->messenger() . '_' . $field;
2436
-                $existing = $this->_message_template_group->messenger_obj()->get_existing_test_settings();
2437
-                $default  = isset($config['default']) ? $config['default'] : '';
2438
-                $default  = isset($config['value']) ? $config['value'] : $default;
2439
-
2440
-                // if type is hidden and the value is empty
2441
-                // something may have gone wrong so let's correct with the defaults
2442
-                $fix                = $config['input'] === 'hidden'
2443
-                                      && isset($existing[ $field ])
2444
-                                      && empty($existing[ $field ])
2445
-                    ? $default
2446
-                    : '';
2447
-                $existing[ $field ] = isset($existing[ $field ]) && empty($fix)
2448
-                    ? $existing[ $field ]
2449
-                    : $fix;
2450
-
2451
-                $template_form_fields[ $field_id ] = [
2452
-                    'name'       => 'test_settings_fld[' . $field . ']',
2453
-                    'label'      => $config['label'],
2454
-                    'input'      => $config['input'],
2455
-                    'type'       => $config['type'],
2456
-                    'required'   => $config['required'],
2457
-                    'validation' => $config['validation'],
2458
-                    'value'      => isset($existing[ $field ]) ? $existing[ $field ] : $default,
2459
-                    'css_class'  => $config['css_class'],
2460
-                    'options'    => isset($config['options']) ? $config['options'] : [],
2461
-                    'default'    => $default,
2462
-                    'format'     => $config['format'],
2463
-                ];
2464
-            }
2465
-        }
2466
-
2467
-        $test_settings_html = ! empty($template_form_fields)
2468
-            ? $this->_generate_admin_form_fields($template_form_fields, 'string', 'ee_tst_settings_flds')
2469
-            : '';
2470
-
2471
-        // print out $test_settings_fields
2472
-        if (! empty($test_settings_html)) {
2473
-            $test_settings_html .= '<input type="submit" class="button--primary mtp-test-button alignright" ';
2474
-            $test_settings_html .= 'name="test_button" value="';
2475
-            $test_settings_html .= esc_html__('Test Send', 'event_espresso');
2476
-            $test_settings_html .= '" /><div style="clear:both"></div>';
2477
-        }
2478
-
2479
-        // and button
2480
-        $test_settings_html .= '<div class="publishing-action alignright resetbutton">';
2481
-        $test_settings_html .= '<p>';
2482
-        $test_settings_html .= esc_html__('Need to reset this message type and start over?', 'event_espresso');
2483
-        $test_settings_html .= '</p>';
2484
-        $test_settings_html .= $this->get_action_link_or_button(
2485
-            'reset_to_default',
2486
-            'reset',
2487
-            $extra_args,
2488
-            'button--primary reset-default-button'
2489
-        );
2490
-        $test_settings_html .= '</div><div style="clear:both"></div>';
2491
-        echo wp_kses($test_settings_html, AllowedTags::getWithFormTags());
2492
-    }
2493
-
2494
-
2495
-    /**
2496
-     * This returns the shortcode selector skeleton for a given context and field.
2497
-     *
2498
-     * @param string $field           The name of the field retrieving shortcodes for.
2499
-     * @param string $linked_input_id The css id of the input that the shortcodes get added to.
2500
-     * @return string
2501
-     * @throws DomainException
2502
-     * @throws EE_Error
2503
-     * @throws InvalidArgumentException
2504
-     * @throws ReflectionException
2505
-     * @throws InvalidDataTypeException
2506
-     * @throws InvalidInterfaceException
2507
-     * @since 4.9.rc.000
2508
-     */
2509
-    protected function _get_shortcode_selector($field, $linked_input_id)
2510
-    {
2511
-        $template_args = [
2512
-            'shortcodes'      => $this->_get_shortcodes([$field]),
2513
-            'fieldname'       => $field,
2514
-            'linked_input_id' => $linked_input_id,
2515
-        ];
2516
-
2517
-        return EEH_Template::display_template(
2518
-            EE_MSG_TEMPLATE_PATH . 'shortcode_selector_skeleton.template.php',
2519
-            $template_args,
2520
-            true
2521
-        );
2522
-    }
2523
-
2524
-
2525
-    /**
2526
-     * This just takes care of returning the meta box content for shortcodes (only used on the edit message template
2527
-     * page)
2528
-     *
2529
-     * @access public
2530
-     * @return void
2531
-     * @throws EE_Error
2532
-     * @throws InvalidArgumentException
2533
-     * @throws ReflectionException
2534
-     * @throws InvalidDataTypeException
2535
-     * @throws InvalidInterfaceException
2536
-     */
2537
-    public function shortcode_meta_box()
2538
-    {
2539
-        $shortcodes = $this->_get_shortcodes([], false);
2540
-        // just make sure the shortcodes property is set
2541
-        // $messenger = $this->_message_template_group->messenger_obj();
2542
-        // now let's set the content depending on the status of the shortcodes array
2543
-        if (empty($shortcodes)) {
2544
-            echo '<p>' . esc_html__('There are no valid shortcodes available', 'event_espresso') . '</p>';
2545
-            return;
2546
-        }
2547
-        ?>
20
+	/**
21
+	 * @var EEM_Message
22
+	 */
23
+	private $MSG_MODEL;
24
+
25
+	/**
26
+	 * @var EEM_Message_Template
27
+	 */
28
+	private $MTP_MODEL;
29
+
30
+	/**
31
+	 * @var EEM_Message_Template_Group
32
+	 */
33
+	private $MTG_MODEL;
34
+
35
+	/**
36
+	 * @var EE_Message_Resource_Manager $_message_resource_manager
37
+	 */
38
+	protected $_message_resource_manager;
39
+
40
+	/**
41
+	 * @var string
42
+	 */
43
+	protected $_active_message_type_name = '';
44
+
45
+	/**
46
+	 * @var string
47
+	 */
48
+	protected $_active_messenger_name = '';
49
+
50
+	/**
51
+	 * @var EE_messenger $_active_messenger
52
+	 */
53
+	protected $_active_messenger;
54
+
55
+	protected $_activate_meta_box_type;
56
+
57
+	protected $_current_message_meta_box;
58
+
59
+	protected $_current_message_meta_box_object;
60
+
61
+	protected $_context_switcher;
62
+
63
+	protected $_shortcodes           = [];
64
+
65
+	protected $_active_messengers    = [];
66
+
67
+	protected $_active_message_types = [];
68
+
69
+	/**
70
+	 * @var EE_Message_Template_Group $_message_template_group
71
+	 */
72
+	protected $_message_template_group;
73
+
74
+	protected $_m_mt_settings = [];
75
+
76
+
77
+	/**
78
+	 * This is set via the _set_message_template_group method and holds whatever the template pack for the group is.
79
+	 * IF there is no group then it gets automatically set to the Default template pack.
80
+	 *
81
+	 * @since 4.5.0
82
+	 *
83
+	 * @var EE_Messages_Template_Pack
84
+	 */
85
+	protected $_template_pack;
86
+
87
+
88
+	/**
89
+	 * This is set via the _set_message_template_group method and holds whatever the template pack variation for the
90
+	 * group is.  If there is no group then it automatically gets set to default.
91
+	 *
92
+	 * @since 4.5.0
93
+	 *
94
+	 * @var string
95
+	 */
96
+	protected $_variation;
97
+
98
+
99
+	/**
100
+	 * @param bool $routing
101
+	 * @throws EE_Error
102
+	 * @throws ReflectionException
103
+	 */
104
+	public function __construct($routing = true)
105
+	{
106
+		// make sure messages autoloader is running
107
+		EED_Messages::set_autoloaders();
108
+		parent::__construct($routing);
109
+	}
110
+
111
+
112
+	/**
113
+	 * @return EEM_Message
114
+	 * @throws EE_Error
115
+	 */
116
+	public function getMsgModel()
117
+	{
118
+		if (! $this->MSG_MODEL instanceof EEM_Message) {
119
+			$this->MSG_MODEL = EEM_Message::instance();
120
+		}
121
+		return $this->MSG_MODEL;
122
+	}
123
+
124
+
125
+	/**
126
+	 * @return EEM_Message_Template
127
+	 * @throws EE_Error
128
+	 */
129
+	public function getMtpModel()
130
+	{
131
+		if (! $this->MTP_MODEL instanceof EEM_Message_Template) {
132
+			$this->MTP_MODEL = EEM_Message_Template::instance();
133
+		}
134
+		return $this->MTP_MODEL;
135
+	}
136
+
137
+
138
+	/**
139
+	 * @return EEM_Message_Template_Group
140
+	 * @throws EE_Error
141
+	 */
142
+	public function getMtgModel()
143
+	{
144
+		if (! $this->MTG_MODEL instanceof EEM_Message_Template_Group) {
145
+			$this->MTG_MODEL = EEM_Message_Template_Group::instance();
146
+		}
147
+		return $this->MTG_MODEL;
148
+	}
149
+
150
+
151
+	/**
152
+	 * @throws EE_Error
153
+	 * @throws ReflectionException
154
+	 */
155
+	protected function _init_page_props()
156
+	{
157
+		$this->page_slug        = EE_MSG_PG_SLUG;
158
+		$this->page_label       = esc_html__('Messages Settings', 'event_espresso');
159
+		$this->_admin_base_url  = EE_MSG_ADMIN_URL;
160
+		$this->_admin_base_path = EE_MSG_ADMIN;
161
+
162
+		$messenger    = $this->request->getRequestParam('messenger', '');
163
+		$message_type = $this->request->getRequestParam('message_type', '');
164
+		$this->_active_messenger_name    = $this->request->getRequestParam('MTP_messenger', $messenger);
165
+		$this->_active_message_type_name = $this->request->getRequestParam('MTP_message_type', $message_type);
166
+
167
+		$this->_load_message_resource_manager();
168
+	}
169
+
170
+
171
+	/**
172
+	 * loads messenger objects into the $_active_messengers property (so we can access the needed methods)
173
+	 *
174
+	 * @throws EE_Error
175
+	 * @throws InvalidDataTypeException
176
+	 * @throws InvalidInterfaceException
177
+	 * @throws InvalidArgumentException
178
+	 * @throws ReflectionException
179
+	 */
180
+	protected function _load_message_resource_manager()
181
+	{
182
+		$this->_message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
183
+	}
184
+
185
+
186
+	/**
187
+	 * @return array
188
+	 * @throws EE_Error
189
+	 * @throws InvalidArgumentException
190
+	 * @throws InvalidDataTypeException
191
+	 * @throws InvalidInterfaceException
192
+	 * @deprecated 4.9.9.rc.014
193
+	 */
194
+	public function get_messengers_for_list_table()
195
+	{
196
+		EE_Error::doing_it_wrong(
197
+			__METHOD__,
198
+			sprintf(
199
+				esc_html__(
200
+					'This method is no longer in use.  There is no replacement for it. The method was used to generate a set of values for use in creating a messenger filter dropdown which is now generated differently via %s',
201
+					'event_espresso'
202
+				),
203
+				'Messages_Admin_Page::get_messengers_select_input()'
204
+			),
205
+			'4.9.9.rc.014'
206
+		);
207
+
208
+		$m_values          = [];
209
+		$active_messengers = $this->getMsgModel()->get_all(['group_by' => 'MSG_messenger']);
210
+		// setup messengers for selects
211
+		$i = 1;
212
+		foreach ($active_messengers as $active_messenger) {
213
+			if ($active_messenger instanceof EE_Message) {
214
+				$m_values[ $i ]['id']   = $active_messenger->messenger();
215
+				$m_values[ $i ]['text'] = ucwords($active_messenger->messenger_label());
216
+				$i++;
217
+			}
218
+		}
219
+
220
+		return $m_values;
221
+	}
222
+
223
+
224
+	/**
225
+	 * @return array
226
+	 * @throws EE_Error
227
+	 * @throws InvalidArgumentException
228
+	 * @throws InvalidDataTypeException
229
+	 * @throws InvalidInterfaceException
230
+	 * @deprecated 4.9.9.rc.014
231
+	 */
232
+	public function get_message_types_for_list_table()
233
+	{
234
+		EE_Error::doing_it_wrong(
235
+			__METHOD__,
236
+			sprintf(
237
+				esc_html__(
238
+					'This method is no longer in use.  There is no replacement for it. The method was used to generate a set of values for use in creating a message type filter dropdown which is now generated differently via %s',
239
+					'event_espresso'
240
+				),
241
+				'Messages_Admin_Page::get_message_types_select_input()'
242
+			),
243
+			'4.9.9.rc.014'
244
+		);
245
+
246
+		$mt_values       = [];
247
+		$active_messages = $this->getMsgModel()->get_all(['group_by' => 'MSG_message_type']);
248
+		$i               = 1;
249
+		foreach ($active_messages as $active_message) {
250
+			if ($active_message instanceof EE_Message) {
251
+				$mt_values[ $i ]['id']   = $active_message->message_type();
252
+				$mt_values[ $i ]['text'] = ucwords($active_message->message_type_label());
253
+				$i++;
254
+			}
255
+		}
256
+
257
+		return $mt_values;
258
+	}
259
+
260
+
261
+	/**
262
+	 * @return array
263
+	 * @throws EE_Error
264
+	 * @throws InvalidArgumentException
265
+	 * @throws InvalidDataTypeException
266
+	 * @throws InvalidInterfaceException
267
+	 * @deprecated 4.9.9.rc.014
268
+	 */
269
+	public function get_contexts_for_message_types_for_list_table()
270
+	{
271
+		EE_Error::doing_it_wrong(
272
+			__METHOD__,
273
+			sprintf(
274
+				esc_html__(
275
+					'This method is no longer in use.  There is no replacement for it. The method was used to generate a set of values for use in creating a message type context filter dropdown which is now generated differently via %s',
276
+					'event_espresso'
277
+				),
278
+				'Messages_Admin_Page::get_contexts_for_message_types_select_input()'
279
+			),
280
+			'4.9.9.rc.014'
281
+		);
282
+
283
+		$contexts                = [];
284
+		$active_message_contexts = $this->getMsgModel()->get_all(['group_by' => 'MSG_context']);
285
+		foreach ($active_message_contexts as $active_message) {
286
+			if ($active_message instanceof EE_Message) {
287
+				$message_type = $active_message->message_type_object();
288
+				if ($message_type instanceof EE_message_type) {
289
+					$message_type_contexts = $message_type->get_contexts();
290
+					foreach ($message_type_contexts as $context => $context_details) {
291
+						$contexts[ $context ] = $context_details['label'];
292
+					}
293
+				}
294
+			}
295
+		}
296
+
297
+		return $contexts;
298
+	}
299
+
300
+
301
+	/**
302
+	 * Generate select input with provided messenger options array.
303
+	 *
304
+	 * @param array $messenger_options Array of messengers indexed by messenger slug and values are the messenger
305
+	 *                                 labels.
306
+	 * @return string
307
+	 * @throws EE_Error
308
+	 */
309
+	public function get_messengers_select_input($messenger_options)
310
+	{
311
+		// if empty or just one value then just return an empty string
312
+		if (
313
+			empty($messenger_options)
314
+			|| ! is_array($messenger_options)
315
+			|| count($messenger_options) === 1
316
+		) {
317
+			return '';
318
+		}
319
+		// merge in default
320
+		$messenger_options = array_merge(
321
+			['none_selected' => esc_html__('Show All Messengers', 'event_espresso')],
322
+			$messenger_options
323
+		);
324
+		$input             = new EE_Select_Input(
325
+			$messenger_options,
326
+			[
327
+				'html_name'  => 'ee_messenger_filter_by',
328
+				'html_id'    => 'ee_messenger_filter_by',
329
+				'html_class' => 'wide',
330
+				'default'    => $this->request->getRequestParam('ee_messenger_filter_by', 'none_selected', 'title'),
331
+			]
332
+		);
333
+
334
+		return $input->get_html_for_input();
335
+	}
336
+
337
+
338
+	/**
339
+	 * Generate select input with provided message type options array.
340
+	 *
341
+	 * @param array $message_type_options Array of message types indexed by message type slug, and values are the
342
+	 *                                    message type labels
343
+	 * @return string
344
+	 * @throws EE_Error
345
+	 */
346
+	public function get_message_types_select_input($message_type_options)
347
+	{
348
+		// if empty or count of options is 1 then just return an empty string
349
+		if (
350
+			empty($message_type_options)
351
+			|| ! is_array($message_type_options)
352
+			|| count($message_type_options) === 1
353
+		) {
354
+			return '';
355
+		}
356
+		// merge in default
357
+		$message_type_options = array_merge(
358
+			['none_selected' => esc_html__('Show All Message Types', 'event_espresso')],
359
+			$message_type_options
360
+		);
361
+		$input                = new EE_Select_Input(
362
+			$message_type_options,
363
+			[
364
+				'html_name'  => 'ee_message_type_filter_by',
365
+				'html_id'    => 'ee_message_type_filter_by',
366
+				'html_class' => 'wide',
367
+				'default'    => $this->request->getRequestParam('ee_message_type_filter_by', 'none_selected', 'title'),
368
+			]
369
+		);
370
+
371
+		return $input->get_html_for_input();
372
+	}
373
+
374
+
375
+	/**
376
+	 * Generate select input with provide message type contexts array.
377
+	 *
378
+	 * @param array $context_options Array of message type contexts indexed by context slug, and values are the
379
+	 *                               context label.
380
+	 * @return string
381
+	 * @throws EE_Error
382
+	 */
383
+	public function get_contexts_for_message_types_select_input($context_options)
384
+	{
385
+		// if empty or count of options is one then just return empty string
386
+		if (
387
+			empty($context_options)
388
+			|| ! is_array($context_options)
389
+			|| count($context_options) === 1
390
+		) {
391
+			return '';
392
+		}
393
+		// merge in default
394
+		$context_options = array_merge(
395
+			['none_selected' => esc_html__('Show all Contexts', 'event_espresso')],
396
+			$context_options
397
+		);
398
+		$input           = new EE_Select_Input(
399
+			$context_options,
400
+			[
401
+				'html_name'  => 'ee_context_filter_by',
402
+				'html_id'    => 'ee_context_filter_by',
403
+				'html_class' => 'wide',
404
+				'default'    => $this->request->getRequestParam('ee_context_filter_by', 'none_selected', 'title'),
405
+			]
406
+		);
407
+
408
+		return $input->get_html_for_input();
409
+	}
410
+
411
+
412
+	protected function _ajax_hooks()
413
+	{
414
+		add_action('wp_ajax_activate_messenger', [$this, 'activate_messenger_toggle']);
415
+		add_action('wp_ajax_activate_mt', [$this, 'activate_mt_toggle']);
416
+		add_action('wp_ajax_ee_msgs_save_settings', [$this, 'save_settings']);
417
+		add_action('wp_ajax_ee_msgs_update_mt_form', [$this, 'update_mt_form']);
418
+		add_action('wp_ajax_switch_template_pack', [$this, 'switch_template_pack']);
419
+		add_action('wp_ajax_toggle_context_template', [$this, 'toggle_context_template']);
420
+	}
421
+
422
+
423
+	protected function _define_page_props()
424
+	{
425
+		$this->_admin_page_title = $this->page_label;
426
+		$this->_labels           = [
427
+			'buttons'    => [
428
+				'add'    => esc_html__('Add New Message Template', 'event_espresso'),
429
+				'edit'   => esc_html__('Edit Message Template', 'event_espresso'),
430
+				'delete' => esc_html__('Delete Message Template', 'event_espresso'),
431
+			],
432
+			'publishbox' => esc_html__('Update Actions', 'event_espresso'),
433
+		];
434
+	}
435
+
436
+
437
+	/**
438
+	 *        an array for storing key => value pairs of request actions and their corresponding methods
439
+	 *
440
+	 * @access protected
441
+	 * @return void
442
+	 */
443
+	protected function _set_page_routes()
444
+	{
445
+		$GRP_ID = $this->request->getRequestParam('GRP_ID', 0, 'int');
446
+		$GRP_ID = $this->request->getRequestParam('id', $GRP_ID, 'int');
447
+		$MSG_ID = $this->request->getRequestParam('MSG_ID', 0, 'int');
448
+
449
+		$this->_page_routes = [
450
+			'default'                          => [
451
+				'func'       => '_message_queue_list_table',
452
+				'capability' => 'ee_read_global_messages',
453
+			],
454
+			'global_mtps'                      => [
455
+				'func'       => '_ee_default_messages_overview_list_table',
456
+				'capability' => 'ee_read_global_messages',
457
+			],
458
+			'custom_mtps'                      => [
459
+				'func'       => '_custom_mtps_preview',
460
+				'capability' => 'ee_read_messages',
461
+			],
462
+			'add_new_message_template'         => [
463
+				'func'       => 'add_message_template',
464
+				'capability' => 'ee_edit_messages',
465
+				'noheader'   => true,
466
+			],
467
+			'edit_message_template'            => [
468
+				'func'       => '_edit_message_template',
469
+				'capability' => 'ee_edit_message',
470
+				'obj_id'     => $GRP_ID,
471
+			],
472
+			'preview_message'                  => [
473
+				'func'               => '_preview_message',
474
+				'capability'         => 'ee_read_message',
475
+				'obj_id'             => $GRP_ID,
476
+				'noheader'           => true,
477
+				'headers_sent_route' => 'display_preview_message',
478
+			],
479
+			'display_preview_message'          => [
480
+				'func'       => '_display_preview_message',
481
+				'capability' => 'ee_read_message',
482
+				'obj_id'     => $GRP_ID,
483
+			],
484
+			'insert_message_template'          => [
485
+				'func'       => '_insert_or_update_message_template',
486
+				'capability' => 'ee_edit_messages',
487
+				'args'       => ['new' => true],
488
+				'noheader'   => true,
489
+			],
490
+			'update_message_template'          => [
491
+				'func'       => '_insert_or_update_message_template',
492
+				'capability' => 'ee_edit_message',
493
+				'obj_id'     => $GRP_ID,
494
+				'args'       => ['new' => false],
495
+				'noheader'   => true,
496
+			],
497
+			'trash_message_template'           => [
498
+				'func'       => '_trash_or_restore_message_template',
499
+				'capability' => 'ee_delete_message',
500
+				'obj_id'     => $GRP_ID,
501
+				'args'       => ['trash' => true, 'all' => true],
502
+				'noheader'   => true,
503
+			],
504
+			'trash_message_template_context'   => [
505
+				'func'       => '_trash_or_restore_message_template',
506
+				'capability' => 'ee_delete_message',
507
+				'obj_id'     => $GRP_ID,
508
+				'args'       => ['trash' => true],
509
+				'noheader'   => true,
510
+			],
511
+			'restore_message_template'         => [
512
+				'func'       => '_trash_or_restore_message_template',
513
+				'capability' => 'ee_delete_message',
514
+				'obj_id'     => $GRP_ID,
515
+				'args'       => ['trash' => false, 'all' => true],
516
+				'noheader'   => true,
517
+			],
518
+			'restore_message_template_context' => [
519
+				'func'       => '_trash_or_restore_message_template',
520
+				'capability' => 'ee_delete_message',
521
+				'obj_id'     => $GRP_ID,
522
+				'args'       => ['trash' => false],
523
+				'noheader'   => true,
524
+			],
525
+			'delete_message_template'          => [
526
+				'func'       => '_delete_message_template',
527
+				'capability' => 'ee_delete_message',
528
+				'obj_id'     => $GRP_ID,
529
+				'noheader'   => true,
530
+			],
531
+			'reset_to_default'                 => [
532
+				'func'       => '_reset_to_default_template',
533
+				'capability' => 'ee_edit_message',
534
+				'obj_id'     => $GRP_ID,
535
+				'noheader'   => true,
536
+			],
537
+			'settings'                         => [
538
+				'func'       => '_settings',
539
+				'capability' => 'manage_options',
540
+			],
541
+			'update_global_settings'           => [
542
+				'func'       => '_update_global_settings',
543
+				'capability' => 'manage_options',
544
+				'noheader'   => true,
545
+			],
546
+			'generate_now'                     => [
547
+				'func'       => '_generate_now',
548
+				'capability' => 'ee_send_message',
549
+				'noheader'   => true,
550
+			],
551
+			'generate_and_send_now'            => [
552
+				'func'       => '_generate_and_send_now',
553
+				'capability' => 'ee_send_message',
554
+				'noheader'   => true,
555
+			],
556
+			'queue_for_resending'              => [
557
+				'func'       => '_queue_for_resending',
558
+				'capability' => 'ee_send_message',
559
+				'noheader'   => true,
560
+			],
561
+			'send_now'                         => [
562
+				'func'       => '_send_now',
563
+				'capability' => 'ee_send_message',
564
+				'noheader'   => true,
565
+			],
566
+			'delete_ee_message'                => [
567
+				'func'       => '_delete_ee_messages',
568
+				'capability' => 'ee_delete_messages',
569
+				'noheader'   => true,
570
+			],
571
+			'delete_ee_messages'               => [
572
+				'func'       => '_delete_ee_messages',
573
+				'capability' => 'ee_delete_messages',
574
+				'noheader'   => true,
575
+				'obj_id'     => $MSG_ID,
576
+			],
577
+		];
578
+	}
579
+
580
+
581
+	protected function _set_page_config()
582
+	{
583
+		$this->_page_config = [
584
+			'default'                  => [
585
+				'nav'           => [
586
+					'label' => esc_html__('Message Activity', 'event_espresso'),
587
+					'icon' => 'dashicons-email',
588
+					'order' => 10,
589
+				],
590
+				'list_table'    => 'EE_Message_List_Table',
591
+				// 'qtips' => array( 'EE_Message_List_Table_Tips' ),
592
+				'require_nonce' => false,
593
+			],
594
+			'global_mtps'              => [
595
+				'nav'           => [
596
+					'label' => esc_html__('Default Message Templates', 'event_espresso'),
597
+					'icon' => 'dashicons-layout',
598
+					'order' => 20,
599
+				],
600
+				'list_table'    => 'Messages_Template_List_Table',
601
+				'help_tabs'     => [
602
+					'messages_overview_help_tab'                                => [
603
+						'title'    => esc_html__('Messages Overview', 'event_espresso'),
604
+						'filename' => 'messages_overview',
605
+					],
606
+					'messages_overview_messages_table_column_headings_help_tab' => [
607
+						'title'    => esc_html__('Messages Table Column Headings', 'event_espresso'),
608
+						'filename' => 'messages_overview_table_column_headings',
609
+					],
610
+					'messages_overview_messages_filters_help_tab'               => [
611
+						'title'    => esc_html__('Message Filters', 'event_espresso'),
612
+						'filename' => 'messages_overview_filters',
613
+					],
614
+					'messages_overview_messages_views_help_tab'                 => [
615
+						'title'    => esc_html__('Message Views', 'event_espresso'),
616
+						'filename' => 'messages_overview_views',
617
+					],
618
+					'message_overview_message_types_help_tab'                   => [
619
+						'title'    => esc_html__('Message Types', 'event_espresso'),
620
+						'filename' => 'messages_overview_types',
621
+					],
622
+					'messages_overview_messengers_help_tab'                     => [
623
+						'title'    => esc_html__('Messengers', 'event_espresso'),
624
+						'filename' => 'messages_overview_messengers',
625
+					],
626
+				],
627
+				'require_nonce' => false,
628
+			],
629
+			'custom_mtps'              => [
630
+				'nav'           => [
631
+					'label' => esc_html__('Custom Message Templates', 'event_espresso'),
632
+					'icon' => 'dashicons-admin-customizer',
633
+					'order' => 30,
634
+				],
635
+				'help_tabs'     => [],
636
+				'require_nonce' => false,
637
+			],
638
+			'add_new_message_template' => [
639
+				'nav'           => [
640
+					'label'      => esc_html__('Add New Message Templates', 'event_espresso'),
641
+					'icon' => 'dashicons-plus-alt',
642
+					'order'      => 5,
643
+					'persistent' => false,
644
+				],
645
+				'require_nonce' => false,
646
+			],
647
+			'edit_message_template'    => [
648
+				'labels'        => [
649
+					'buttons'    => [
650
+						'reset' => esc_html__('Reset Templates', 'event_espresso'),
651
+					],
652
+					'publishbox' => esc_html__('Update Actions', 'event_espresso'),
653
+				],
654
+				'nav'           => [
655
+					'label'      => esc_html__('Edit Message Templates', 'event_espresso'),
656
+					'icon' => 'dashicons-edit-large',
657
+					'order'      => 5,
658
+					'persistent' => false,
659
+					'url'        => '',
660
+				],
661
+				'metaboxes'     => ['_publish_post_box', '_register_edit_meta_boxes'],
662
+				'has_metaboxes' => true,
663
+				'help_tabs'     => [
664
+					'edit_message_template'            => [
665
+						'title'    => esc_html__('Message Template Editor', 'event_espresso'),
666
+						'callback' => 'edit_message_template_help_tab',
667
+					],
668
+					'message_templates_help_tab'       => [
669
+						'title'    => esc_html__('Message Templates', 'event_espresso'),
670
+						'filename' => 'messages_templates',
671
+					],
672
+					'message_template_shortcodes'      => [
673
+						'title'    => esc_html__('Message Shortcodes', 'event_espresso'),
674
+						'callback' => 'message_template_shortcodes_help_tab',
675
+					],
676
+					'message_preview_help_tab'         => [
677
+						'title'    => esc_html__('Message Preview', 'event_espresso'),
678
+						'filename' => 'messages_preview',
679
+					],
680
+					'messages_overview_other_help_tab' => [
681
+						'title'    => esc_html__('Messages Other', 'event_espresso'),
682
+						'filename' => 'messages_overview_other',
683
+					],
684
+				],
685
+				'require_nonce' => false,
686
+			],
687
+			'display_preview_message'  => [
688
+				'nav'           => [
689
+					'label'      => esc_html__('Message Preview', 'event_espresso'),
690
+					'icon' => 'dashicons-visibility-bar',
691
+					'order'      => 5,
692
+					'url'        => '',
693
+					'persistent' => false,
694
+				],
695
+				'help_tabs'     => [
696
+					'preview_message' => [
697
+						'title'    => esc_html__('About Previews', 'event_espresso'),
698
+						'callback' => 'preview_message_help_tab',
699
+					],
700
+				],
701
+				'require_nonce' => false,
702
+			],
703
+			'settings'                 => [
704
+				'nav'           => [
705
+					'label' => esc_html__('Settings', 'event_espresso'),
706
+					'icon' => 'dashicons-admin-generic',
707
+					'order' => 40,
708
+				],
709
+				'metaboxes'     => ['_messages_settings_metaboxes'],
710
+				'help_tabs'     => [
711
+					'messages_settings_help_tab'               => [
712
+						'title'    => esc_html__('Messages Settings', 'event_espresso'),
713
+						'filename' => 'messages_settings',
714
+					],
715
+					'messages_settings_message_types_help_tab' => [
716
+						'title'    => esc_html__('Activating / Deactivating Message Types', 'event_espresso'),
717
+						'filename' => 'messages_settings_message_types',
718
+					],
719
+					'messages_settings_messengers_help_tab'    => [
720
+						'title'    => esc_html__('Activating / Deactivating Messengers', 'event_espresso'),
721
+						'filename' => 'messages_settings_messengers',
722
+					],
723
+				],
724
+				'require_nonce' => false,
725
+			],
726
+		];
727
+	}
728
+
729
+
730
+	protected function _add_screen_options()
731
+	{
732
+		// todo
733
+	}
734
+
735
+
736
+	protected function _add_screen_options_global_mtps()
737
+	{
738
+		/**
739
+		 * Note: the reason for the value swap here on $this->_admin_page_title is because $this->_per_page_screen_options
740
+		 * uses the $_admin_page_title property and we want different outputs in the different spots.
741
+		 */
742
+		$page_title              = $this->_admin_page_title;
743
+		$this->_admin_page_title = esc_html__('Global Message Templates', 'event_espresso');
744
+		$this->_per_page_screen_option();
745
+		$this->_admin_page_title = $page_title;
746
+	}
747
+
748
+
749
+	protected function _add_screen_options_default()
750
+	{
751
+		$this->_admin_page_title = esc_html__('Message Activity', 'event_espresso');
752
+		$this->_per_page_screen_option();
753
+	}
754
+
755
+
756
+	// none of the below group are currently used for Messages
757
+	protected function _add_feature_pointers()
758
+	{
759
+	}
760
+
761
+
762
+	public function admin_init()
763
+	{
764
+	}
765
+
766
+
767
+	public function admin_notices()
768
+	{
769
+	}
770
+
771
+
772
+	public function admin_footer_scripts()
773
+	{
774
+	}
775
+
776
+
777
+	public function messages_help_tab()
778
+	{
779
+		EEH_Template::display_template(EE_MSG_TEMPLATE_PATH . 'ee_msg_messages_help_tab.template.php');
780
+	}
781
+
782
+
783
+	public function messengers_help_tab()
784
+	{
785
+		EEH_Template::display_template(EE_MSG_TEMPLATE_PATH . 'ee_msg_messenger_help_tab.template.php');
786
+	}
787
+
788
+
789
+	public function message_types_help_tab()
790
+	{
791
+		EEH_Template::display_template(EE_MSG_TEMPLATE_PATH . 'ee_msg_message_type_help_tab.template.php');
792
+	}
793
+
794
+
795
+	public function messages_overview_help_tab()
796
+	{
797
+		EEH_Template::display_template(EE_MSG_TEMPLATE_PATH . 'ee_msg_overview_help_tab.template.php');
798
+	}
799
+
800
+
801
+	public function message_templates_help_tab()
802
+	{
803
+		EEH_Template::display_template(EE_MSG_TEMPLATE_PATH . 'ee_msg_message_templates_help_tab.template.php');
804
+	}
805
+
806
+
807
+	public function edit_message_template_help_tab()
808
+	{
809
+		$args['img1'] = '<img src="' . EE_MSG_ASSETS_URL . 'images/editor.png' . '" alt="'
810
+						. esc_attr__('Editor Title', 'event_espresso')
811
+						. '" />';
812
+		$args['img2'] = '<img src="' . EE_MSG_ASSETS_URL . 'images/switch-context.png' . '" alt="'
813
+						. esc_attr__('Context Switcher and Preview', 'event_espresso')
814
+						. '" />';
815
+		$args['img3'] = '<img class="left" src="' . EE_MSG_ASSETS_URL . 'images/form-fields.png' . '" alt="'
816
+						. esc_attr__('Message Template Form Fields', 'event_espresso')
817
+						. '" />';
818
+		$args['img4'] = '<img class="right" src="' . EE_MSG_ASSETS_URL . 'images/shortcodes-metabox.png' . '" alt="'
819
+						. esc_attr__('Shortcodes Metabox', 'event_espresso')
820
+						. '" />';
821
+		$args['img5'] = '<img class="right" src="' . EE_MSG_ASSETS_URL . 'images/publish-meta-box.png' . '" alt="'
822
+						. esc_attr__('Publish Metabox', 'event_espresso')
823
+						. '" />';
824
+		EEH_Template::display_template(
825
+			EE_MSG_TEMPLATE_PATH . 'ee_msg_messages_templates_editor_help_tab.template.php',
826
+			$args
827
+		);
828
+	}
829
+
830
+
831
+	/**
832
+	 * @throws ReflectionException
833
+	 * @throws EE_Error
834
+	 */
835
+	public function message_template_shortcodes_help_tab()
836
+	{
837
+		$this->_set_shortcodes();
838
+		$args['shortcodes'] = $this->_shortcodes;
839
+		EEH_Template::display_template(
840
+			EE_MSG_TEMPLATE_PATH . 'ee_msg_messages_shortcodes_help_tab.template.php',
841
+			$args
842
+		);
843
+	}
844
+
845
+
846
+	public function preview_message_help_tab()
847
+	{
848
+		EEH_Template::display_template(EE_MSG_TEMPLATE_PATH . 'ee_msg_preview_help_tab.template.php');
849
+	}
850
+
851
+
852
+	public function settings_help_tab()
853
+	{
854
+		$args['img1'] = '<img class="inline-text" src="' . EE_MSG_ASSETS_URL . 'images/email-tab-active.png'
855
+						. '" alt="' . esc_attr__('Active Email Tab', 'event_espresso') . '" />';
856
+		$args['img2'] = '<img class="inline-text" src="' . EE_MSG_ASSETS_URL . 'images/email-tab-inactive.png'
857
+						. '" alt="' . esc_attr__('Inactive Email Tab', 'event_espresso') . '" />';
858
+		$args['img3'] = '<div class="switch">'
859
+						. '<input class="ee-on-off-toggle ee-toggle-round-flat"'
860
+						. ' type="checkbox" checked>'
861
+						. '<label for="ee-on-off-toggle-on"></label>'
862
+						. '</div>';
863
+		$args['img4'] = '<div class="switch">'
864
+						. '<input class="ee-on-off-toggle ee-toggle-round-flat"'
865
+						. ' type="checkbox">'
866
+						. '<label for="ee-on-off-toggle-on"></label>'
867
+						. '</div>';
868
+		EEH_Template::display_template(EE_MSG_TEMPLATE_PATH . 'ee_msg_messages_settings_help_tab.template.php', $args);
869
+	}
870
+
871
+
872
+	public function load_scripts_styles()
873
+	{
874
+		wp_register_style('espresso_ee_msg', EE_MSG_ASSETS_URL . 'ee_message_admin.css', EVENT_ESPRESSO_VERSION);
875
+		wp_enqueue_style('espresso_ee_msg');
876
+
877
+		wp_register_script(
878
+			'ee-messages-settings',
879
+			EE_MSG_ASSETS_URL . 'ee-messages-settings.js',
880
+			['jquery-ui-droppable', 'ee-serialize-full-array'],
881
+			EVENT_ESPRESSO_VERSION,
882
+			true
883
+		);
884
+		wp_register_script(
885
+			'ee-msg-list-table-js',
886
+			EE_MSG_ASSETS_URL . 'ee_message_admin_list_table.js',
887
+			['ee-dialog'],
888
+			EVENT_ESPRESSO_VERSION
889
+		);
890
+	}
891
+
892
+
893
+	public function load_scripts_styles_default()
894
+	{
895
+		wp_enqueue_script('ee-msg-list-table-js');
896
+	}
897
+
898
+
899
+	public function wp_editor_css($mce_css)
900
+	{
901
+		// if we're on the edit_message_template route
902
+		if ($this->_req_action === 'edit_message_template' && $this->_active_messenger instanceof EE_messenger) {
903
+			$message_type_name = $this->_active_message_type_name;
904
+
905
+			// we're going to REPLACE the existing mce css
906
+			// we need to get the css file location from the active messenger
907
+			$mce_css = $this->_active_messenger->get_variation(
908
+				$this->_template_pack,
909
+				$message_type_name,
910
+				true,
911
+				'wpeditor',
912
+				$this->_variation
913
+			);
914
+		}
915
+
916
+		return $mce_css;
917
+	}
918
+
919
+
920
+	/**
921
+	 * @throws EE_Error
922
+	 * @throws ReflectionException
923
+	 */
924
+	public function load_scripts_styles_edit_message_template()
925
+	{
926
+
927
+		$this->_set_shortcodes();
928
+
929
+		EE_Registry::$i18n_js_strings['confirm_default_reset']        = sprintf(
930
+			esc_html__(
931
+				'Are you sure you want to reset the %s %s message templates?  Remember continuing will reset the templates for all contexts in this messenger and message type group.',
932
+				'event_espresso'
933
+			),
934
+			$this->_message_template_group->messenger_obj()->label['singular'],
935
+			$this->_message_template_group->message_type_obj()->label['singular']
936
+		);
937
+		EE_Registry::$i18n_js_strings['confirm_switch_template_pack'] = esc_html__(
938
+			'Switching the template pack for a messages template will reset the content for the template so the new layout is loaded.  Any custom content in the existing template will be lost. Are you sure you wish to do this?',
939
+			'event_espresso'
940
+		);
941
+		EE_Registry::$i18n_js_strings['server_error']                 = esc_html__(
942
+			'An unknown error occurred on the server while attempting to process your request. Please refresh the page and try again or contact support.',
943
+			'event_espresso'
944
+		);
945
+
946
+		wp_register_script(
947
+			'ee_msgs_edit_js',
948
+			EE_MSG_ASSETS_URL . 'ee_message_editor.js',
949
+			['jquery'],
950
+			EVENT_ESPRESSO_VERSION
951
+		);
952
+
953
+		wp_enqueue_script('ee_admin_js');
954
+		wp_enqueue_script('ee_msgs_edit_js');
955
+
956
+		// add in special css for tiny_mce
957
+		add_filter('mce_css', [$this, 'wp_editor_css']);
958
+	}
959
+
960
+
961
+	/**
962
+	 * @throws EE_Error
963
+	 * @throws ReflectionException
964
+	 */
965
+	public function load_scripts_styles_display_preview_message()
966
+	{
967
+		$this->_set_message_template_group();
968
+		if ($this->_active_messenger_name) {
969
+			$this->_active_messenger = $this->_message_resource_manager->get_active_messenger(
970
+				$this->_active_messenger_name
971
+			);
972
+		}
973
+
974
+		wp_enqueue_style(
975
+			'espresso_preview_css',
976
+			$this->_active_messenger->get_variation(
977
+				$this->_template_pack,
978
+				$this->_active_message_type_name,
979
+				true,
980
+				'preview',
981
+				$this->_variation
982
+			)
983
+		);
984
+	}
985
+
986
+
987
+	public function load_scripts_styles_settings()
988
+	{
989
+		wp_register_style(
990
+			'ee-message-settings',
991
+			EE_MSG_ASSETS_URL . 'ee_message_settings.css',
992
+			[],
993
+			EVENT_ESPRESSO_VERSION
994
+		);
995
+		wp_enqueue_style('ee-text-links');
996
+		wp_enqueue_style('ee-message-settings');
997
+		wp_enqueue_script('ee-messages-settings');
998
+	}
999
+
1000
+
1001
+	/**
1002
+	 * set views array for List Table
1003
+	 */
1004
+	public function _set_list_table_views_global_mtps()
1005
+	{
1006
+		$this->_views = [
1007
+			'in_use' => [
1008
+				'slug'  => 'in_use',
1009
+				'label' => esc_html__('In Use', 'event_espresso'),
1010
+				'count' => 0,
1011
+			],
1012
+		];
1013
+	}
1014
+
1015
+
1016
+	/**
1017
+	 * Set views array for the Custom Template List Table
1018
+	 */
1019
+	public function _set_list_table_views_custom_mtps()
1020
+	{
1021
+		$this->_set_list_table_views_global_mtps();
1022
+		$this->_views['in_use']['bulk_action'] = [
1023
+			'trash_message_template' => esc_html__('Move to Trash', 'event_espresso'),
1024
+		];
1025
+	}
1026
+
1027
+
1028
+	/**
1029
+	 * set views array for message queue list table
1030
+	 *
1031
+	 * @throws InvalidDataTypeException
1032
+	 * @throws InvalidInterfaceException
1033
+	 * @throws InvalidArgumentException
1034
+	 * @throws EE_Error
1035
+	 * @throws ReflectionException
1036
+	 */
1037
+	public function _set_list_table_views_default()
1038
+	{
1039
+		EE_Registry::instance()->load_helper('Template');
1040
+
1041
+		$common_bulk_actions = EE_Registry::instance()->CAP->current_user_can(
1042
+			'ee_send_message',
1043
+			'message_list_table_bulk_actions'
1044
+		)
1045
+			? [
1046
+				'generate_now'          => esc_html__('Generate Now', 'event_espresso'),
1047
+				'generate_and_send_now' => esc_html__('Generate and Send Now', 'event_espresso'),
1048
+				'queue_for_resending'   => esc_html__('Queue for Resending', 'event_espresso'),
1049
+				'send_now'              => esc_html__('Send Now', 'event_espresso'),
1050
+			]
1051
+			: [];
1052
+
1053
+		$delete_bulk_action = EE_Registry::instance()->CAP->current_user_can(
1054
+			'ee_delete_messages',
1055
+			'message_list_table_bulk_actions'
1056
+		)
1057
+			? ['delete_ee_messages' => esc_html__('Delete Messages', 'event_espresso')]
1058
+			: [];
1059
+
1060
+
1061
+		$this->_views = [
1062
+			'all' => [
1063
+				'slug'        => 'all',
1064
+				'label'       => esc_html__('All', 'event_espresso'),
1065
+				'count'       => 0,
1066
+				'bulk_action' => array_merge($common_bulk_actions, $delete_bulk_action),
1067
+			],
1068
+		];
1069
+
1070
+
1071
+		foreach ($this->getMsgModel()->all_statuses() as $status) {
1072
+			if ($status === EEM_Message::status_debug_only && ! EEM_Message::debug()) {
1073
+				continue;
1074
+			}
1075
+			$status_bulk_actions = $common_bulk_actions;
1076
+			// unset bulk actions not applying to status
1077
+			if (! empty($status_bulk_actions)) {
1078
+				switch ($status) {
1079
+					case EEM_Message::status_idle:
1080
+					case EEM_Message::status_resend:
1081
+						$status_bulk_actions['send_now'] = $common_bulk_actions['send_now'];
1082
+						break;
1083
+
1084
+					case EEM_Message::status_failed:
1085
+					case EEM_Message::status_debug_only:
1086
+					case EEM_Message::status_messenger_executing:
1087
+						$status_bulk_actions = [];
1088
+						break;
1089
+
1090
+					case EEM_Message::status_incomplete:
1091
+						unset($status_bulk_actions['queue_for_resending'], $status_bulk_actions['send_now']);
1092
+						break;
1093
+
1094
+					case EEM_Message::status_retry:
1095
+					case EEM_Message::status_sent:
1096
+						unset($status_bulk_actions['generate_now'], $status_bulk_actions['generate_and_send_now']);
1097
+						break;
1098
+				}
1099
+			}
1100
+
1101
+			// skip adding messenger executing status to views because it will be included with the Failed view.
1102
+			if ($status === EEM_Message::status_messenger_executing) {
1103
+				continue;
1104
+			}
1105
+
1106
+			$this->_views[ strtolower($status) ] = [
1107
+				'slug'        => strtolower($status),
1108
+				'label'       => EEH_Template::pretty_status($status, false, 'sentence'),
1109
+				'count'       => 0,
1110
+				'bulk_action' => array_merge($status_bulk_actions, $delete_bulk_action),
1111
+			];
1112
+		}
1113
+	}
1114
+
1115
+
1116
+	/**
1117
+	 * @throws EE_Error
1118
+	 */
1119
+	protected function _ee_default_messages_overview_list_table()
1120
+	{
1121
+		$this->_admin_page_title = esc_html__('Default Message Templates', 'event_espresso');
1122
+		$this->display_admin_list_table_page_with_no_sidebar();
1123
+	}
1124
+
1125
+
1126
+	/**
1127
+	 * @throws EE_Error
1128
+	 * @throws ReflectionException
1129
+	 */
1130
+	protected function _message_queue_list_table()
1131
+	{
1132
+		$this->_search_btn_label                   = esc_html__('Message Activity', 'event_espresso');
1133
+		$this->_template_args['per_column']        = 6;
1134
+		$this->_template_args['after_list_table']  = $this->_display_legend($this->_message_legend_items());
1135
+		$message_results = trim(EEM_Message::instance()->get_pretty_label_for_results());
1136
+		$this->_template_args['before_list_table'] = ! empty($message_results) ? "<h3>{$message_results}</h3>" : '';
1137
+		$this->display_admin_list_table_page_with_no_sidebar();
1138
+	}
1139
+
1140
+
1141
+	/**
1142
+	 * @throws EE_Error
1143
+	 */
1144
+	protected function _message_legend_items()
1145
+	{
1146
+
1147
+		$action_css_classes = EEH_MSG_Template::get_message_action_icons();
1148
+		$action_items       = [];
1149
+
1150
+		foreach ($action_css_classes as $action_item => $action_details) {
1151
+			if ($action_item === 'see_notifications_for') {
1152
+				continue;
1153
+			}
1154
+			$action_items[ $action_item ] = [
1155
+				'class' => $action_details['css_class'],
1156
+				'desc'  => $action_details['label'],
1157
+			];
1158
+		}
1159
+
1160
+		/** @var array $status_items status legend setup */
1161
+		$status_items = [
1162
+			'sent_status'                => [
1163
+				'class' => 'ee-status-legend ee-status-bg--' . EEM_Message::status_sent,
1164
+				'desc'  => EEH_Template::pretty_status(EEM_Message::status_sent, false, 'sentence'),
1165
+			],
1166
+			'idle_status'                => [
1167
+				'class' => 'ee-status-legend ee-status-bg--' . EEM_Message::status_idle,
1168
+				'desc'  => EEH_Template::pretty_status(EEM_Message::status_idle, false, 'sentence'),
1169
+			],
1170
+			'failed_status'              => [
1171
+				'class' => 'ee-status-legend ee-status-bg--' . EEM_Message::status_failed,
1172
+				'desc'  => EEH_Template::pretty_status(EEM_Message::status_failed, false, 'sentence'),
1173
+			],
1174
+			'messenger_executing_status' => [
1175
+				'class' => 'ee-status-legend ee-status-bg--' . EEM_Message::status_messenger_executing,
1176
+				'desc'  => EEH_Template::pretty_status(EEM_Message::status_messenger_executing, false, 'sentence'),
1177
+			],
1178
+			'resend_status'              => [
1179
+				'class' => 'ee-status-legend ee-status-bg--' . EEM_Message::status_resend,
1180
+				'desc'  => EEH_Template::pretty_status(EEM_Message::status_resend, false, 'sentence'),
1181
+			],
1182
+			'incomplete_status'          => [
1183
+				'class' => 'ee-status-legend ee-status-bg--' . EEM_Message::status_incomplete,
1184
+				'desc'  => EEH_Template::pretty_status(EEM_Message::status_incomplete, false, 'sentence'),
1185
+			],
1186
+			'retry_status'               => [
1187
+				'class' => 'ee-status-legend ee-status-bg--' . EEM_Message::status_retry,
1188
+				'desc'  => EEH_Template::pretty_status(EEM_Message::status_retry, false, 'sentence'),
1189
+			],
1190
+		];
1191
+		if (EEM_Message::debug()) {
1192
+			$status_items['debug_only_status'] = [
1193
+				'class' => 'ee-status-legend ee-status-bg--' . EEM_Message::status_debug_only,
1194
+				'desc'  => EEH_Template::pretty_status(EEM_Message::status_debug_only, false, 'sentence'),
1195
+			];
1196
+		}
1197
+
1198
+		return array_merge($action_items, $status_items);
1199
+	}
1200
+
1201
+
1202
+	/**
1203
+	 * @throws EE_Error
1204
+	 */
1205
+	protected function _custom_mtps_preview()
1206
+	{
1207
+		$this->_admin_page_title              = esc_html__('Custom Message Templates (Preview)', 'event_espresso');
1208
+		$this->_template_args['preview_img']  = '<img src="' . EE_MSG_ASSETS_URL . 'images/custom_mtps_preview.png"'
1209
+												. ' alt="' . esc_attr__(
1210
+													'Preview Custom Message Templates screenshot',
1211
+													'event_espresso'
1212
+												) . '" />';
1213
+		$this->_template_args['preview_text'] = '<strong>'
1214
+												. esc_html__(
1215
+													'Custom Message Templates is a feature that is only available in the premium version of Event Espresso 4 which is available with a support license purchase on EventEspresso.com. With the Custom Message Templates feature, you are able to create custom message templates and assign them on a per-event basis.',
1216
+													'event_espresso'
1217
+												)
1218
+												. '</strong>';
1219
+
1220
+		$this->display_admin_caf_preview_page('custom_message_types', false);
1221
+	}
1222
+
1223
+
1224
+	/**
1225
+	 * get_message_templates
1226
+	 * This gets all the message templates for listing on the overview list.
1227
+	 *
1228
+	 * @access public
1229
+	 * @param int    $per_page the amount of templates groups to show per page
1230
+	 * @param string $type     the current _view we're getting templates for
1231
+	 * @param bool   $count    return count?
1232
+	 * @param bool   $all      disregard any paging info (get all data);
1233
+	 * @param bool   $global   whether to return just global (true) or custom templates (false)
1234
+	 * @return array
1235
+	 * @throws EE_Error
1236
+	 * @throws InvalidArgumentException
1237
+	 * @throws InvalidDataTypeException
1238
+	 * @throws InvalidInterfaceException
1239
+	 */
1240
+	public function get_message_templates(
1241
+		$per_page = 10,
1242
+		$type = 'in_use',
1243
+		$count = false,
1244
+		$all = false,
1245
+		$global = true
1246
+	) {
1247
+		$orderby = $this->request->getRequestParam('orderby', 'GRP_ID');
1248
+		$this->request->setRequestParam('orderby', $orderby);
1249
+
1250
+		$order        = $this->request->getRequestParam('order', 'ASC');
1251
+		$current_page = $this->request->getRequestParam('paged', 1, 'int');
1252
+		$per_page     = $this->request->getRequestParam('perpage', $per_page, 'int');
1253
+
1254
+		$offset = ($current_page - 1) * $per_page;
1255
+		$limit  = $all ? null : [$offset, $per_page];
1256
+
1257
+		// options will match what is in the _views array property
1258
+		return $type === 'in_use'
1259
+			? $this->getMtgModel()->get_all_active_message_templates(
1260
+				$orderby,
1261
+				$order,
1262
+				$limit,
1263
+				$count,
1264
+				$global,
1265
+				true
1266
+			)
1267
+			: $this->getMtgModel()->get_all_trashed_grouped_message_templates(
1268
+				$orderby,
1269
+				$order,
1270
+				$limit,
1271
+				$count,
1272
+				$global
1273
+			);
1274
+	}
1275
+
1276
+
1277
+	/**
1278
+	 * filters etc might need a list of installed message_types
1279
+	 *
1280
+	 * @return array an array of message type objects
1281
+	 */
1282
+	public function get_installed_message_types()
1283
+	{
1284
+		$installed_message_types = $this->_message_resource_manager->installed_message_types();
1285
+		$installed               = [];
1286
+
1287
+		foreach ($installed_message_types as $message_type) {
1288
+			$installed[ $message_type->name ] = $message_type;
1289
+		}
1290
+
1291
+		return $installed;
1292
+	}
1293
+
1294
+
1295
+	/**
1296
+	 * This is used when creating a custom template. All Custom Templates start based off another template.
1297
+	 *
1298
+	 * @param string $message_type
1299
+	 * @param string $messenger
1300
+	 * @param string $GRP_ID
1301
+	 *
1302
+	 * @throws EE_error
1303
+	 * @throws ReflectionException
1304
+	 */
1305
+	public function add_message_template($message_type = '', $messenger = '', $GRP_ID = '')
1306
+	{
1307
+		// set values override any request data
1308
+		$message_type = ! empty($message_type) ? $message_type : $this->_active_message_type_name;
1309
+		$messenger    = ! empty($messenger) ? $messenger : $this->_active_messenger_name;
1310
+		$GRP_ID       = ! empty($GRP_ID) ? $GRP_ID : $this->request->getRequestParam('GRP_ID', 0, 'int');
1311
+
1312
+		// we need messenger and message type.  They should be coming from the event editor. If not here then return error
1313
+		if (empty($message_type) || empty($messenger)) {
1314
+			throw new EE_Error(
1315
+				esc_html__(
1316
+					'Sorry, but we can\'t create new templates because we\'re missing the messenger or message type',
1317
+					'event_espresso'
1318
+				)
1319
+			);
1320
+		}
1321
+
1322
+		// we need the GRP_ID for the template being used as the base for the new template
1323
+		if (empty($GRP_ID)) {
1324
+			throw new EE_Error(
1325
+				esc_html__(
1326
+					'In order to create a custom message template the GRP_ID of the template being used as a base is needed',
1327
+					'event_espresso'
1328
+				)
1329
+			);
1330
+		}
1331
+
1332
+		// let's just make sure the template gets generated!
1333
+
1334
+		// we need to reassign some variables for what the insert is expecting
1335
+		$this->request->setRequestParam('MTP_messenger', $messenger);
1336
+		$this->request->setRequestParam('MTP_message_type', $message_type);
1337
+		$this->request->setRequestParam('GRP_ID', $GRP_ID);
1338
+
1339
+		$this->_insert_or_update_message_template(true);
1340
+	}
1341
+
1342
+
1343
+	/**
1344
+	 * @param string $message_type     message type slug
1345
+	 * @param string $messenger        messenger slug
1346
+	 * @param int    $GRP_ID           GRP_ID for the related message template group this new template will be based
1347
+	 *                                 off of.
1348
+	 * @throws EE_error
1349
+	 * @throws ReflectionException
1350
+	 * @deprecated 4.10.29.p
1351
+	 */
1352
+	protected function _add_message_template($message_type, $messenger, $GRP_ID)
1353
+	{
1354
+		$this->add_message_template($message_type, $messenger, $GRP_ID);
1355
+	}
1356
+
1357
+
1358
+	/**
1359
+	 * _edit_message_template
1360
+	 *
1361
+	 * @access protected
1362
+	 * @return void
1363
+	 * @throws InvalidIdentifierException
1364
+	 * @throws DomainException
1365
+	 * @throws EE_Error
1366
+	 * @throws InvalidArgumentException
1367
+	 * @throws ReflectionException
1368
+	 * @throws InvalidDataTypeException
1369
+	 * @throws InvalidInterfaceException
1370
+	 */
1371
+	protected function _edit_message_template()
1372
+	{
1373
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
1374
+		$template_fields = '';
1375
+		$sidebar_fields  = '';
1376
+		// we filter the tinyMCE settings to remove the validation since message templates by their nature will not have
1377
+		// valid html in the templates.
1378
+		add_filter('tiny_mce_before_init', [$this, 'filter_tinymce_init'], 10, 2);
1379
+
1380
+		$GRP_ID = $this->request->getRequestParam('id', 0, 'int');
1381
+		$EVT_ID = $this->request->getRequestParam('evt_id', 0, 'int');
1382
+
1383
+		$this->_set_shortcodes(); // this also sets the _message_template property.
1384
+		$message_template_group = $this->_message_template_group;
1385
+		$c_label                = $message_template_group->context_label();
1386
+		$c_config               = $message_template_group->contexts_config();
1387
+
1388
+		reset($c_config);
1389
+		$context = $this->request->getRequestParam('context', key($c_config));
1390
+		$context = strtolower($context);
1391
+
1392
+		$action = empty($GRP_ID) ? 'insert_message_template' : 'update_message_template';
1393
+
1394
+		$edit_message_template_form_url = add_query_arg(
1395
+			['action' => $action, 'noheader' => true],
1396
+			EE_MSG_ADMIN_URL
1397
+		);
1398
+
1399
+		// set active messenger for this view
1400
+		$this->_active_messenger         = $this->_message_resource_manager->get_active_messenger(
1401
+			$message_template_group->messenger()
1402
+		);
1403
+		$this->_active_message_type_name = $message_template_group->message_type();
1404
+
1405
+
1406
+		// Do we have any validation errors?
1407
+		$validators = $this->_get_transient();
1408
+		$v_fields   = ! empty($validators) ? array_keys($validators) : [];
1409
+
1410
+
1411
+		// we need to assemble the title from Various details
1412
+		$context_label = sprintf(
1413
+			esc_html__('(%s %s)', 'event_espresso'),
1414
+			$c_config[ $context ]['label'],
1415
+			ucwords($c_label['label'])
1416
+		);
1417
+
1418
+		$title = sprintf(
1419
+			esc_html__(' %s %s Template %s', 'event_espresso'),
1420
+			ucwords($message_template_group->messenger_obj()->label['singular']),
1421
+			ucwords($message_template_group->message_type_obj()->label['singular']),
1422
+			$context_label
1423
+		);
1424
+
1425
+		$this->_template_args['GRP_ID']           = $GRP_ID;
1426
+		$this->_template_args['message_template'] = $message_template_group;
1427
+		$this->_template_args['is_extra_fields']  = false;
1428
+
1429
+
1430
+		// let's get EEH_MSG_Template so we can get template form fields
1431
+		$template_field_structure = EEH_MSG_Template::get_fields(
1432
+			$message_template_group->messenger(),
1433
+			$message_template_group->message_type()
1434
+		);
1435
+
1436
+		if (! $template_field_structure) {
1437
+			$template_field_structure = false;
1438
+			$template_fields          = esc_html__(
1439
+				'There was an error in assembling the fields for this display (you should see an error message)',
1440
+				'event_espresso'
1441
+			);
1442
+		}
1443
+
1444
+
1445
+		$message_templates = $message_template_group->context_templates();
1446
+
1447
+
1448
+		// if we have the extra key.. then we need to remove the content index from the template_field_structure as it
1449
+		// will get handled in the "extra" array.
1450
+		if (is_array($template_field_structure[ $context ]) && isset($template_field_structure[ $context ]['extra'])) {
1451
+			foreach ($template_field_structure[ $context ]['extra'] as $reference_field => $new_fields) {
1452
+				unset($template_field_structure[ $context ][ $reference_field ]);
1453
+			}
1454
+		}
1455
+
1456
+		// let's loop through the template_field_structure and actually assemble the input fields!
1457
+		if (! empty($template_field_structure)) {
1458
+			foreach ($template_field_structure[ $context ] as $template_field => $field_setup_array) {
1459
+				// if this is an 'extra' template field then we need to remove any existing fields that are keyed up in
1460
+				// the extra array and reset them.
1461
+				if ($template_field === 'extra') {
1462
+					$this->_template_args['is_extra_fields'] = true;
1463
+					foreach ($field_setup_array as $reference_field => $new_fields_array) {
1464
+						$message_template = $message_templates[ $context ][ $reference_field ];
1465
+						$content          = $message_template instanceof EE_Message_Template
1466
+							? $message_template->get('MTP_content')
1467
+							: '';
1468
+						foreach ($new_fields_array as $extra_field => $extra_array) {
1469
+							// let's verify if we need this extra field via the shortcodes parameter.
1470
+							$continue = false;
1471
+							if (isset($extra_array['shortcodes_required'])) {
1472
+								foreach ((array) $extra_array['shortcodes_required'] as $shortcode) {
1473
+									if (! array_key_exists($shortcode, $this->_shortcodes)) {
1474
+										$continue = true;
1475
+									}
1476
+								}
1477
+								if ($continue) {
1478
+									continue;
1479
+								}
1480
+							}
1481
+
1482
+							$field_id = $reference_field . '-' . $extra_field . '-content';
1483
+
1484
+							$template_form_fields[ $field_id ]         = $extra_array;
1485
+							$template_form_fields[ $field_id ]['name'] = 'MTP_template_fields['
1486
+																		 . $reference_field
1487
+																		 . '][content]['
1488
+																		 . $extra_field . ']';
1489
+							$css_class                                 = isset($extra_array['css_class'])
1490
+								? $extra_array['css_class']
1491
+								: '';
1492
+
1493
+							$template_form_fields[ $field_id ]['css_class'] = ! empty($v_fields)
1494
+																			  && in_array($extra_field, $v_fields, true)
1495
+																			  && (
1496
+																				  is_array($validators[ $extra_field ])
1497
+																				  && isset($validators[ $extra_field ]['msg'])
1498
+																			  )
1499
+								? 'validate-error ' . $css_class
1500
+								: $css_class;
1501
+
1502
+							$template_form_fields[ $field_id ]['value'] = ! empty($message_templates)
1503
+																		  && isset($content[ $extra_field ])
1504
+								? $content[ $extra_field ]
1505
+								: '';
1506
+
1507
+							// do we have a validation error?  if we do then let's use that value instead
1508
+							$template_form_fields[ $field_id ]['value'] = isset($validators[ $extra_field ])
1509
+								? $validators[ $extra_field ]['value']
1510
+								: $template_form_fields[ $field_id ]['value'];
1511
+
1512
+
1513
+							$template_form_fields[ $field_id ]['db-col'] = 'MTP_content';
1514
+
1515
+							// shortcode selector
1516
+							$field_name_to_use                                   = $extra_field === 'main'
1517
+								? 'content'
1518
+								: $extra_field;
1519
+							$template_form_fields[ $field_id ]['append_content'] = $this->_get_shortcode_selector(
1520
+								$field_name_to_use,
1521
+								$field_id
1522
+							);
1523
+						}
1524
+						$template_field_MTP_id           = $reference_field . '-MTP_ID';
1525
+						$template_field_template_name_id = $reference_field . '-name';
1526
+
1527
+						$template_form_fields[ $template_field_MTP_id ] = [
1528
+							'name'       => 'MTP_template_fields[' . $reference_field . '][MTP_ID]',
1529
+							'label'      => null,
1530
+							'input'      => 'hidden',
1531
+							'type'       => 'int',
1532
+							'required'   => false,
1533
+							'validation' => false,
1534
+							'value'      => ! empty($message_templates) ? $message_template->ID() : '',
1535
+							'css_class'  => '',
1536
+							'format'     => '%d',
1537
+							'db-col'     => 'MTP_ID',
1538
+						];
1539
+
1540
+						$template_form_fields[ $template_field_template_name_id ] = [
1541
+							'name'       => 'MTP_template_fields[' . $reference_field . '][name]',
1542
+							'label'      => null,
1543
+							'input'      => 'hidden',
1544
+							'type'       => 'string',
1545
+							'required'   => false,
1546
+							'validation' => true,
1547
+							'value'      => $reference_field,
1548
+							'css_class'  => '',
1549
+							'format'     => '%s',
1550
+							'db-col'     => 'MTP_template_field',
1551
+						];
1552
+					}
1553
+					continue; // skip the next stuff, we got the necessary fields here for this dataset.
1554
+				} else {
1555
+					$field_id                                   = $template_field . '-content';
1556
+					$template_form_fields[ $field_id ]          = $field_setup_array;
1557
+					$template_form_fields[ $field_id ]['name']  =
1558
+						'MTP_template_fields[' . $template_field . '][content]';
1559
+					$message_template                           =
1560
+						isset($message_templates[ $context ][ $template_field ])
1561
+							? $message_templates[ $context ][ $template_field ]
1562
+							: null;
1563
+					$template_form_fields[ $field_id ]['value'] = ! empty($message_templates)
1564
+																  && is_array($message_templates[ $context ])
1565
+																  && $message_template instanceof EE_Message_Template
1566
+						? $message_template->get('MTP_content')
1567
+						: '';
1568
+
1569
+					// do we have a validator error for this field?  if we do then we'll use that value instead
1570
+					$template_form_fields[ $field_id ]['value'] = isset($validators[ $template_field ])
1571
+						? $validators[ $template_field ]['value']
1572
+						: $template_form_fields[ $field_id ]['value'];
1573
+
1574
+
1575
+					$template_form_fields[ $field_id ]['db-col']    = 'MTP_content';
1576
+					$css_class                                      = isset($field_setup_array['css_class'])
1577
+						? $field_setup_array['css_class']
1578
+						: '';
1579
+					$template_form_fields[ $field_id ]['css_class'] = ! empty($v_fields)
1580
+																	  && in_array($template_field, $v_fields, true)
1581
+																	  && isset($validators[ $template_field ]['msg'])
1582
+						? 'validate-error ' . $css_class
1583
+						: $css_class;
1584
+
1585
+					// shortcode selector
1586
+					$template_form_fields[ $field_id ]['append_content'] = $this->_get_shortcode_selector(
1587
+						$template_field,
1588
+						$field_id
1589
+					);
1590
+				}
1591
+
1592
+				// k took care of content field(s) now let's take care of others.
1593
+
1594
+				$template_field_MTP_id                 = $template_field . '-MTP_ID';
1595
+				$template_field_field_template_name_id = $template_field . '-name';
1596
+
1597
+				// foreach template field there are actually two form fields created
1598
+				$template_form_fields[ $template_field_MTP_id ] = [
1599
+					'name'       => 'MTP_template_fields[' . $template_field . '][MTP_ID]',
1600
+					'label'      => null,
1601
+					'input'      => 'hidden',
1602
+					'type'       => 'int',
1603
+					'required'   => false,
1604
+					'validation' => true,
1605
+					'value'      => $message_template instanceof EE_Message_Template ? $message_template->ID() : '',
1606
+					'css_class'  => '',
1607
+					'format'     => '%d',
1608
+					'db-col'     => 'MTP_ID',
1609
+				];
1610
+
1611
+				$template_form_fields[ $template_field_field_template_name_id ] = [
1612
+					'name'       => 'MTP_template_fields[' . $template_field . '][name]',
1613
+					'label'      => null,
1614
+					'input'      => 'hidden',
1615
+					'type'       => 'string',
1616
+					'required'   => false,
1617
+					'validation' => true,
1618
+					'value'      => $template_field,
1619
+					'css_class'  => '',
1620
+					'format'     => '%s',
1621
+					'db-col'     => 'MTP_template_field',
1622
+				];
1623
+			}
1624
+
1625
+			// add other fields
1626
+			$template_form_fields['ee-msg-current-context'] = [
1627
+				'name'       => 'MTP_context',
1628
+				'label'      => null,
1629
+				'input'      => 'hidden',
1630
+				'type'       => 'string',
1631
+				'required'   => false,
1632
+				'validation' => true,
1633
+				'value'      => $context,
1634
+				'css_class'  => '',
1635
+				'format'     => '%s',
1636
+				'db-col'     => 'MTP_context',
1637
+			];
1638
+
1639
+			$template_form_fields['ee-msg-grp-id'] = [
1640
+				'name'       => 'GRP_ID',
1641
+				'label'      => null,
1642
+				'input'      => 'hidden',
1643
+				'type'       => 'int',
1644
+				'required'   => false,
1645
+				'validation' => true,
1646
+				'value'      => $GRP_ID,
1647
+				'css_class'  => '',
1648
+				'format'     => '%d',
1649
+				'db-col'     => 'GRP_ID',
1650
+			];
1651
+
1652
+			$template_form_fields['ee-msg-messenger'] = [
1653
+				'name'       => 'MTP_messenger',
1654
+				'label'      => null,
1655
+				'input'      => 'hidden',
1656
+				'type'       => 'string',
1657
+				'required'   => false,
1658
+				'validation' => true,
1659
+				'value'      => $message_template_group->messenger(),
1660
+				'css_class'  => '',
1661
+				'format'     => '%s',
1662
+				'db-col'     => 'MTP_messenger',
1663
+			];
1664
+
1665
+			$template_form_fields['ee-msg-message-type'] = [
1666
+				'name'       => 'MTP_message_type',
1667
+				'label'      => null,
1668
+				'input'      => 'hidden',
1669
+				'type'       => 'string',
1670
+				'required'   => false,
1671
+				'validation' => true,
1672
+				'value'      => $message_template_group->message_type(),
1673
+				'css_class'  => '',
1674
+				'format'     => '%s',
1675
+				'db-col'     => 'MTP_message_type',
1676
+			];
1677
+
1678
+			$sidebar_form_fields['ee-msg-is-global'] = [
1679
+				'name'       => 'MTP_is_global',
1680
+				'label'      => esc_html__('Global Template', 'event_espresso'),
1681
+				'input'      => 'hidden',
1682
+				'type'       => 'int',
1683
+				'required'   => false,
1684
+				'validation' => true,
1685
+				'value'      => $message_template_group->get('MTP_is_global'),
1686
+				'css_class'  => '',
1687
+				'format'     => '%d',
1688
+				'db-col'     => 'MTP_is_global',
1689
+			];
1690
+
1691
+			$sidebar_form_fields['ee-msg-is-override'] = [
1692
+				'name'       => 'MTP_is_override',
1693
+				'label'      => esc_html__('Override all custom', 'event_espresso'),
1694
+				'input'      => $message_template_group->is_global() ? 'checkbox' : 'hidden',
1695
+				'type'       => 'int',
1696
+				'required'   => false,
1697
+				'validation' => true,
1698
+				'value'      => $message_template_group->get('MTP_is_override'),
1699
+				'css_class'  => '',
1700
+				'format'     => '%d',
1701
+				'db-col'     => 'MTP_is_override',
1702
+			];
1703
+
1704
+			$sidebar_form_fields['ee-msg-is-active'] = [
1705
+				'name'       => 'MTP_is_active',
1706
+				'label'      => esc_html__('Active Template', 'event_espresso'),
1707
+				'input'      => 'hidden',
1708
+				'type'       => 'int',
1709
+				'required'   => false,
1710
+				'validation' => true,
1711
+				'value'      => $message_template_group->is_active(),
1712
+				'css_class'  => '',
1713
+				'format'     => '%d',
1714
+				'db-col'     => 'MTP_is_active',
1715
+			];
1716
+
1717
+			$sidebar_form_fields['ee-msg-deleted'] = [
1718
+				'name'       => 'MTP_deleted',
1719
+				'label'      => null,
1720
+				'input'      => 'hidden',
1721
+				'type'       => 'int',
1722
+				'required'   => false,
1723
+				'validation' => true,
1724
+				'value'      => $message_template_group->get('MTP_deleted'),
1725
+				'css_class'  => '',
1726
+				'format'     => '%d',
1727
+				'db-col'     => 'MTP_deleted',
1728
+			];
1729
+			$sidebar_form_fields['ee-msg-author']  = [
1730
+				'name'       => 'MTP_user_id',
1731
+				'label'      => esc_html__('Author', 'event_espresso'),
1732
+				'input'      => 'hidden',
1733
+				'type'       => 'int',
1734
+				'required'   => false,
1735
+				'validation' => false,
1736
+				'value'      => $message_template_group->user(),
1737
+				'format'     => '%d',
1738
+				'db-col'     => 'MTP_user_id',
1739
+			];
1740
+
1741
+			$sidebar_form_fields['ee-msg-route'] = [
1742
+				'name'  => 'action',
1743
+				'input' => 'hidden',
1744
+				'type'  => 'string',
1745
+				'value' => $action,
1746
+			];
1747
+
1748
+			$sidebar_form_fields['ee-msg-id']        = [
1749
+				'name'  => 'id',
1750
+				'input' => 'hidden',
1751
+				'type'  => 'int',
1752
+				'value' => $GRP_ID,
1753
+			];
1754
+			$sidebar_form_fields['ee-msg-evt-nonce'] = [
1755
+				'name'  => $action . '_nonce',
1756
+				'input' => 'hidden',
1757
+				'type'  => 'string',
1758
+				'value' => wp_create_nonce($action . '_nonce'),
1759
+			];
1760
+
1761
+			$template_switch = $this->request->getRequestParam('template_switch');
1762
+			if ($template_switch) {
1763
+				$sidebar_form_fields['ee-msg-template-switch'] = [
1764
+					'name'  => 'template_switch',
1765
+					'input' => 'hidden',
1766
+					'type'  => 'int',
1767
+					'value' => 1,
1768
+				];
1769
+			}
1770
+
1771
+
1772
+			$template_fields = $this->_generate_admin_form_fields($template_form_fields);
1773
+			$sidebar_fields  = $this->_generate_admin_form_fields($sidebar_form_fields);
1774
+		} //end if ( !empty($template_field_structure) )
1775
+
1776
+		// set extra content for publish box
1777
+		$this->_template_args['publish_box_extra_content'] = $sidebar_fields;
1778
+		$this->_set_publish_post_box_vars(
1779
+			'id',
1780
+			$GRP_ID,
1781
+			false,
1782
+			add_query_arg(
1783
+				['action' => 'global_mtps'],
1784
+				$this->_admin_base_url
1785
+			)
1786
+		);
1787
+
1788
+		// add preview button
1789
+		$preview_url    = parent::add_query_args_and_nonce(
1790
+			[
1791
+				'message_type' => $message_template_group->message_type(),
1792
+				'messenger'    => $message_template_group->messenger(),
1793
+				'context'      => $context,
1794
+				'GRP_ID'       => $GRP_ID,
1795
+				'evt_id'       => $EVT_ID ?: false,
1796
+				'action'       => 'preview_message',
1797
+			],
1798
+			$this->_admin_base_url
1799
+		);
1800
+		$preview_button = '<a href="' . $preview_url . '" class="button--secondary messages-preview-button">'
1801
+						  . esc_html__('Preview', 'event_espresso')
1802
+						  . '</a>';
1803
+
1804
+
1805
+		// setup context switcher
1806
+		$this->_set_context_switcher(
1807
+			$message_template_group,
1808
+			[
1809
+				'page'    => 'espresso_messages',
1810
+				'action'  => 'edit_message_template',
1811
+				'id'      => $GRP_ID,
1812
+				'evt_id'  => $EVT_ID,
1813
+				'context' => $context,
1814
+				'extra'   => $preview_button,
1815
+			]
1816
+		);
1817
+
1818
+
1819
+		// main box
1820
+		$this->_template_args['template_fields']                         = $template_fields;
1821
+		$this->_template_args['sidebar_box_id']                          = 'details';
1822
+		$this->_template_args['action']                                  = $action;
1823
+		$this->_template_args['context']                                 = $context;
1824
+		$this->_template_args['edit_message_template_form_url']          = $edit_message_template_form_url;
1825
+		$this->_template_args['learn_more_about_message_templates_link'] =
1826
+			$this->_learn_more_about_message_templates_link();
1827
+
1828
+
1829
+		$this->_template_args['before_admin_page_content'] = '<div class="ee-msg-admin-header">';
1830
+		$this->_template_args['before_admin_page_content'] .= $this->add_active_context_element(
1831
+			$message_template_group,
1832
+			$context,
1833
+			$context_label
1834
+		);
1835
+		$this->_template_args['before_admin_page_content'] .= $this->add_context_switcher();
1836
+		$this->_template_args['before_admin_page_content'] .= '</div>';
1837
+		$this->_template_args['before_admin_page_content'] .= $this->_add_form_element_before();
1838
+		$this->_template_args['after_admin_page_content']  = $this->_add_form_element_after();
1839
+
1840
+		$this->_template_path = $this->_template_args['GRP_ID']
1841
+			? EE_MSG_TEMPLATE_PATH . 'ee_msg_details_main_edit_meta_box.template.php'
1842
+			: EE_MSG_TEMPLATE_PATH . 'ee_msg_details_main_add_meta_box.template.php';
1843
+
1844
+		// send along EE_Message_Template_Group object for further template use.
1845
+		$this->_template_args['MTP'] = $message_template_group;
1846
+
1847
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
1848
+			$this->_template_path,
1849
+			$this->_template_args,
1850
+			true
1851
+		);
1852
+
1853
+
1854
+		// finally, let's set the admin_page title
1855
+		$this->_admin_page_title = sprintf(esc_html__('Editing %s', 'event_espresso'), $title);
1856
+
1857
+
1858
+		// we need to take care of setting the shortcodes property for use elsewhere.
1859
+		$this->_set_shortcodes();
1860
+
1861
+
1862
+		// final template wrapper
1863
+		$this->display_admin_page_with_sidebar();
1864
+	}
1865
+
1866
+
1867
+	public function filter_tinymce_init($mceInit, $editor_id)
1868
+	{
1869
+		return $mceInit;
1870
+	}
1871
+
1872
+
1873
+	public function add_context_switcher()
1874
+	{
1875
+		return $this->_context_switcher;
1876
+	}
1877
+
1878
+
1879
+	/**
1880
+	 * Adds the activation/deactivation toggle for the message template context.
1881
+	 *
1882
+	 * @param EE_Message_Template_Group $message_template_group
1883
+	 * @param string                    $context
1884
+	 * @param string                    $context_label
1885
+	 * @return string
1886
+	 * @throws DomainException
1887
+	 * @throws EE_Error
1888
+	 * @throws InvalidIdentifierException
1889
+	 * @throws ReflectionException
1890
+	 */
1891
+	protected function add_active_context_element(
1892
+		EE_Message_Template_Group $message_template_group,
1893
+		$context,
1894
+		$context_label
1895
+	) {
1896
+		$template_args = [
1897
+			'context'                   => $context,
1898
+			'nonce'                     => wp_create_nonce('activate_' . $context . '_toggle_nonce'),
1899
+			'is_active'                 => $message_template_group->is_context_active($context),
1900
+			'on_off_action'             => $message_template_group->is_context_active($context)
1901
+				? 'context-off'
1902
+				: 'context-on',
1903
+			'context_label'             => str_replace(['(', ')'], '', $context_label),
1904
+			'message_template_group_id' => $message_template_group->ID(),
1905
+		];
1906
+		return EEH_Template::display_template(
1907
+			EE_MSG_TEMPLATE_PATH . 'ee_msg_editor_active_context_element.template.php',
1908
+			$template_args,
1909
+			true
1910
+		);
1911
+	}
1912
+
1913
+
1914
+	/**
1915
+	 * Ajax callback for `toggle_context_template` ajax action.
1916
+	 * Handles toggling the message context on or off.
1917
+	 *
1918
+	 * @throws EE_Error
1919
+	 * @throws InvalidArgumentException
1920
+	 * @throws InvalidDataTypeException
1921
+	 * @throws InvalidIdentifierException
1922
+	 * @throws InvalidInterfaceException
1923
+	 */
1924
+	public function toggle_context_template()
1925
+	{
1926
+		$success = true;
1927
+		// check for required data
1928
+		if (
1929
+			! (
1930
+				$this->request->requestParamIsSet('message_template_group_id')
1931
+				&& $this->request->requestParamIsSet('context')
1932
+				&& $this->request->requestParamIsSet('status')
1933
+			)
1934
+		) {
1935
+			EE_Error::add_error(
1936
+				esc_html__('Required data for doing this action is not available.', 'event_espresso'),
1937
+				__FILE__,
1938
+				__FUNCTION__,
1939
+				__LINE__
1940
+			);
1941
+			$success = false;
1942
+		}
1943
+
1944
+		$nonce   = $this->request->getRequestParam('toggle_context_nonce', '');
1945
+		$context = $this->request->getRequestParam('context', '');
1946
+		$status  = $this->request->getRequestParam('status', '');
1947
+
1948
+		$this->_verify_nonce($nonce, "activate_{$context}_toggle_nonce");
1949
+
1950
+		if ($status !== 'off' && $status !== 'on') {
1951
+			EE_Error::add_error(
1952
+				sprintf(
1953
+					esc_html__('The given status (%s) is not valid. Must be "off" or "on"', 'event_espresso'),
1954
+					$status
1955
+				),
1956
+				__FILE__,
1957
+				__FUNCTION__,
1958
+				__LINE__
1959
+			);
1960
+			$success = false;
1961
+		}
1962
+		$message_template_group_id = $this->request->getRequestParam('message_template_group_id', 0, 'int');
1963
+		$message_template_group    = $this->getMtgModel()->get_one_by_ID($message_template_group_id);
1964
+		if (! $message_template_group instanceof EE_Message_Template_Group) {
1965
+			EE_Error::add_error(
1966
+				sprintf(
1967
+					esc_html__(
1968
+						'Unable to change the active state because the given id "%1$d" does not match a valid "%2$s"',
1969
+						'event_espresso'
1970
+					),
1971
+					$message_template_group_id,
1972
+					'EE_Message_Template_Group'
1973
+				),
1974
+				__FILE__,
1975
+				__FUNCTION__,
1976
+				__LINE__
1977
+			);
1978
+			$success = false;
1979
+		}
1980
+		if ($success) {
1981
+			$success = $status === 'off'
1982
+				? $message_template_group->deactivate_context($context)
1983
+				: $message_template_group->activate_context($context);
1984
+		}
1985
+		$this->_template_args['success'] = $success;
1986
+		$this->_return_json();
1987
+	}
1988
+
1989
+
1990
+	public function _add_form_element_before()
1991
+	{
1992
+		return '<form method="post" action="'
1993
+			   . $this->_template_args['edit_message_template_form_url']
1994
+			   . '" id="ee-msg-edit-frm">';
1995
+	}
1996
+
1997
+
1998
+	public function _add_form_element_after()
1999
+	{
2000
+		return '</form>';
2001
+	}
2002
+
2003
+
2004
+	/**
2005
+	 * This executes switching the template pack for a message template.
2006
+	 *
2007
+	 * @throws EE_Error
2008
+	 * @throws InvalidDataTypeException
2009
+	 * @throws InvalidInterfaceException
2010
+	 * @throws InvalidArgumentException
2011
+	 * @throws ReflectionException
2012
+	 * @since 4.5.0
2013
+	 */
2014
+	public function switch_template_pack()
2015
+	{
2016
+
2017
+		$GRP_ID        = $this->request->getRequestParam('GRP_ID', 0, 'int');
2018
+		$template_pack = $this->request->getRequestParam('template_pack', '');
2019
+
2020
+		// verify we have needed values.
2021
+		if (empty($GRP_ID) || empty($template_pack)) {
2022
+			$this->_template_args['error'] = true;
2023
+			EE_Error::add_error(
2024
+				esc_html__('The required date for switching templates is not available.', 'event_espresso'),
2025
+				__FILE__,
2026
+				__FUNCTION__,
2027
+				__LINE__
2028
+			);
2029
+		} else {
2030
+			// get template, set the new template_pack and then reset to default
2031
+			/** @var EE_Message_Template_Group $message_template_group */
2032
+			$message_template_group = $this->getMtgModel()->get_one_by_ID($GRP_ID);
2033
+
2034
+			$message_template_group->set_template_pack_name($template_pack);
2035
+			$this->request->setRequestParam('msgr', $message_template_group->messenger());
2036
+			$this->request->setRequestParam('mt', $message_template_group->message_type());
2037
+
2038
+			$query_args = $this->_reset_to_default_template();
2039
+
2040
+			if (empty($query_args['id'])) {
2041
+				EE_Error::add_error(
2042
+					esc_html__(
2043
+						'Something went wrong with switching the template pack. Please try again or contact EE support',
2044
+						'event_espresso'
2045
+					),
2046
+					__FILE__,
2047
+					__FUNCTION__,
2048
+					__LINE__
2049
+				);
2050
+				$this->_template_args['error'] = true;
2051
+			} else {
2052
+				$template_label       = $message_template_group->get_template_pack()->label;
2053
+				$template_pack_labels = $message_template_group->messenger_obj()->get_supports_labels();
2054
+				EE_Error::add_success(
2055
+					sprintf(
2056
+						esc_html__(
2057
+							'This message template has been successfully switched to use the %1$s %2$s.  Please wait while the page reloads with your new template.',
2058
+							'event_espresso'
2059
+						),
2060
+						$template_label,
2061
+						$template_pack_labels->template_pack
2062
+					)
2063
+				);
2064
+				// generate the redirect url for js.
2065
+				$url = self::add_query_args_and_nonce($query_args, $this->_admin_base_url);
2066
+
2067
+				$this->_template_args['data']['redirect_url'] = $url;
2068
+				$this->_template_args['success']              = true;
2069
+			}
2070
+
2071
+			$this->_return_json();
2072
+		}
2073
+	}
2074
+
2075
+
2076
+	/**
2077
+	 * This handles resetting the template for the given messenger/message_type so that users can start from scratch if
2078
+	 * they want.
2079
+	 *
2080
+	 * @access protected
2081
+	 * @return array|void
2082
+	 * @throws EE_Error
2083
+	 * @throws InvalidArgumentException
2084
+	 * @throws InvalidDataTypeException
2085
+	 * @throws InvalidInterfaceException
2086
+	 * @throws ReflectionException
2087
+	 */
2088
+	protected function _reset_to_default_template()
2089
+	{
2090
+		$templates    = [];
2091
+		$GRP_ID       = $this->request->getRequestParam('GRP_ID', 0, 'int');
2092
+		$messenger    = $this->request->getRequestParam('msgr');
2093
+		$message_type = $this->request->getRequestParam('mt');
2094
+		// we need to make sure we've got the info we need.
2095
+		if (! ($GRP_ID && $messenger && $message_type)) {
2096
+			EE_Error::add_error(
2097
+				esc_html__(
2098
+					'In order to reset the template to its default we require the messenger, message type, and message template GRP_ID to know what is being reset.  At least one of these is missing.',
2099
+					'event_espresso'
2100
+				),
2101
+				__FILE__,
2102
+				__FUNCTION__,
2103
+				__LINE__
2104
+			);
2105
+		}
2106
+
2107
+		// all templates will be reset to whatever the defaults are
2108
+		// for the global template matching the messenger and message type.
2109
+		$success = ! empty($GRP_ID);
2110
+
2111
+		if ($success) {
2112
+			// let's first determine if the incoming template is a global template,
2113
+			// if it isn't then we need to get the global template matching messenger and message type.
2114
+			// $MTPG = $this->getMtgModel()->get_one_by_ID( $GRP_ID );
2115
+
2116
+
2117
+			// note this is ONLY deleting the template fields (Message Template rows) NOT the message template group.
2118
+			$success = $this->_delete_mtp_permanently($GRP_ID, false);
2119
+
2120
+			if ($success) {
2121
+				// if successfully deleted, lets generate the new ones.
2122
+				// Note. We set GLOBAL to true, because resets on ANY template
2123
+				// will use the related global template defaults for regeneration.
2124
+				// This means that if a custom template is reset it resets to whatever the related global template is.
2125
+				// HOWEVER, we DO keep the template pack and template variation set
2126
+				// for the current custom template when resetting.
2127
+				$templates = $this->_generate_new_templates($messenger, $message_type, $GRP_ID, true);
2128
+			}
2129
+		}
2130
+
2131
+		// any error messages?
2132
+		if (! $success) {
2133
+			EE_Error::add_error(
2134
+				esc_html__(
2135
+					'Something went wrong with deleting existing templates. Unable to reset to default',
2136
+					'event_espresso'
2137
+				),
2138
+				__FILE__,
2139
+				__FUNCTION__,
2140
+				__LINE__
2141
+			);
2142
+		}
2143
+
2144
+		// all good, let's add a success message!
2145
+		if ($success && ! empty($templates)) {
2146
+			// the info for the template we generated is the first element in the returned array
2147
+			EE_Error::overwrite_success();
2148
+			EE_Error::add_success(esc_html__('Templates have been reset to defaults.', 'event_espresso'));
2149
+		}
2150
+
2151
+
2152
+		$query_args = [
2153
+			'id'      => isset($templates['GRP_ID']) ? $templates['GRP_ID'] : null,
2154
+			'context' => isset($templates['MTP_context']) ? $templates['MTP_context'] : null,
2155
+			'action'  => isset($templates['GRP_ID']) ? 'edit_message_template' : 'global_mtps',
2156
+		];
2157
+
2158
+		// if called via ajax then we return query args otherwise redirect
2159
+		if ($this->request->isAjax()) {
2160
+			return $query_args;
2161
+		}
2162
+		$this->_redirect_after_action(false, '', '', $query_args, true);
2163
+	}
2164
+
2165
+
2166
+	/**
2167
+	 * Retrieve and set the message preview for display.
2168
+	 *
2169
+	 * @param bool $send if TRUE then we are doing an actual TEST send with the results of the preview.
2170
+	 * @return string
2171
+	 * @throws ReflectionException
2172
+	 * @throws EE_Error
2173
+	 * @throws InvalidArgumentException
2174
+	 * @throws InvalidDataTypeException
2175
+	 * @throws InvalidInterfaceException
2176
+	 */
2177
+	public function _preview_message($send = false)
2178
+	{
2179
+		// first make sure we've got the necessary parameters
2180
+		$GRP_ID = $this->request->getRequestParam('GRP_ID', 0, 'int');
2181
+		if (! ($GRP_ID && $this->_active_messenger_name && $this->_active_message_type_name)) {
2182
+			EE_Error::add_error(
2183
+				esc_html__('Missing necessary parameters for displaying preview', 'event_espresso'),
2184
+				__FILE__,
2185
+				__FUNCTION__,
2186
+				__LINE__
2187
+			);
2188
+		}
2189
+
2190
+		$context = $this->request->getRequestParam('context');
2191
+		// get the preview!
2192
+		$preview = EED_Messages::preview_message(
2193
+			$this->_active_message_type_name,
2194
+			$context,
2195
+			$this->_active_messenger_name,
2196
+			$send
2197
+		);
2198
+
2199
+		if ($send) {
2200
+			return $preview;
2201
+		}
2202
+
2203
+		// if we have an evt_id set on the request, use it.
2204
+		$EVT_ID = $this->request->getRequestParam('evt_id', 0, 'int');
2205
+
2206
+		// let's add a button to go back to the edit view
2207
+		$query_args             = [
2208
+			'id'      => $GRP_ID,
2209
+			'evt_id'  => $EVT_ID,
2210
+			'context' => $context,
2211
+			'action'  => 'edit_message_template',
2212
+		];
2213
+		$go_back_url            = parent::add_query_args_and_nonce($query_args, $this->_admin_base_url);
2214
+		$preview_button         = '<a href="'
2215
+								  . $go_back_url
2216
+								  . '" class="button--secondary messages-preview-go-back-button">'
2217
+								  . esc_html__('Go Back to Edit', 'event_espresso')
2218
+								  . '</a>';
2219
+		$message_types          = $this->get_installed_message_types();
2220
+		$active_messenger       = $this->_message_resource_manager->get_active_messenger($this->_active_messenger_name);
2221
+		$active_messenger_label = $active_messenger instanceof EE_messenger
2222
+			? ucwords($active_messenger->label['singular'])
2223
+			: esc_html__('Unknown Messenger', 'event_espresso');
2224
+		// let's provide a helpful title for context
2225
+		$preview_title = sprintf(
2226
+			esc_html__('Viewing Preview for %s %s Message Template', 'event_espresso'),
2227
+			$active_messenger_label,
2228
+			ucwords($message_types[ $this->_active_message_type_name ]->label['singular'])
2229
+		);
2230
+		if (empty($preview)) {
2231
+			$this->noEventsErrorMessage();
2232
+		}
2233
+		// setup display of preview.
2234
+		$this->_admin_page_title                    = $preview_title;
2235
+		$this->_template_args['admin_page_title']   = $preview_title;
2236
+		$this->_template_args['admin_page_content'] = $preview_button . '<br />' . $preview;
2237
+		$this->_template_args['data']['force_json'] = true;
2238
+
2239
+		return '';
2240
+	}
2241
+
2242
+
2243
+	/**
2244
+	 * Used to set an error if there are no events available for generating a preview/test send.
2245
+	 *
2246
+	 * @param bool $test_send Whether the error should be generated for the context of a test send.
2247
+	 */
2248
+	protected function noEventsErrorMessage($test_send = false)
2249
+	{
2250
+		$events_url = parent::add_query_args_and_nonce(
2251
+			[
2252
+				'action' => 'default',
2253
+				'page'   => 'espresso_events',
2254
+			],
2255
+			admin_url('admin.php')
2256
+		);
2257
+		$message    = $test_send
2258
+			? esc_html__(
2259
+				'A test message could not be sent for this message template because there are no events created yet. The preview system uses actual events for generating the test message. %1$sGo see your events%2$s!',
2260
+				'event_espresso'
2261
+			)
2262
+			: esc_html__(
2263
+				'There is no preview for this message template available because there are no events created yet. The preview system uses actual events for generating the preview. %1$sGo see your events%2$s!',
2264
+				'event_espresso'
2265
+			);
2266
+
2267
+		EE_Error::add_attention(
2268
+			sprintf(
2269
+				$message,
2270
+				"<a href='{$events_url}'>",
2271
+				'</a>'
2272
+			)
2273
+		);
2274
+	}
2275
+
2276
+
2277
+	/**
2278
+	 * The initial _preview_message is on a no headers route.  It will optionally call this if necessary otherwise it
2279
+	 * gets called automatically.
2280
+	 *
2281
+	 * @return void
2282
+	 * @throws EE_Error
2283
+	 * @since 4.5.0
2284
+	 *
2285
+	 */
2286
+	protected function _display_preview_message()
2287
+	{
2288
+		$this->display_admin_page_with_no_sidebar();
2289
+	}
2290
+
2291
+
2292
+	/**
2293
+	 * registers metaboxes that should show up on the "edit_message_template" page
2294
+	 *
2295
+	 * @access protected
2296
+	 * @return void
2297
+	 */
2298
+	protected function _register_edit_meta_boxes()
2299
+	{
2300
+		$this->addMetaBox(
2301
+			'mtp_valid_shortcodes',
2302
+			esc_html__('Valid Shortcodes', 'event_espresso'),
2303
+			[$this, 'shortcode_meta_box'],
2304
+			$this->_current_screen->id,
2305
+			'side'
2306
+		);
2307
+		$this->addMetaBox(
2308
+			'mtp_extra_actions',
2309
+			esc_html__('Extra Actions', 'event_espresso'),
2310
+			[$this, 'extra_actions_meta_box'],
2311
+			$this->_current_screen->id,
2312
+			'side',
2313
+			'high'
2314
+		);
2315
+		$this->addMetaBox(
2316
+			'mtp_templates',
2317
+			esc_html__('Template Styles', 'event_espresso'),
2318
+			[$this, 'template_pack_meta_box'],
2319
+			$this->_current_screen->id,
2320
+			'side',
2321
+			'high'
2322
+		);
2323
+	}
2324
+
2325
+
2326
+	/**
2327
+	 * metabox content for all template pack and variation selection.
2328
+	 *
2329
+	 * @return void
2330
+	 * @throws DomainException
2331
+	 * @throws EE_Error
2332
+	 * @throws InvalidArgumentException
2333
+	 * @throws ReflectionException
2334
+	 * @throws InvalidDataTypeException
2335
+	 * @throws InvalidInterfaceException
2336
+	 * @since 4.5.0
2337
+	 */
2338
+	public function template_pack_meta_box()
2339
+	{
2340
+		$this->_set_message_template_group();
2341
+
2342
+		$tp_collection = EEH_MSG_Template::get_template_pack_collection();
2343
+
2344
+		$tp_select_values = [];
2345
+
2346
+		foreach ($tp_collection as $tp) {
2347
+			// only include template packs that support this messenger and message type!
2348
+			$supports = $tp->get_supports();
2349
+			if (
2350
+				! isset($supports[ $this->_message_template_group->messenger() ])
2351
+				|| ! in_array(
2352
+					$this->_message_template_group->message_type(),
2353
+					$supports[ $this->_message_template_group->messenger() ],
2354
+					true
2355
+				)
2356
+			) {
2357
+				// not supported
2358
+				continue;
2359
+			}
2360
+
2361
+			$tp_select_values[] = [
2362
+				'text' => $tp->label,
2363
+				'id'   => $tp->dbref,
2364
+			];
2365
+		}
2366
+
2367
+		// if empty $tp_select_values then we make sure default is set because EVERY message type should be supported by
2368
+		// the default template pack.  This still allows for the odd template pack to override.
2369
+		if (empty($tp_select_values)) {
2370
+			$tp_select_values[] = [
2371
+				'text' => esc_html__('Default', 'event_espresso'),
2372
+				'id'   => 'default',
2373
+			];
2374
+		}
2375
+
2376
+		// setup variation select values for the currently selected template.
2377
+		$variations               = $this->_message_template_group->get_template_pack()->get_variations(
2378
+			$this->_message_template_group->messenger(),
2379
+			$this->_message_template_group->message_type()
2380
+		);
2381
+		$variations_select_values = [];
2382
+		foreach ($variations as $variation => $label) {
2383
+			$variations_select_values[] = [
2384
+				'text' => $label,
2385
+				'id'   => $variation,
2386
+			];
2387
+		}
2388
+
2389
+		$template_pack_labels = $this->_message_template_group->messenger_obj()->get_supports_labels();
2390
+
2391
+		$template_args['template_packs_selector']        = EEH_Form_Fields::select_input(
2392
+			'MTP_template_pack',
2393
+			$tp_select_values,
2394
+			$this->_message_template_group->get_template_pack_name()
2395
+		);
2396
+		$template_args['variations_selector']            = EEH_Form_Fields::select_input(
2397
+			'MTP_template_variation',
2398
+			$variations_select_values,
2399
+			$this->_message_template_group->get_template_pack_variation()
2400
+		);
2401
+		$template_args['template_pack_label']            = $template_pack_labels->template_pack;
2402
+		$template_args['template_variation_label']       = $template_pack_labels->template_variation;
2403
+		$template_args['template_pack_description']      = $template_pack_labels->template_pack_description;
2404
+		$template_args['template_variation_description'] = $template_pack_labels->template_variation_description;
2405
+
2406
+		$template = EE_MSG_TEMPLATE_PATH . 'template_pack_and_variations_metabox.template.php';
2407
+
2408
+		EEH_Template::display_template($template, $template_args);
2409
+	}
2410
+
2411
+
2412
+	/**
2413
+	 * This meta box holds any extra actions related to Message Templates
2414
+	 * For now, this includes Resetting templates to defaults and sending a test email.
2415
+	 *
2416
+	 * @access  public
2417
+	 * @return void
2418
+	 * @throws EE_Error
2419
+	 */
2420
+	public function extra_actions_meta_box()
2421
+	{
2422
+		$template_form_fields = [];
2423
+
2424
+		$extra_args = [
2425
+			'msgr'   => $this->_message_template_group->messenger(),
2426
+			'mt'     => $this->_message_template_group->message_type(),
2427
+			'GRP_ID' => $this->_message_template_group->GRP_ID(),
2428
+		];
2429
+		// first we need to see if there are any fields
2430
+		$fields = $this->_message_template_group->messenger_obj()->get_test_settings_fields();
2431
+
2432
+		if (! empty($fields)) {
2433
+			// yup there be fields
2434
+			foreach ($fields as $field => $config) {
2435
+				$field_id = $this->_message_template_group->messenger() . '_' . $field;
2436
+				$existing = $this->_message_template_group->messenger_obj()->get_existing_test_settings();
2437
+				$default  = isset($config['default']) ? $config['default'] : '';
2438
+				$default  = isset($config['value']) ? $config['value'] : $default;
2439
+
2440
+				// if type is hidden and the value is empty
2441
+				// something may have gone wrong so let's correct with the defaults
2442
+				$fix                = $config['input'] === 'hidden'
2443
+									  && isset($existing[ $field ])
2444
+									  && empty($existing[ $field ])
2445
+					? $default
2446
+					: '';
2447
+				$existing[ $field ] = isset($existing[ $field ]) && empty($fix)
2448
+					? $existing[ $field ]
2449
+					: $fix;
2450
+
2451
+				$template_form_fields[ $field_id ] = [
2452
+					'name'       => 'test_settings_fld[' . $field . ']',
2453
+					'label'      => $config['label'],
2454
+					'input'      => $config['input'],
2455
+					'type'       => $config['type'],
2456
+					'required'   => $config['required'],
2457
+					'validation' => $config['validation'],
2458
+					'value'      => isset($existing[ $field ]) ? $existing[ $field ] : $default,
2459
+					'css_class'  => $config['css_class'],
2460
+					'options'    => isset($config['options']) ? $config['options'] : [],
2461
+					'default'    => $default,
2462
+					'format'     => $config['format'],
2463
+				];
2464
+			}
2465
+		}
2466
+
2467
+		$test_settings_html = ! empty($template_form_fields)
2468
+			? $this->_generate_admin_form_fields($template_form_fields, 'string', 'ee_tst_settings_flds')
2469
+			: '';
2470
+
2471
+		// print out $test_settings_fields
2472
+		if (! empty($test_settings_html)) {
2473
+			$test_settings_html .= '<input type="submit" class="button--primary mtp-test-button alignright" ';
2474
+			$test_settings_html .= 'name="test_button" value="';
2475
+			$test_settings_html .= esc_html__('Test Send', 'event_espresso');
2476
+			$test_settings_html .= '" /><div style="clear:both"></div>';
2477
+		}
2478
+
2479
+		// and button
2480
+		$test_settings_html .= '<div class="publishing-action alignright resetbutton">';
2481
+		$test_settings_html .= '<p>';
2482
+		$test_settings_html .= esc_html__('Need to reset this message type and start over?', 'event_espresso');
2483
+		$test_settings_html .= '</p>';
2484
+		$test_settings_html .= $this->get_action_link_or_button(
2485
+			'reset_to_default',
2486
+			'reset',
2487
+			$extra_args,
2488
+			'button--primary reset-default-button'
2489
+		);
2490
+		$test_settings_html .= '</div><div style="clear:both"></div>';
2491
+		echo wp_kses($test_settings_html, AllowedTags::getWithFormTags());
2492
+	}
2493
+
2494
+
2495
+	/**
2496
+	 * This returns the shortcode selector skeleton for a given context and field.
2497
+	 *
2498
+	 * @param string $field           The name of the field retrieving shortcodes for.
2499
+	 * @param string $linked_input_id The css id of the input that the shortcodes get added to.
2500
+	 * @return string
2501
+	 * @throws DomainException
2502
+	 * @throws EE_Error
2503
+	 * @throws InvalidArgumentException
2504
+	 * @throws ReflectionException
2505
+	 * @throws InvalidDataTypeException
2506
+	 * @throws InvalidInterfaceException
2507
+	 * @since 4.9.rc.000
2508
+	 */
2509
+	protected function _get_shortcode_selector($field, $linked_input_id)
2510
+	{
2511
+		$template_args = [
2512
+			'shortcodes'      => $this->_get_shortcodes([$field]),
2513
+			'fieldname'       => $field,
2514
+			'linked_input_id' => $linked_input_id,
2515
+		];
2516
+
2517
+		return EEH_Template::display_template(
2518
+			EE_MSG_TEMPLATE_PATH . 'shortcode_selector_skeleton.template.php',
2519
+			$template_args,
2520
+			true
2521
+		);
2522
+	}
2523
+
2524
+
2525
+	/**
2526
+	 * This just takes care of returning the meta box content for shortcodes (only used on the edit message template
2527
+	 * page)
2528
+	 *
2529
+	 * @access public
2530
+	 * @return void
2531
+	 * @throws EE_Error
2532
+	 * @throws InvalidArgumentException
2533
+	 * @throws ReflectionException
2534
+	 * @throws InvalidDataTypeException
2535
+	 * @throws InvalidInterfaceException
2536
+	 */
2537
+	public function shortcode_meta_box()
2538
+	{
2539
+		$shortcodes = $this->_get_shortcodes([], false);
2540
+		// just make sure the shortcodes property is set
2541
+		// $messenger = $this->_message_template_group->messenger_obj();
2542
+		// now let's set the content depending on the status of the shortcodes array
2543
+		if (empty($shortcodes)) {
2544
+			echo '<p>' . esc_html__('There are no valid shortcodes available', 'event_espresso') . '</p>';
2545
+			return;
2546
+		}
2547
+		?>
2548 2548
         <div style="float:right; margin-top:10px">
2549 2549
             <?php echo wp_kses($this->_get_help_tab_link('message_template_shortcodes'), AllowedTags::getAllowedTags());
2550
-            ?>
2550
+			?>
2551 2551
         </div>
2552 2552
         <p class="small-text">
2553 2553
             <?php printf(
2554
-                esc_html__(
2555
-                    'You can view the shortcodes usable in your template by clicking the %s icon next to each field.',
2556
-                    'event_espresso'
2557
-                ),
2558
-                '<span class="dashicons dashicons-shortcode"></span>'
2559
-            ); ?>
2554
+				esc_html__(
2555
+					'You can view the shortcodes usable in your template by clicking the %s icon next to each field.',
2556
+					'event_espresso'
2557
+				),
2558
+				'<span class="dashicons dashicons-shortcode"></span>'
2559
+			); ?>
2560 2560
         </p>
2561 2561
         <?php
2562
-    }
2563
-
2564
-
2565
-    /**
2566
-     * used to set the $_shortcodes property for when its needed elsewhere.
2567
-     *
2568
-     * @access protected
2569
-     * @return void
2570
-     * @throws EE_Error
2571
-     * @throws InvalidArgumentException
2572
-     * @throws ReflectionException
2573
-     * @throws InvalidDataTypeException
2574
-     * @throws InvalidInterfaceException
2575
-     */
2576
-    protected function _set_shortcodes()
2577
-    {
2578
-
2579
-        // no need to run this if the property is already set
2580
-        if (! empty($this->_shortcodes)) {
2581
-            return;
2582
-        }
2583
-
2584
-        $this->_shortcodes = $this->_get_shortcodes();
2585
-    }
2586
-
2587
-
2588
-    /**
2589
-     * gets all shortcodes for a given template group. (typically used by _set_shortcodes to set the $_shortcodes
2590
-     * property)
2591
-     *
2592
-     * @access  protected
2593
-     * @param array   $fields  include an array of specific field names that you want to be used to get the shortcodes
2594
-     *                         for. Defaults to all (for the given context)
2595
-     * @param boolean $merged  Whether to merge all the shortcodes into one list of unique shortcodes
2596
-     * @return array Shortcodes indexed by fieldname and the an array of shortcode/label pairs OR if merged is
2597
-     *                         true just an array of shortcode/label pairs.
2598
-     * @throws EE_Error
2599
-     * @throws InvalidArgumentException
2600
-     * @throws ReflectionException
2601
-     * @throws InvalidDataTypeException
2602
-     * @throws InvalidInterfaceException
2603
-     */
2604
-    protected function _get_shortcodes($fields = [], $merged = true)
2605
-    {
2606
-        $this->_set_message_template_group();
2607
-
2608
-        // we need the messenger and message template to retrieve the valid shortcodes array.
2609
-        $GRP_ID = $this->request->getRequestParam('id', 0, 'int');
2610
-        if (empty($GRP_ID)) {
2611
-            return [];
2612
-        }
2613
-        $context = $this->request->getRequestParam(
2614
-            'messenger',
2615
-            key($this->_message_template_group->contexts_config())
2616
-        );
2617
-        return $this->_message_template_group->get_shortcodes($context, $fields, $merged);
2618
-    }
2619
-
2620
-
2621
-    /**
2622
-     * This sets the _message_template property (containing the called message_template object)
2623
-     *
2624
-     * @access protected
2625
-     * @return void
2626
-     * @throws EE_Error
2627
-     * @throws InvalidArgumentException
2628
-     * @throws ReflectionException
2629
-     * @throws InvalidDataTypeException
2630
-     * @throws InvalidInterfaceException
2631
-     */
2632
-    protected function _set_message_template_group()
2633
-    {
2634
-        // get out if this is already set.
2635
-        if (! empty($this->_message_template_group)) {
2636
-            return;
2637
-        }
2638
-
2639
-        $GRP_ID = $this->request->getRequestParam('GRP_ID', 0, 'int');
2640
-        $GRP_ID = $this->request->getRequestParam('id', $GRP_ID, 'int');
2641
-
2642
-        // let's get the message templates
2643
-        $this->_message_template_group = ! empty($GRP_ID)
2644
-            ? $this->getMtgModel()->get_one_by_ID($GRP_ID)
2645
-            : $this->getMtgModel()->create_default_object();
2646
-
2647
-        $this->_template_pack = $this->_message_template_group->get_template_pack();
2648
-        $this->_variation     = $this->_message_template_group->get_template_pack_variation();
2649
-    }
2650
-
2651
-
2652
-    /**
2653
-     * sets up a context switcher for edit forms
2654
-     *
2655
-     * @access  protected
2656
-     * @param EE_Message_Template_Group $template_group_object the template group object being displayed on the form
2657
-     * @param array                     $args                  various things the context switcher needs.
2658
-     * @throws EE_Error
2659
-     */
2660
-    protected function _set_context_switcher(EE_Message_Template_Group $template_group_object, $args)
2661
-    {
2662
-        $context_details = $template_group_object->contexts_config();
2663
-        $context_label   = $template_group_object->context_label();
2664
-        ob_start();
2665
-        ?>
2562
+	}
2563
+
2564
+
2565
+	/**
2566
+	 * used to set the $_shortcodes property for when its needed elsewhere.
2567
+	 *
2568
+	 * @access protected
2569
+	 * @return void
2570
+	 * @throws EE_Error
2571
+	 * @throws InvalidArgumentException
2572
+	 * @throws ReflectionException
2573
+	 * @throws InvalidDataTypeException
2574
+	 * @throws InvalidInterfaceException
2575
+	 */
2576
+	protected function _set_shortcodes()
2577
+	{
2578
+
2579
+		// no need to run this if the property is already set
2580
+		if (! empty($this->_shortcodes)) {
2581
+			return;
2582
+		}
2583
+
2584
+		$this->_shortcodes = $this->_get_shortcodes();
2585
+	}
2586
+
2587
+
2588
+	/**
2589
+	 * gets all shortcodes for a given template group. (typically used by _set_shortcodes to set the $_shortcodes
2590
+	 * property)
2591
+	 *
2592
+	 * @access  protected
2593
+	 * @param array   $fields  include an array of specific field names that you want to be used to get the shortcodes
2594
+	 *                         for. Defaults to all (for the given context)
2595
+	 * @param boolean $merged  Whether to merge all the shortcodes into one list of unique shortcodes
2596
+	 * @return array Shortcodes indexed by fieldname and the an array of shortcode/label pairs OR if merged is
2597
+	 *                         true just an array of shortcode/label pairs.
2598
+	 * @throws EE_Error
2599
+	 * @throws InvalidArgumentException
2600
+	 * @throws ReflectionException
2601
+	 * @throws InvalidDataTypeException
2602
+	 * @throws InvalidInterfaceException
2603
+	 */
2604
+	protected function _get_shortcodes($fields = [], $merged = true)
2605
+	{
2606
+		$this->_set_message_template_group();
2607
+
2608
+		// we need the messenger and message template to retrieve the valid shortcodes array.
2609
+		$GRP_ID = $this->request->getRequestParam('id', 0, 'int');
2610
+		if (empty($GRP_ID)) {
2611
+			return [];
2612
+		}
2613
+		$context = $this->request->getRequestParam(
2614
+			'messenger',
2615
+			key($this->_message_template_group->contexts_config())
2616
+		);
2617
+		return $this->_message_template_group->get_shortcodes($context, $fields, $merged);
2618
+	}
2619
+
2620
+
2621
+	/**
2622
+	 * This sets the _message_template property (containing the called message_template object)
2623
+	 *
2624
+	 * @access protected
2625
+	 * @return void
2626
+	 * @throws EE_Error
2627
+	 * @throws InvalidArgumentException
2628
+	 * @throws ReflectionException
2629
+	 * @throws InvalidDataTypeException
2630
+	 * @throws InvalidInterfaceException
2631
+	 */
2632
+	protected function _set_message_template_group()
2633
+	{
2634
+		// get out if this is already set.
2635
+		if (! empty($this->_message_template_group)) {
2636
+			return;
2637
+		}
2638
+
2639
+		$GRP_ID = $this->request->getRequestParam('GRP_ID', 0, 'int');
2640
+		$GRP_ID = $this->request->getRequestParam('id', $GRP_ID, 'int');
2641
+
2642
+		// let's get the message templates
2643
+		$this->_message_template_group = ! empty($GRP_ID)
2644
+			? $this->getMtgModel()->get_one_by_ID($GRP_ID)
2645
+			: $this->getMtgModel()->create_default_object();
2646
+
2647
+		$this->_template_pack = $this->_message_template_group->get_template_pack();
2648
+		$this->_variation     = $this->_message_template_group->get_template_pack_variation();
2649
+	}
2650
+
2651
+
2652
+	/**
2653
+	 * sets up a context switcher for edit forms
2654
+	 *
2655
+	 * @access  protected
2656
+	 * @param EE_Message_Template_Group $template_group_object the template group object being displayed on the form
2657
+	 * @param array                     $args                  various things the context switcher needs.
2658
+	 * @throws EE_Error
2659
+	 */
2660
+	protected function _set_context_switcher(EE_Message_Template_Group $template_group_object, $args)
2661
+	{
2662
+		$context_details = $template_group_object->contexts_config();
2663
+		$context_label   = $template_group_object->context_label();
2664
+		ob_start();
2665
+		?>
2666 2666
         <div class="ee-msg-switcher-container">
2667 2667
             <form method="get" action="<?php echo esc_url_raw(EE_MSG_ADMIN_URL); ?>" id="ee-msg-context-switcher-frm">
2668 2668
                 <?php
2669
-                foreach ($args as $name => $value) {
2670
-                    if ($name === 'context' || empty($value) || $name === 'extra') {
2671
-                        continue;
2672
-                    }
2673
-                    ?>
2669
+				foreach ($args as $name => $value) {
2670
+					if ($name === 'context' || empty($value) || $name === 'extra') {
2671
+						continue;
2672
+					}
2673
+					?>
2674 2674
                     <input type="hidden"
2675 2675
                            name="<?php echo esc_attr($name); ?>"
2676 2676
                            value="<?php echo esc_attr($value); ?>"
2677 2677
                     />
2678 2678
                     <?php
2679
-                }
2680
-                // setup nonce_url
2681
-                wp_nonce_field($args['action'] . '_nonce', $args['action'] . '_nonce', false);
2682
-                $id = 'ee-' . sanitize_key($context_label['label']) . '-select';
2683
-                ?>
2679
+				}
2680
+				// setup nonce_url
2681
+				wp_nonce_field($args['action'] . '_nonce', $args['action'] . '_nonce', false);
2682
+				$id = 'ee-' . sanitize_key($context_label['label']) . '-select';
2683
+				?>
2684 2684
                 <label for='<?php echo esc_attr($id); ?>' class='screen-reader-text'>
2685 2685
                     <?php esc_html_e('message context options', 'event_espresso'); ?>
2686 2686
                 </label>
2687 2687
                 <select id="<?php echo esc_attr($id); ?>" name="context">
2688 2688
                     <?php
2689
-                    $context_templates = $template_group_object->context_templates();
2690
-                    if (is_array($context_templates)) :
2691
-                        foreach ($context_templates as $context => $template_fields) :
2692
-                            $checked = ($context === $args['context']) ? 'selected' : '';
2693
-                            ?>
2689
+					$context_templates = $template_group_object->context_templates();
2690
+					if (is_array($context_templates)) :
2691
+						foreach ($context_templates as $context => $template_fields) :
2692
+							$checked = ($context === $args['context']) ? 'selected' : '';
2693
+							?>
2694 2694
                             <option value="<?php echo esc_attr($context); ?>" <?php echo esc_attr($checked); ?>>
2695 2695
                                 <?php echo esc_html($context_details[ $context ]['label']); ?>
2696 2696
                             </option>
2697 2697
                         <?php endforeach;
2698
-                    endif; ?>
2698
+					endif; ?>
2699 2699
                 </select>
2700 2700
                 <?php $button_text = sprintf(
2701
-                    esc_html__('Switch %s', 'event_espresso'),
2702
-                    ucwords($context_label['label'])
2703
-                ); ?>
2701
+					esc_html__('Switch %s', 'event_espresso'),
2702
+					ucwords($context_label['label'])
2703
+				); ?>
2704 2704
                 <input class='button--secondary'
2705 2705
                        id="submit-msg-context-switcher-sbmt"
2706 2706
                        type="submit"
@@ -2710,1996 +2710,1996 @@  discard block
 block discarded – undo
2710 2710
             <?php echo wp_kses($args['extra'], AllowedTags::getWithFormTags()); ?>
2711 2711
         </div> <!-- end .ee-msg-switcher-container -->
2712 2712
         <?php $this->_context_switcher = ob_get_clean();
2713
-    }
2714
-
2715
-
2716
-    /**
2717
-     * @param bool $new
2718
-     * @throws EE_Error
2719
-     * @throws ReflectionException
2720
-     */
2721
-    protected function _insert_or_update_message_template($new = false)
2722
-    {
2723
-        $form_data    = $this->getMessageTemplateFormData();
2724
-        $GRP_ID       = $form_data['GRP_ID'];
2725
-        $messenger    = $form_data['MTP_messenger'];
2726
-        $message_type = $form_data['MTP_message_type'];
2727
-        $context      = $form_data['MTP_context'];
2728
-
2729
-        // if this is "new" then we need to generate the default contexts
2730
-        // for the selected messenger/message_type for user to edit.
2731
-        [$success, $query_args] = $new
2732
-            ? $this->generateNewTemplates($GRP_ID, $messenger, $message_type)
2733
-            : $this->updateExistingTemplates($GRP_ID, $messenger, $message_type, $context, $form_data);
2734
-
2735
-        $success     = $success ? 1 : 0;
2736
-        $action_desc = $new ? 'created' : 'updated';
2737
-        $item_desc   = $this->generateUpdateDescription($messenger, $message_type, $context);
2738
-        $override    = $this->performTestSendAfterUpdate($messenger, $message_type, $context);
2739
-
2740
-        $this->_redirect_after_action($success, $item_desc, $action_desc, $query_args, $override);
2741
-    }
2742
-
2743
-
2744
-    /**
2745
-     * retrieve and sanitize form data
2746
-     *
2747
-     * @return array
2748
-     * @since 4.10.29.p
2749
-     */
2750
-    protected function getMessageTemplateFormData()
2751
-    {
2752
-        return [
2753
-            'GRP_ID'           => $this->request->getRequestParam('GRP_ID', 0, 'int'),
2754
-            'MTP_context'      => strtolower($this->request->getRequestParam('MTP_context', '')),
2755
-            'MTP_messenger'    => strtolower($this->request->getRequestParam('MTP_messenger', '')),
2756
-            'MTP_message_type' => strtolower($this->request->getRequestParam('MTP_message_type', '')),
2757
-            'MTP_user_id'      => $this->request->getRequestParam('MTP_user_id', 0, 'int'),
2758
-            'MTP_is_global'    => $this->request->getRequestParam('MTP_is_global', 0, 'int'),
2759
-            'MTP_is_override'  => $this->request->getRequestParam('MTP_is_override', 0, 'int'),
2760
-            'MTP_deleted'      => $this->request->getRequestParam('MTP_deleted', 0, 'int'),
2761
-            'MTP_is_active'    => $this->request->getRequestParam('MTP_is_active', 0, 'int'),
2762
-        ];
2763
-    }
2764
-
2765
-
2766
-    /**
2767
-     * @param int    $GRP_ID
2768
-     * @param string $messenger
2769
-     * @param string $message_type
2770
-     * @return array no return on AJAX requests
2771
-     * @throws EE_Error
2772
-     * @throws ReflectionException
2773
-     * @since 4.10.29.p
2774
-     */
2775
-    private function generateNewTemplates($GRP_ID, $messenger, $message_type)
2776
-    {
2777
-        $new_templates = $this->_generate_new_templates($messenger, [$message_type], $GRP_ID);
2778
-        $success       = ! empty($new_templates);
2779
-
2780
-        // we return things differently if doing ajax
2781
-        if ($this->request->isAjax()) {
2782
-            $this->_template_args['success'] = $success;
2783
-            $this->_template_args['error']   = ! $success;
2784
-            $this->_template_args['content'] = '';
2785
-            $this->_template_args['data']    = [
2786
-                'grpID'        => $new_templates['GRP_ID'],
2787
-                'templateName' => $new_templates['template_name'],
2788
-            ];
2789
-            if ($success) {
2790
-                EE_Error::overwrite_success();
2791
-                EE_Error::add_success(
2792
-                    esc_html__(
2793
-                        'The new template has been created and automatically selected for this event.  You can edit the new template by clicking the edit button.  Note before this template is assigned to this event, the event must be saved.',
2794
-                        'event_espresso'
2795
-                    )
2796
-                );
2797
-            }
2798
-            $this->_return_json();
2799
-        }
2800
-        return [
2801
-            $success,
2802
-            // 'query_args'
2803
-            [
2804
-                'id'      => $new_templates['GRP_ID'],
2805
-                'context' => $new_templates['MTP_context'],
2806
-                'action'  => 'edit_message_template',
2807
-            ],
2808
-        ];
2809
-    }
2810
-
2811
-
2812
-    /**
2813
-     * @param int    $GRP_ID
2814
-     * @param string $messenger
2815
-     * @param string $message_type
2816
-     * @param string $context
2817
-     * @param array  $form_data
2818
-     * @return array
2819
-     * @throws EE_Error
2820
-     * @since 4.10.29.p
2821
-     */
2822
-    private function updateExistingTemplates(
2823
-        $GRP_ID,
2824
-        $messenger,
2825
-        $message_type,
2826
-        $context,
2827
-        array $form_data
2828
-    ) {
2829
-        $success         = false;
2830
-        $template_fields = $this->getTemplateFields();
2831
-        if ($template_fields) {
2832
-            // if field data is valid, then success will be true
2833
-            $success = $this->validateTemplateFields(
2834
-                $messenger,
2835
-                $message_type,
2836
-                $context,
2837
-                $template_fields
2838
-            );
2839
-            if ($success) {
2840
-                $field_data = [];
2841
-                foreach ($template_fields as $template_field => $content) {
2842
-                    // combine top-level form data with content for this field
2843
-                    $field_data = $this->getTemplateFieldFormData($content, $form_data);
2844
-                    $success    = $this->updateMessageTemplates($template_field, $field_data) ? $success : false;
2845
-                }
2846
-                // we can use the last set_column_values for the MTPG update
2847
-                // (because its the same for all of these specific MTPs)
2848
-                $success = $this->updateMessageTemplateGroup($field_data) ? $success : false;
2849
-            }
2850
-        }
2851
-
2852
-        return [
2853
-            $success,
2854
-            // 'query_args'
2855
-            [
2856
-                'id'      => $GRP_ID,
2857
-                'context' => $context,
2858
-                'action'  => 'edit_message_template',
2859
-            ],
2860
-        ];
2861
-    }
2862
-
2863
-
2864
-    /**
2865
-     * @return array
2866
-     * @since 4.10.29.p
2867
-     */
2868
-    private function getTemplateFields()
2869
-    {
2870
-        $template_fields = $this->request->getRequestParam('MTP_template_fields', null, 'html', true);
2871
-        if (empty($template_fields)) {
2872
-            EE_Error::add_error(
2873
-                esc_html__(
2874
-                    'There was a problem saving the template fields from the form because I didn\'t receive any actual template field data.',
2875
-                    'event_espresso'
2876
-                ),
2877
-                __FILE__,
2878
-                __FUNCTION__,
2879
-                __LINE__
2880
-            );
2881
-            return null;
2882
-        }
2883
-        // messages content is expected to be escaped
2884
-        return EEH_Array::addSlashesRecursively($template_fields);
2885
-    }
2886
-
2887
-
2888
-    /**
2889
-     * @param string $messenger
2890
-     * @param string $message_type
2891
-     * @param string $context
2892
-     * @param array  $template_fields
2893
-     * @return bool
2894
-     * @throws EE_Error
2895
-     * @since   4.10.29.p
2896
-     */
2897
-    private function validateTemplateFields(
2898
-        $messenger,
2899
-        $message_type,
2900
-        $context,
2901
-        array $template_fields
2902
-    ) {
2903
-        // first validate all fields!
2904
-        // this filter allows client code to add its own validation to the template fields as well.
2905
-        // returning an empty array means everything passed validation.
2906
-        // errors in validation should be represented in an array with the following shape:
2907
-        // array(
2908
-        //   'fieldname' => array(
2909
-        //          'msg' => 'error message'
2910
-        //          'value' => 'value for field producing error'
2911
-        // )
2912
-        $custom_validation = (array) apply_filters(
2913
-            'FHEE__Messages_Admin_Page___insert_or_update_message_template__validates',
2914
-            [],
2915
-            $template_fields,
2916
-            $context,
2917
-            $messenger,
2918
-            $message_type
2919
-        );
2920
-
2921
-        $system_validation = $this->getMtgModel()->validate(
2922
-            $template_fields,
2923
-            $context,
2924
-            $messenger,
2925
-            $message_type
2926
-        );
2927
-
2928
-        $system_validation = ! is_array($system_validation) && $system_validation ? [] : $system_validation;
2929
-        $validates         = array_merge($custom_validation, $system_validation);
2930
-
2931
-        // if $validate returned error messages (i.e. is_array()) then we need to process them and setup an
2932
-        // appropriate response. HMM, dang this isn't correct, $validates will ALWAYS be an array.
2933
-        //  WE need to make sure there is no actual error messages in validates.
2934
-        if (empty($validates)) {
2935
-            return true;
2936
-        }
2937
-
2938
-        // add the transient so when the form loads we know which fields to highlight
2939
-        $this->_add_transient('edit_message_template', $validates);
2940
-        // setup notices
2941
-        foreach ($validates as $error) {
2942
-            if (isset($error['msg'])) {
2943
-                EE_Error::add_error($error['msg'], __FILE__, __FUNCTION__, __LINE__);
2944
-            }
2945
-        }
2946
-        return false;
2947
-    }
2948
-
2949
-
2950
-    /**
2951
-     * @param array $field_data
2952
-     * @param array $form_data
2953
-     * @return array
2954
-     * @since   4.10.29.p
2955
-     */
2956
-    private function getTemplateFieldFormData(array $field_data, array $form_data)
2957
-    {
2958
-        return $form_data + [
2959
-                'MTP_ID'             => $field_data['MTP_ID'],
2960
-                'MTP_template_field' => $field_data['name'],
2961
-                // if they aren't allowed to use all JS, restrict them to standard allowed post tags
2962
-                'MTP_content'        => ! current_user_can('unfiltered_html')
2963
-                    ? $this->sanitizeMessageTemplateContent($field_data['content'])
2964
-                    : $field_data['content'],
2965
-            ];
2966
-    }
2967
-
2968
-
2969
-    /**
2970
-     * @param string $template_field
2971
-     * @param array  $form_data
2972
-     * @return bool
2973
-     * @throws EE_Error
2974
-     * @since 4.10.29.p
2975
-     */
2976
-    private function updateMessageTemplates($template_field, array $form_data)
2977
-    {
2978
-        $MTP_ID                  = $form_data['MTP_ID'];
2979
-        $message_template_fields = [
2980
-            'GRP_ID'             => $form_data['GRP_ID'],
2981
-            'MTP_template_field' => $form_data['MTP_template_field'],
2982
-            'MTP_context'        => $form_data['MTP_context'],
2983
-            'MTP_content'        => $form_data['MTP_content'],
2984
-        ];
2985
-
2986
-        $hasMtpID = ! empty($MTP_ID);
2987
-        // if we have a MTP_ID for this field then update it, otherwise insert.
2988
-        // this has already been through the template field validator and sanitized, so it will be
2989
-        // safe to insert this field.  Why insert?  This typically happens when we introduce a new
2990
-        // message template field in a messenger/message type and existing users don't have the
2991
-        // default setup for it.
2992
-        // @link https://events.codebasehq.com/projects/event-espresso/tickets/9465
2993
-        $updated = $hasMtpID
2994
-            ? $this->getMtpModel()->update($message_template_fields, [['MTP_ID' => $MTP_ID]])
2995
-            : $this->getMtpModel()->insert($message_template_fields);
2996
-
2997
-        $insert_failed = ! $hasMtpID && ! $updated;
2998
-        // updates will return 0 if the field was not changed (ie: no changes = nothing actually updated)
2999
-        // but we won't consider that a problem, but if it returns false, then something went BOOM!
3000
-        $update_failed = $hasMtpID && $updated === false;
3001
-
3002
-        if ($insert_failed || $update_failed) {
3003
-            EE_Error::add_error(
3004
-                sprintf(
3005
-                    esc_html__('%s field was NOT updated for some reason', 'event_espresso'),
3006
-                    $template_field
3007
-                ),
3008
-                __FILE__,
3009
-                __FUNCTION__,
3010
-                __LINE__
3011
-            );
3012
-            return false;
3013
-        }
3014
-        return true;
3015
-    }
3016
-
3017
-
3018
-    /**
3019
-     * @param array $form_data
3020
-     * @return bool
3021
-     * @throws EE_Error
3022
-     * @since 4.10.29.p
3023
-     */
3024
-    private function updateMessageTemplateGroup(array $form_data)
3025
-    {
3026
-        $GRP_ID  = $form_data['GRP_ID'];
3027
-        $updated = $this->getMtgModel()->update(
3028
-        // fields and values
3029
-            [
3030
-                'MTP_user_id'      => $form_data['MTP_user_id'],
3031
-                'MTP_messenger'    => $form_data['MTP_messenger'],
3032
-                'MTP_message_type' => $form_data['MTP_message_type'],
3033
-                'MTP_is_global'    => $form_data['MTP_is_global'],
3034
-                'MTP_is_override'  => $form_data['MTP_is_override'],
3035
-                'MTP_deleted'      => $form_data['MTP_deleted'],
3036
-                'MTP_is_active'    => $form_data['MTP_is_active'],
3037
-                'MTP_name'         => $this->request->getRequestParam('ee_msg_non_global_fields[MTP_name]', ''),
3038
-                'MTP_description'  => $this->request->getRequestParam(
3039
-                    'ee_msg_non_global_fields[MTP_description]',
3040
-                    ''
3041
-                ),
3042
-            ],
3043
-            // where
3044
-            [['GRP_ID' => $GRP_ID]]
3045
-        );
3046
-
3047
-        if ($updated === false) {
3048
-            EE_Error::add_error(
3049
-                sprintf(
3050
-                    esc_html__(
3051
-                        'The Message Template Group (%d) was NOT updated for some reason',
3052
-                        'event_espresso'
3053
-                    ),
3054
-                    $form_data['GRP_ID']
3055
-                ),
3056
-                __FILE__,
3057
-                __FUNCTION__,
3058
-                __LINE__
3059
-            );
3060
-            return false;
3061
-        }
3062
-        // k now we need to ensure the template_pack and template_variation fields are set.
3063
-        $template_pack      = $this->request->getRequestParam('MTP_template_pack', 'default');
3064
-        $template_variation = $this->request->getRequestParam('MTP_template_variation', 'default');
3065
-
3066
-        $message_template_group = $this->getMtgModel()->get_one_by_ID($GRP_ID);
3067
-        if ($message_template_group instanceof EE_Message_Template_Group) {
3068
-            $message_template_group->set_template_pack_name($template_pack);
3069
-            $message_template_group->set_template_pack_variation($template_variation);
3070
-        }
3071
-        return true;
3072
-    }
3073
-
3074
-
3075
-    /**
3076
-     * recursively runs wp_kses() on message template content in a model safe manner
3077
-     *
3078
-     * @param array|string $content
3079
-     * @return array|string
3080
-     * @since   4.10.29.p
3081
-     */
3082
-    private function sanitizeMessageTemplateContent($content)
3083
-    {
3084
-        if (is_array($content)) {
3085
-            foreach ($content as $key => $value) {
3086
-                $content[ $key ] = $this->sanitizeMessageTemplateContent($value);
3087
-            }
3088
-            return $content;
3089
-        }
3090
-        // remove slashes so wp_kses() works properly
3091
-        // wp_kses_stripslashes() only removes slashes from double-quotes,
3092
-        // so attributes using single quotes always appear invalid.
3093
-        $content = stripslashes($content);
3094
-        $content = wp_kses($content, wp_kses_allowed_html('post'));
3095
-        // But currently the models expect slashed data, so after wp_kses()
3096
-        // runs we need to re-slash the data. Sheesh.
3097
-        // See https://events.codebasehq.com/projects/event-espresso/tickets/11211#update-47321587
3098
-        return addslashes($content);
3099
-    }
3100
-
3101
-
3102
-    /**
3103
-     * @param string $messenger
3104
-     * @param string $message_type
3105
-     * @param string $context
3106
-     * @return string
3107
-     * @since 4.10.29.p
3108
-     */
3109
-    private function generateUpdateDescription($messenger, $message_type, $context)
3110
-    {
3111
-        // need the message type and messenger objects to be able to use the labels for the notices
3112
-        $messenger_object = $this->_message_resource_manager->get_messenger($messenger);
3113
-        $messenger_label  = $messenger_object instanceof EE_messenger
3114
-            ? ucwords($messenger_object->label['singular'])
3115
-            : '';
3116
-
3117
-        $message_type_object = $this->_message_resource_manager->get_message_type($message_type);
3118
-        $message_type_label  = $message_type_object instanceof EE_message_type
3119
-            ? ucwords($message_type_object->label['singular'])
3120
-            : '';
3121
-
3122
-        $context   = ucwords(str_replace('_', ' ', $context));
3123
-        $item_desc = $messenger_label && $message_type_label
3124
-            ? $messenger_label . ' ' . $message_type_label . ' ' . $context . ' '
3125
-            : '';
3126
-        $item_desc .= 'Message Template';
3127
-        return $item_desc;
3128
-    }
3129
-
3130
-
3131
-    /**
3132
-     * @param string $messenger
3133
-     * @param string $message_type
3134
-     * @param string $context
3135
-     * @return bool
3136
-     * @throws EE_Error
3137
-     * @throws ReflectionException
3138
-     * @since 4.10.29.p
3139
-     */
3140
-    private function performTestSendAfterUpdate($messenger, $message_type, $context)
3141
-    {
3142
-        // was a test send triggered?
3143
-        if ($this->request->requestParamIsSet('test_button')) {
3144
-            EE_Error::overwrite_success();
3145
-            $this->_do_test_send($context, $messenger, $message_type);
3146
-            return true;
3147
-        }
3148
-        return false;
3149
-    }
3150
-
3151
-
3152
-    /**
3153
-     * processes a test send request to do an actual messenger delivery test for the given message template being tested
3154
-     *
3155
-     * @param string $context      what context being tested
3156
-     * @param string $messenger    messenger being tested
3157
-     * @param string $message_type message type being tested
3158
-     * @throws EE_Error
3159
-     * @throws InvalidArgumentException
3160
-     * @throws InvalidDataTypeException
3161
-     * @throws InvalidInterfaceException
3162
-     * @throws ReflectionException
3163
-     */
3164
-    protected function _do_test_send($context, $messenger, $message_type)
3165
-    {
3166
-        // set things up for preview
3167
-        $this->request->setRequestParam('messenger', $messenger);
3168
-        $this->request->setRequestParam('message_type', $message_type);
3169
-        $this->request->setRequestParam('context', $context);
3170
-        $GRP_ID = $this->request->getRequestParam('GRP_ID', 0, 'int');
3171
-        $this->request->setRequestParam('GRP_ID', $GRP_ID);
3172
-
3173
-        $active_messenger  = $this->_message_resource_manager->get_active_messenger($messenger);
3174
-        $test_settings_fld = $this->request->getRequestParam('test_settings_fld', [], 'string', true);
3175
-
3176
-        // let's save any existing fields that might be required by the messenger
3177
-        if (
3178
-            ! empty($test_settings_fld)
3179
-            && $active_messenger instanceof EE_messenger
3180
-            && apply_filters(
3181
-                'FHEE__Messages_Admin_Page__do_test_send__set_existing_test_settings',
3182
-                true,
3183
-                $test_settings_fld,
3184
-                $active_messenger
3185
-            )
3186
-        ) {
3187
-            $active_messenger->set_existing_test_settings($test_settings_fld);
3188
-        }
3189
-
3190
-        /**
3191
-         * Use filter to add additional controls on whether message can send or not
3192
-         */
3193
-        if (
3194
-            apply_filters(
3195
-                'FHEE__Messages_Admin_Page__do_test_send__can_send',
3196
-                true,
3197
-                $context,
3198
-                $this->request->requestParams(),
3199
-                $messenger,
3200
-                $message_type
3201
-            )
3202
-        ) {
3203
-            if (EEM_Event::instance()->count() > 0) {
3204
-                $success = $this->_preview_message(true);
3205
-                if ($success) {
3206
-                    EE_Error::add_success(esc_html__('Test message sent', 'event_espresso'));
3207
-                } else {
3208
-                    EE_Error::add_error(
3209
-                        esc_html__('The test message was not sent', 'event_espresso'),
3210
-                        __FILE__,
3211
-                        __FUNCTION__,
3212
-                        __LINE__
3213
-                    );
3214
-                }
3215
-            } else {
3216
-                $this->noEventsErrorMessage(true);
3217
-            }
3218
-        }
3219
-    }
3220
-
3221
-
3222
-    /**
3223
-     * _generate_new_templates
3224
-     * This will handle the messenger, message_type selection when "adding a new custom template" for an event and will
3225
-     * automatically create the defaults for the event.  The user would then be redirected to edit the default context
3226
-     * for the event.
3227
-     *
3228
-     *
3229
-     * @param string $messenger      the messenger we are generating templates for
3230
-     * @param array  $message_types  array of message types that the templates are generated for.
3231
-     * @param int    $GRP_ID         If this is a custom template being generated then a GRP_ID needs to be included to
3232
-     *                               indicate the message_template_group being used as the base.
3233
-     *
3234
-     * @param bool   $global
3235
-     *
3236
-     * @return array|bool array of data required for the redirect to the correct edit page or bool if
3237
-     *                               encountering problems.
3238
-     * @throws EE_Error
3239
-     * @throws ReflectionException
3240
-     */
3241
-    protected function _generate_new_templates($messenger, $message_types, $GRP_ID = 0, $global = false)
3242
-    {
3243
-        // if no $message_types are given then that's okay... this may be a messenger that just adds shortcodes, so we
3244
-        // just don't generate any templates.
3245
-        if (empty($message_types)) {
3246
-            return [];
3247
-        }
3248
-
3249
-        $templates = EEH_MSG_Template::generate_new_templates($messenger, $message_types, $GRP_ID, $global);
3250
-        return $templates[0];
3251
-    }
3252
-
3253
-
3254
-    /**
3255
-     * [_trash_or_restore_message_template]
3256
-     *
3257
-     * @param boolean $trash  whether to move an item to trash/restore (TRUE) or restore it (FALSE)
3258
-     * @param boolean $all    whether this is going to trash/restore all contexts within a template group (TRUE) OR just
3259
-     *                        an individual context (FALSE).
3260
-     * @return void
3261
-     * @throws EE_Error
3262
-     * @throws InvalidArgumentException
3263
-     * @throws InvalidDataTypeException
3264
-     * @throws InvalidInterfaceException
3265
-     */
3266
-    protected function _trash_or_restore_message_template($trash = true, $all = false)
3267
-    {
3268
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3269
-
3270
-        $success = 1;
3271
-
3272
-        // incoming GRP_IDs
3273
-        if ($all) {
3274
-            // Checkboxes
3275
-            $checkboxes = $this->request->getRequestParam('checkbox', [], 'int', true);
3276
-            if (! empty($checkboxes)) {
3277
-                // if array has more than one element then success message should be plural.
3278
-                // todo: what about nonce?
3279
-                $success = count($checkboxes) > 1 ? 2 : 1;
3280
-
3281
-                // cycle through checkboxes
3282
-                while (list($GRP_ID, $value) = each($checkboxes)) {
3283
-                    $trashed_or_restored = $trash
3284
-                        ? $this->getMtgModel()->delete_by_ID($GRP_ID)
3285
-                        : $this->getMtgModel()->restore_by_ID($GRP_ID);
3286
-                    if (! $trashed_or_restored) {
3287
-                        $success = 0;
3288
-                    }
3289
-                }
3290
-            } else {
3291
-                // grab single GRP_ID and handle
3292
-                $GRP_ID = $this->request->getRequestParam('id', 0, 'int');
3293
-                if (! empty($GRP_ID)) {
3294
-                    $trashed_or_restored = $trash
3295
-                        ? $this->getMtgModel()->delete_by_ID($GRP_ID)
3296
-                        : $this->getMtgModel()->restore_by_ID($GRP_ID);
3297
-                    if (! $trashed_or_restored) {
3298
-                        $success = 0;
3299
-                    }
3300
-                } else {
3301
-                    $success = 0;
3302
-                }
3303
-            }
3304
-        }
3305
-
3306
-        $action_desc = $trash
3307
-            ? esc_html__('moved to the trash', 'event_espresso')
3308
-            : esc_html__('restored', 'event_espresso');
3309
-
3310
-        $template_switch = $this->request->getRequestParam('template_switch', false, 'bool');
3311
-        $action_desc     = $template_switch ? esc_html__('switched', 'event_espresso') : $action_desc;
3312
-
3313
-        $item_desc = $all ? _n(
3314
-            'Message Template Group',
3315
-            'Message Template Groups',
3316
-            $success,
3317
-            'event_espresso'
3318
-        ) : _n('Message Template Context', 'Message Template Contexts', $success, 'event_espresso');
3319
-
3320
-        $item_desc = $template_switch
3321
-            ? _n('template', 'templates', $success, 'event_espresso')
3322
-            : $item_desc;
3323
-
3324
-        $this->_redirect_after_action($success, $item_desc, $action_desc, []);
3325
-    }
3326
-
3327
-
3328
-    /**
3329
-     * [_delete_message_template]
3330
-     * NOTE: this handles not only the deletion of the groups but also all the templates belonging to that group.
3331
-     *
3332
-     * @return void
3333
-     * @throws EE_Error
3334
-     * @throws InvalidArgumentException
3335
-     * @throws InvalidDataTypeException
3336
-     * @throws InvalidInterfaceException
3337
-     * @throws ReflectionException
3338
-     */
3339
-    protected function _delete_message_template()
3340
-    {
3341
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3342
-
3343
-        // checkboxes
3344
-        $checkboxes = $this->request->getRequestParam('checkbox', [], 'int', true);
3345
-        if (! empty($checkboxes)) {
3346
-            // if array has more than one element then success message should be plural
3347
-            $success = count($checkboxes) > 1 ? 2 : 1;
3348
-
3349
-            // cycle through bulk action checkboxes
3350
-            while (list($GRP_ID, $value) = each($checkboxes)) {
3351
-                $success = $this->_delete_mtp_permanently($GRP_ID) ? $success : false;
3352
-            }
3353
-        } else {
3354
-            // grab single grp_id and delete
3355
-            $GRP_ID  = $this->request->getRequestParam('id', 0, 'int');
3356
-            $success = $this->_delete_mtp_permanently($GRP_ID);
3357
-        }
3358
-
3359
-        $this->_redirect_after_action($success, 'Message Templates', 'deleted', []);
3360
-    }
3361
-
3362
-
3363
-    /**
3364
-     * helper for permanently deleting a mtP group and all related message_templates
3365
-     *
3366
-     * @param int  $GRP_ID        The group being deleted
3367
-     * @param bool $include_group whether to delete the Message Template Group as well.
3368
-     * @return bool boolean to indicate the success of the deletes or not.
3369
-     * @throws EE_Error
3370
-     * @throws InvalidArgumentException
3371
-     * @throws InvalidDataTypeException
3372
-     * @throws InvalidInterfaceException
3373
-     * @throws ReflectionException
3374
-     * @throws ReflectionException
3375
-     */
3376
-    private function _delete_mtp_permanently($GRP_ID, $include_group = true)
3377
-    {
3378
-        $success = true;
3379
-        // first let's GET this group
3380
-        $MTG = $this->getMtgModel()->get_one_by_ID($GRP_ID);
3381
-        // then delete permanently all the related Message Templates
3382
-        $deleted = $MTG->delete_related_permanently('Message_Template');
3383
-
3384
-        if ($deleted === 0) {
3385
-            $success = false;
3386
-        }
3387
-
3388
-        // now delete permanently this particular group
3389
-
3390
-        if ($include_group && ! $MTG->delete_permanently()) {
3391
-            $success = false;
3392
-        }
3393
-
3394
-        return $success;
3395
-    }
3396
-
3397
-
3398
-    /**
3399
-     *    _learn_more_about_message_templates_link
3400
-     *
3401
-     * @access protected
3402
-     * @return string
3403
-     */
3404
-    protected function _learn_more_about_message_templates_link()
3405
-    {
3406
-        return '<a class="hidden" style="margin:0 20px; cursor:pointer; font-size:12px;" >'
3407
-               . esc_html__('learn more about how message templates works', 'event_espresso')
3408
-               . '</a>';
3409
-    }
3410
-
3411
-
3412
-    /**
3413
-     * Used for setting up messenger/message type activation.  This loads up the initial view.  The rest is handled by
3414
-     * ajax and other routes.
3415
-     *
3416
-     * @return void
3417
-     * @throws DomainException
3418
-     * @throws EE_Error
3419
-     */
3420
-    protected function _settings()
3421
-    {
3422
-        $this->_set_m_mt_settings();
3423
-
3424
-        // let's setup the messenger tabs
3425
-        $this->_template_args['admin_page_header'] = EEH_Tabbed_Content::tab_text_links(
3426
-            $this->_m_mt_settings['messenger_tabs'],
3427
-            'messenger_links',
3428
-            '|',
3429
-            $this->request->getRequestParam('selected_messenger', 'email')
3430
-        );
3431
-
3432
-        $this->_template_args['before_admin_page_content'] = '<div class="ui-widget ui-helper-clearfix">';
3433
-        $this->_template_args['after_admin_page_content']  = '</div><!-- end .ui-widget -->';
3434
-
3435
-        $this->display_admin_page_with_sidebar();
3436
-    }
3437
-
3438
-
3439
-    /**
3440
-     * This sets the $_m_mt_settings property for when needed (used on the Messages settings page)
3441
-     *
3442
-     * @access protected
3443
-     * @return void
3444
-     * @throws DomainException
3445
-     */
3446
-    protected function _set_m_mt_settings()
3447
-    {
3448
-        // first if this is already set then lets get out no need to regenerate data.
3449
-        if (! empty($this->_m_mt_settings)) {
3450
-            return;
3451
-        }
3452
-
3453
-        // get all installed messengers and message_types
3454
-        $messengers    = $this->_message_resource_manager->installed_messengers();
3455
-        $message_types = $this->_message_resource_manager->installed_message_types();
3456
-
3457
-
3458
-        // assemble the array for the _tab_text_links helper
3459
-
3460
-        foreach ($messengers as $messenger) {
3461
-            $active = $this->_message_resource_manager->is_messenger_active($messenger->name);
3462
-            $class = 'ee-messenger-' .  sanitize_key($messenger->label['singular']);
3463
-            $this->_m_mt_settings['messenger_tabs'][ $messenger->name ] = [
3464
-                'label' => ucwords($messenger->label['singular']),
3465
-                'class' => $active ? "{$class} messenger-active" : $class,
3466
-                'href'  => $messenger->name,
3467
-                'title' => esc_html__('Modify this Messenger', 'event_espresso'),
3468
-                'slug'  => $messenger->name,
3469
-                'obj'   => $messenger,
3470
-                'icon' => $active
3471
-                    ? '<span class="dashicons dashicons-yes-alt"></span>'
3472
-                    : '<span class="dashicons dashicons-remove"></span>',
3473
-            ];
3474
-
3475
-
3476
-            $message_types_for_messenger = $messenger->get_valid_message_types();
3477
-
3478
-            foreach ($message_types as $message_type) {
3479
-                // first we need to verify that this message type is valid with this messenger. Cause if it isn't then
3480
-                // it shouldn't show in either the inactive OR active metabox.
3481
-                if (! in_array($message_type->name, $message_types_for_messenger, true)) {
3482
-                    continue;
3483
-                }
3484
-
3485
-                $a_or_i = $this->_message_resource_manager->is_message_type_active_for_messenger(
3486
-                    $messenger->name,
3487
-                    $message_type->name
3488
-                )
3489
-                    ? 'active'
3490
-                    : 'inactive';
3491
-
3492
-                $this->_m_mt_settings['message_type_tabs'][ $messenger->name ][ $a_or_i ][ $message_type->name ] = [
3493
-                    'label'    => ucwords($message_type->label['singular']),
3494
-                    'class'    => 'message-type-' . $a_or_i,
3495
-                    'slug_id'  => $message_type->name . '-messagetype-' . $messenger->name,
3496
-                    'mt_nonce' => wp_create_nonce($message_type->name . '_nonce'),
3497
-                    'href'     => 'espresso_' . $message_type->name . '_message_type_settings',
3498
-                    'title'    => $a_or_i === 'active'
3499
-                        ? esc_html__('Drag this message type to the Inactive window to deactivate', 'event_espresso')
3500
-                        : esc_html__('Drag this message type to the messenger to activate', 'event_espresso'),
3501
-                    'content'  => $a_or_i === 'active'
3502
-                        ? $this->_message_type_settings_content($message_type, $messenger, true)
3503
-                        : $this->_message_type_settings_content($message_type, $messenger),
3504
-                    'slug'     => $message_type->name,
3505
-                    'active'   => $a_or_i === 'active',
3506
-                    'obj'      => $message_type,
3507
-                ];
3508
-            }
3509
-        }
3510
-    }
3511
-
3512
-
3513
-    /**
3514
-     * This just prepares the content for the message type settings
3515
-     *
3516
-     * @param EE_message_type $message_type The message type object
3517
-     * @param EE_messenger    $messenger    The messenger object
3518
-     * @param boolean         $active       Whether the message type is active or not
3519
-     * @return string html output for the content
3520
-     * @throws DomainException
3521
-     */
3522
-    protected function _message_type_settings_content($message_type, $messenger, $active = false)
3523
-    {
3524
-        // get message type fields
3525
-        $fields                                         = $message_type->get_admin_settings_fields();
3526
-        $settings_template_args['template_form_fields'] = '';
3527
-
3528
-        if (! empty($fields) && $active) {
3529
-            $existing_settings = $message_type->get_existing_admin_settings($messenger->name);
3530
-            foreach ($fields as $fldname => $fldprops) {
3531
-                $field_id                         = $messenger->name . '-' . $message_type->name . '-' . $fldname;
3532
-                $template_form_field[ $field_id ] = [
3533
-                    'name'       => 'message_type_settings[' . $fldname . ']',
3534
-                    'label'      => $fldprops['label'],
3535
-                    'input'      => $fldprops['field_type'],
3536
-                    'type'       => $fldprops['value_type'],
3537
-                    'required'   => $fldprops['required'],
3538
-                    'validation' => $fldprops['validation'],
3539
-                    'value'      => isset($existing_settings[ $fldname ])
3540
-                        ? $existing_settings[ $fldname ]
3541
-                        : $fldprops['default'],
3542
-                    'options'    => isset($fldprops['options'])
3543
-                        ? $fldprops['options']
3544
-                        : [],
3545
-                    'default'    => isset($existing_settings[ $fldname ])
3546
-                        ? $existing_settings[ $fldname ]
3547
-                        : $fldprops['default'],
3548
-                    'css_class'  => 'no-drag',
3549
-                    'format'     => $fldprops['format'],
3550
-                ];
3551
-            }
3552
-
3553
-
3554
-            $settings_template_args['template_form_fields'] = ! empty($template_form_field)
3555
-                ? $this->_generate_admin_form_fields(
3556
-                    $template_form_field,
3557
-                    'string',
3558
-                    'ee_mt_activate_form'
3559
-                )
3560
-                : '';
3561
-        }
3562
-
3563
-        $settings_template_args['description'] = $message_type->description;
3564
-        // we also need some hidden fields
3565
-        $hidden_fields = [
3566
-            'message_type_settings[messenger]' . $message_type->name    => [
3567
-                'type'  => 'hidden',
3568
-                'value' => $messenger->name,
3569
-            ],
3570
-            'message_type_settings[message_type]' . $message_type->name => [
3571
-                'type'  => 'hidden',
3572
-                'value' => $message_type->name,
3573
-            ],
3574
-            'type' . $message_type->name                                => [
3575
-                'type'  => 'hidden',
3576
-                'value' => 'message_type',
3577
-            ],
3578
-        ];
3579
-
3580
-        $settings_template_args['hidden_fields'] = $this->_generate_admin_form_fields(
3581
-            $hidden_fields,
3582
-            'array'
3583
-        );
3584
-        $settings_template_args['show_form']     = empty($settings_template_args['template_form_fields'])
3585
-            ? ' hidden'
3586
-            : '';
3587
-
3588
-
3589
-        $template = EE_MSG_TEMPLATE_PATH . 'ee_msg_mt_settings_content.template.php';
3590
-        return EEH_Template::display_template($template, $settings_template_args, true);
3591
-    }
3592
-
3593
-
3594
-    /**
3595
-     * Generate all the metaboxes for the message types and register them for the messages settings page.
3596
-     *
3597
-     * @access protected
3598
-     * @return void
3599
-     * @throws DomainException
3600
-     */
3601
-    protected function _messages_settings_metaboxes()
3602
-    {
3603
-        $this->_set_m_mt_settings();
3604
-        $m_boxes         = $mt_boxes = [];
3605
-        $m_template_args = $mt_template_args = [];
3606
-
3607
-        $selected_messenger = $this->request->getRequestParam('selected_messenger', 'email');
3608
-
3609
-        if (isset($this->_m_mt_settings['messenger_tabs'])) {
3610
-            foreach ($this->_m_mt_settings['messenger_tabs'] as $messenger => $tab_array) {
3611
-                $is_messenger_active = $this->_message_resource_manager->is_messenger_active($messenger);
3612
-                $hide_on_message     = $is_messenger_active ? '' : 'hidden';
3613
-                $hide_off_message    = $is_messenger_active ? 'hidden' : '';
3614
-
3615
-                // messenger meta boxes
3616
-                $active         = $selected_messenger === $messenger;
3617
-                $active_mt_tabs = isset($this->_m_mt_settings['message_type_tabs'][ $messenger ]['active'])
3618
-                    ? $this->_m_mt_settings['message_type_tabs'][ $messenger ]['active']
3619
-                    : '';
3620
-
3621
-                $m_boxes[ $messenger . '_a_box' ] = sprintf(
3622
-                    esc_html__('%s Settings', 'event_espresso'),
3623
-                    $tab_array['label']
3624
-                );
3625
-
3626
-                $m_template_args[ $messenger . '_a_box' ] = [
3627
-                    'active_message_types'   => ! empty($active_mt_tabs) ? $this->_get_mt_tabs($active_mt_tabs) : '',
3628
-                    'inactive_message_types' => isset(
3629
-                        $this->_m_mt_settings['message_type_tabs'][ $messenger ]['inactive']
3630
-                    )
3631
-                        ? $this->_get_mt_tabs($this->_m_mt_settings['message_type_tabs'][ $messenger ]['inactive'])
3632
-                        : '',
3633
-                    'content'                => $this->_get_messenger_box_content($tab_array['obj']),
3634
-                    'hidden'                 => $active ? '' : ' hidden',
3635
-                    'hide_on_message'        => $hide_on_message,
3636
-                    'messenger'              => $messenger,
3637
-                    'active'                 => $active,
3638
-                ];
3639
-
3640
-                // message type meta boxes
3641
-                // (which is really just the inactive container for each messenger
3642
-                // showing inactive message types for that messenger)
3643
-                $mt_boxes[ $messenger . '_i_box' ]         = esc_html__('Inactive Message Types', 'event_espresso');
3644
-                $mt_template_args[ $messenger . '_i_box' ] = [
3645
-                    'active_message_types'   => ! empty($active_mt_tabs) ? $this->_get_mt_tabs($active_mt_tabs) : '',
3646
-                    'inactive_message_types' => isset(
3647
-                        $this->_m_mt_settings['message_type_tabs'][ $messenger ]['inactive']
3648
-                    )
3649
-                        ? $this->_get_mt_tabs($this->_m_mt_settings['message_type_tabs'][ $messenger ]['inactive'])
3650
-                        : '',
3651
-                    'hidden'                 => $active ? '' : ' hidden',
3652
-                    'hide_on_message'        => $hide_on_message,
3653
-                    'hide_off_message'       => $hide_off_message,
3654
-                    'messenger'              => $messenger,
3655
-                    'active'                 => $active,
3656
-                ];
3657
-            }
3658
-        }
3659
-
3660
-
3661
-        // register messenger metaboxes
3662
-        $m_template_path = EE_MSG_TEMPLATE_PATH . 'ee_msg_details_messenger_mt_meta_box.template.php';
3663
-        foreach ($m_boxes as $box => $label) {
3664
-            $callback_args = ['template_path' => $m_template_path, 'template_args' => $m_template_args[ $box ]];
3665
-            $msgr          = str_replace('_a_box', '', $box);
3666
-            $this->addMetaBox(
3667
-                'espresso_' . $msgr . '_settings',
3668
-                $label,
3669
-                function ($post, $metabox) {
3670
-                    EEH_Template::display_template(
3671
-                        $metabox['args']['template_path'],
3672
-                        $metabox['args']['template_args']
3673
-                    );
3674
-                },
3675
-                $this->_current_screen->id,
3676
-                'normal',
3677
-                'high',
3678
-                $callback_args
3679
-            );
3680
-        }
3681
-
3682
-        // register message type metaboxes
3683
-        $mt_template_path = EE_MSG_TEMPLATE_PATH . 'ee_msg_details_messenger_meta_box.template.php';
3684
-        foreach ($mt_boxes as $box => $label) {
3685
-            $callback_args = [
3686
-                'template_path' => $mt_template_path,
3687
-                'template_args' => $mt_template_args[ $box ],
3688
-            ];
3689
-            $mt            = str_replace('_i_box', '', $box);
3690
-            $this->addMetaBox(
3691
-                'espresso_' . $mt . '_inactive_mts',
3692
-                $label,
3693
-                function ($post, $metabox) {
3694
-                    EEH_Template::display_template(
3695
-                        $metabox['args']['template_path'],
3696
-                        $metabox['args']['template_args']
3697
-                    );
3698
-                },
3699
-                $this->_current_screen->id,
3700
-                'side',
3701
-                'high',
3702
-                $callback_args
3703
-            );
3704
-        }
3705
-
3706
-        // register metabox for global messages settings but only when on the main site.  On single site installs this
3707
-        // will always result in the metabox showing, on multisite installs the metabox will only show on the main site.
3708
-        if (is_main_site()) {
3709
-            $this->addMetaBox(
3710
-                'espresso_global_message_settings',
3711
-                esc_html__('Global Message Settings', 'event_espresso'),
3712
-                [$this, 'global_messages_settings_metabox_content'],
3713
-                $this->_current_screen->id,
3714
-                'normal',
3715
-                'low',
3716
-                []
3717
-            );
3718
-        }
3719
-    }
3720
-
3721
-
3722
-    /**
3723
-     *  This generates the content for the global messages settings metabox.
3724
-     *
3725
-     * @return void
3726
-     * @throws EE_Error
3727
-     * @throws InvalidArgumentException
3728
-     * @throws ReflectionException
3729
-     * @throws InvalidDataTypeException
3730
-     * @throws InvalidInterfaceException
3731
-     */
3732
-    public function global_messages_settings_metabox_content()
3733
-    {
3734
-        $form = $this->_generate_global_settings_form();
3735
-        echo wp_kses(
3736
-            $form->form_open(
3737
-                $this->add_query_args_and_nonce(['action' => 'update_global_settings'], EE_MSG_ADMIN_URL),
3738
-                'POST'
3739
-            ),
3740
-            AllowedTags::getWithFormTags()
3741
-        );
3742
-        echo wp_kses($form->get_html(), AllowedTags::getWithFormTags());
3743
-        echo wp_kses($form->form_close(), AllowedTags::getWithFormTags());
3744
-    }
3745
-
3746
-
3747
-    /**
3748
-     * This generates and returns the form object for the global messages settings.
3749
-     *
3750
-     * @return EE_Form_Section_Proper
3751
-     * @throws EE_Error
3752
-     * @throws InvalidArgumentException
3753
-     * @throws ReflectionException
3754
-     * @throws InvalidDataTypeException
3755
-     * @throws InvalidInterfaceException
3756
-     */
3757
-    protected function _generate_global_settings_form()
3758
-    {
3759
-        /** @var EE_Network_Core_Config $network_config */
3760
-        $network_config = EE_Registry::instance()->NET_CFG->core;
3761
-
3762
-        return new EE_Form_Section_Proper(
3763
-            [
3764
-                'name'            => 'global_messages_settings',
3765
-                'html_id'         => 'global_messages_settings',
3766
-                'html_class'      => 'form-table',
3767
-                'layout_strategy' => new EE_Admin_Two_Column_Layout(),
3768
-                'subsections'     => apply_filters(
3769
-                    'FHEE__Messages_Admin_Page__global_messages_settings_metabox_content__form_subsections',
3770
-                    [
3771
-                        'do_messages_on_same_request' => new EE_Select_Input(
3772
-                            [
3773
-                                true  => esc_html__('On the same request', 'event_espresso'),
3774
-                                false => esc_html__('On a separate request', 'event_espresso'),
3775
-                            ],
3776
-                            [
3777
-                                'default'         => $network_config->do_messages_on_same_request,
3778
-                                'html_label_text' => esc_html__(
3779
-                                    'Generate and send all messages:',
3780
-                                    'event_espresso'
3781
-                                ),
3782
-                                'html_help_text'  => esc_html__(
3783
-                                    'By default the messages system uses a more efficient means of processing messages on separate requests and utilizes the wp-cron scheduling system.  This makes things execute faster for people registering for your events.  However, if the wp-cron system is disabled on your site and there is no alternative in place, then you can change this so messages are always executed on the same request.',
3784
-                                    'event_espresso'
3785
-                                ),
3786
-                            ]
3787
-                        ),
3788
-                        'delete_threshold'            => new EE_Select_Input(
3789
-                            [
3790
-                                0  => esc_html__('Forever', 'event_espresso'),
3791
-                                3  => esc_html__('3 Months', 'event_espresso'),
3792
-                                6  => esc_html__('6 Months', 'event_espresso'),
3793
-                                9  => esc_html__('9 Months', 'event_espresso'),
3794
-                                12 => esc_html__('12 Months', 'event_espresso'),
3795
-                                24 => esc_html__('24 Months', 'event_espresso'),
3796
-                                36 => esc_html__('36 Months', 'event_espresso'),
3797
-                            ],
3798
-                            [
3799
-                                'default'         => EE_Registry::instance()->CFG->messages->delete_threshold,
3800
-                                'html_label_text' => esc_html__('Cleanup of old messages:', 'event_espresso'),
3801
-                                'html_help_text'  => esc_html__(
3802
-                                    'You can control how long a record of processed messages is kept via this option.',
3803
-                                    'event_espresso'
3804
-                                ),
3805
-                            ]
3806
-                        ),
3807
-                        'update_settings'             => new EE_Submit_Input(
3808
-                            [
3809
-                                'default'         => esc_html__('Update', 'event_espresso'),
3810
-                                'html_label_text' => '',
3811
-                            ]
3812
-                        ),
3813
-                    ]
3814
-                ),
3815
-            ]
3816
-        );
3817
-    }
3818
-
3819
-
3820
-    /**
3821
-     * This handles updating the global settings set on the admin page.
3822
-     *
3823
-     * @throws EE_Error
3824
-     * @throws InvalidDataTypeException
3825
-     * @throws InvalidInterfaceException
3826
-     * @throws InvalidArgumentException
3827
-     * @throws ReflectionException
3828
-     */
3829
-    protected function _update_global_settings()
3830
-    {
3831
-        /** @var EE_Network_Core_Config $network_config */
3832
-        $network_config  = EE_Registry::instance()->NET_CFG->core;
3833
-        $messages_config = EE_Registry::instance()->CFG->messages;
3834
-        $form            = $this->_generate_global_settings_form();
3835
-        if ($form->was_submitted()) {
3836
-            $form->receive_form_submission();
3837
-            if ($form->is_valid()) {
3838
-                $valid_data = $form->valid_data();
3839
-                foreach ($valid_data as $property => $value) {
3840
-                    $setter = 'set_' . $property;
3841
-                    if (method_exists($network_config, $setter)) {
3842
-                        $network_config->{$setter}($value);
3843
-                    } elseif (
3844
-                        property_exists($network_config, $property)
3845
-                        && $network_config->{$property} !== $value
3846
-                    ) {
3847
-                        $network_config->{$property} = $value;
3848
-                    } elseif (
3849
-                        property_exists($messages_config, $property)
3850
-                        && $messages_config->{$property} !== $value
3851
-                    ) {
3852
-                        $messages_config->{$property} = $value;
3853
-                    }
3854
-                }
3855
-                // only update if the form submission was valid!
3856
-                EE_Registry::instance()->NET_CFG->update_config(true, false);
3857
-                EE_Registry::instance()->CFG->update_espresso_config();
3858
-                EE_Error::overwrite_success();
3859
-                EE_Error::add_success(esc_html__('Global message settings were updated', 'event_espresso'));
3860
-            }
3861
-        }
3862
-        $this->_redirect_after_action(0, '', '', ['action' => 'settings'], true);
3863
-    }
3864
-
3865
-
3866
-    /**
3867
-     * this prepares the messenger tabs that can be dragged in and out of messenger boxes to activate/deactivate
3868
-     *
3869
-     * @param array $tab_array This is an array of message type tab details used to generate the tabs
3870
-     * @return string html formatted tabs
3871
-     * @throws DomainException
3872
-     */
3873
-    protected function _get_mt_tabs($tab_array)
3874
-    {
3875
-        $tab_array = (array) $tab_array;
3876
-        $template  = EE_MSG_TEMPLATE_PATH . 'ee_msg_details_mt_settings_tab_item.template.php';
3877
-        $tabs      = '';
3878
-
3879
-        foreach ($tab_array as $tab) {
3880
-            $tabs .= EEH_Template::display_template($template, $tab, true);
3881
-        }
3882
-
3883
-        return $tabs;
3884
-    }
3885
-
3886
-
3887
-    /**
3888
-     * This prepares the content of the messenger meta box admin settings
3889
-     *
3890
-     * @param EE_messenger $messenger The messenger we're setting up content for
3891
-     * @return string html formatted content
3892
-     * @throws DomainException
3893
-     */
3894
-    protected function _get_messenger_box_content(EE_messenger $messenger)
3895
-    {
3896
-
3897
-        $fields                                         = $messenger->get_admin_settings_fields();
3898
-        $settings_template_args['template_form_fields'] = '';
3899
-
3900
-        // is $messenger active?
3901
-        $settings_template_args['active'] = $this->_message_resource_manager->is_messenger_active($messenger->name);
3902
-
3903
-
3904
-        if (! empty($fields)) {
3905
-            $existing_settings = $messenger->get_existing_admin_settings();
3906
-
3907
-            foreach ($fields as $fldname => $fldprops) {
3908
-                $field_id                         = $messenger->name . '-' . $fldname;
3909
-                $template_form_field[ $field_id ] = [
3910
-                    'name'       => 'messenger_settings[' . $field_id . ']',
3911
-                    'label'      => $fldprops['label'],
3912
-                    'input'      => $fldprops['field_type'],
3913
-                    'type'       => $fldprops['value_type'],
3914
-                    'required'   => $fldprops['required'],
3915
-                    'validation' => $fldprops['validation'],
3916
-                    'value'      => isset($existing_settings[ $field_id ])
3917
-                        ? $existing_settings[ $field_id ]
3918
-                        : $fldprops['default'],
3919
-                    'css_class'  => '',
3920
-                    'format'     => $fldprops['format'],
3921
-                ];
3922
-            }
3923
-
3924
-
3925
-            $settings_template_args['template_form_fields'] = ! empty($template_form_field)
3926
-                ? $this->_generate_admin_form_fields($template_form_field, 'string', 'ee_m_activate_form')
3927
-                : '';
3928
-        }
3929
-
3930
-        // we also need some hidden fields
3931
-        $settings_template_args['hidden_fields'] = [
3932
-            'messenger_settings[messenger]' . $messenger->name => [
3933
-                'type'  => 'hidden',
3934
-                'value' => $messenger->name,
3935
-            ],
3936
-            'type' . $messenger->name                          => [
3937
-                'type'  => 'hidden',
3938
-                'value' => 'messenger',
3939
-            ],
3940
-        ];
3941
-
3942
-        // make sure any active message types that are existing are included in the hidden fields
3943
-        if (isset($this->_m_mt_settings['message_type_tabs'][ $messenger->name ]['active'])) {
3944
-            foreach ($this->_m_mt_settings['message_type_tabs'][ $messenger->name ]['active'] as $mt => $values) {
3945
-                $settings_template_args['hidden_fields'][ 'messenger_settings[message_types][' . $mt . ']' ] = [
3946
-                    'type'  => 'hidden',
3947
-                    'value' => $mt,
3948
-                ];
3949
-            }
3950
-        }
3951
-        $settings_template_args['hidden_fields'] = $this->_generate_admin_form_fields(
3952
-            $settings_template_args['hidden_fields'],
3953
-            'array'
3954
-        );
3955
-        $active                                  =
3956
-            $this->_message_resource_manager->is_messenger_active($messenger->name);
3957
-
3958
-        $settings_template_args['messenger']           = $messenger->name;
3959
-        $settings_template_args['description']         = $messenger->description;
3960
-        $settings_template_args['show_hide_edit_form'] = $active ? '' : ' hidden';
3961
-
3962
-
3963
-        $settings_template_args['show_hide_edit_form'] = $this->_message_resource_manager->is_messenger_active(
3964
-            $messenger->name
3965
-        )
3966
-            ? $settings_template_args['show_hide_edit_form']
3967
-            : ' hidden';
3968
-
3969
-        $settings_template_args['show_hide_edit_form'] = empty($settings_template_args['template_form_fields'])
3970
-            ? ' hidden'
3971
-            : $settings_template_args['show_hide_edit_form'];
3972
-
3973
-
3974
-        $settings_template_args['on_off_action'] = $active ? 'messenger-off' : 'messenger-on';
3975
-        $settings_template_args['nonce']         = wp_create_nonce('activate_' . $messenger->name . '_toggle_nonce');
3976
-        $settings_template_args['on_off_status'] = $active;
3977
-        $template                                = EE_MSG_TEMPLATE_PATH . 'ee_msg_m_settings_content.template.php';
3978
-        return EEH_Template::display_template(
3979
-            $template,
3980
-            $settings_template_args,
3981
-            true
3982
-        );
3983
-    }
3984
-
3985
-
3986
-    /**
3987
-     * used by ajax on the messages settings page to activate|deactivate the messenger
3988
-     *
3989
-     * @throws DomainException
3990
-     * @throws EE_Error
3991
-     * @throws InvalidDataTypeException
3992
-     * @throws InvalidInterfaceException
3993
-     * @throws InvalidArgumentException
3994
-     * @throws ReflectionException
3995
-     */
3996
-    public function activate_messenger_toggle()
3997
-    {
3998
-        $success = true;
3999
-        $this->_prep_default_response_for_messenger_or_message_type_toggle();
4000
-        // let's check that we have required data
4001
-
4002
-        if (! $this->_active_messenger_name) {
4003
-            EE_Error::add_error(
4004
-                esc_html__('Messenger name needed to toggle activation. None given', 'event_espresso'),
4005
-                __FILE__,
4006
-                __FUNCTION__,
4007
-                __LINE__
4008
-            );
4009
-            $success = false;
4010
-        }
4011
-
4012
-        // do a nonce check here since we're not arriving via a normal route
4013
-        $nonce     = $this->request->getRequestParam('activate_nonce', '');
4014
-        $nonce_ref = "activate_{$this->_active_messenger_name}_toggle_nonce";
4015
-
4016
-        $this->_verify_nonce($nonce, $nonce_ref);
4017
-
4018
-
4019
-        $status = $this->request->getRequestParam('status');
4020
-        if (! $status) {
4021
-            EE_Error::add_error(
4022
-                esc_html__(
4023
-                    'Messenger status needed to know whether activation or deactivation is happening. No status is given',
4024
-                    'event_espresso'
4025
-                ),
4026
-                __FILE__,
4027
-                __FUNCTION__,
4028
-                __LINE__
4029
-            );
4030
-            $success = false;
4031
-        }
4032
-
4033
-        // do check to verify we have a valid status.
4034
-        if ($status !== 'off' && $status !== 'on') {
4035
-            EE_Error::add_error(
4036
-                sprintf(
4037
-                    esc_html__('The given status (%s) is not valid. Must be "off" or "on"', 'event_espresso'),
4038
-                    $status
4039
-                ),
4040
-                __FILE__,
4041
-                __FUNCTION__,
4042
-                __LINE__
4043
-            );
4044
-            $success = false;
4045
-        }
4046
-
4047
-        if ($success) {
4048
-            // made it here?  Stop dawdling then!!
4049
-            $success = $status === 'off'
4050
-                ? $this->_deactivate_messenger($this->_active_messenger_name)
4051
-                : $this->_activate_messenger($this->_active_messenger_name);
4052
-        }
4053
-
4054
-        $this->_template_args['success'] = $success;
4055
-
4056
-        // no special instructions so let's just do the json return (which should automatically do all the special stuff).
4057
-        $this->_return_json();
4058
-    }
4059
-
4060
-
4061
-    /**
4062
-     * used by ajax from the messages settings page to activate|deactivate a message type
4063
-     *
4064
-     * @throws DomainException
4065
-     * @throws EE_Error
4066
-     * @throws ReflectionException
4067
-     * @throws InvalidDataTypeException
4068
-     * @throws InvalidInterfaceException
4069
-     * @throws InvalidArgumentException
4070
-     */
4071
-    public function activate_mt_toggle()
4072
-    {
4073
-        $success = true;
4074
-        $this->_prep_default_response_for_messenger_or_message_type_toggle();
4075
-
4076
-        // let's make sure we have the necessary data
4077
-        if (! $this->_active_message_type_name) {
4078
-            EE_Error::add_error(
4079
-                esc_html__('Message Type name needed to toggle activation. None given', 'event_espresso'),
4080
-                __FILE__,
4081
-                __FUNCTION__,
4082
-                __LINE__
4083
-            );
4084
-            $success = false;
4085
-        }
4086
-
4087
-        if (! $this->_active_messenger_name) {
4088
-            EE_Error::add_error(
4089
-                esc_html__('Messenger name needed to toggle activation. None given', 'event_espresso'),
4090
-                __FILE__,
4091
-                __FUNCTION__,
4092
-                __LINE__
4093
-            );
4094
-            $success = false;
4095
-        }
4096
-
4097
-        $status = $this->request->getRequestParam('status');
4098
-        if (! $status) {
4099
-            EE_Error::add_error(
4100
-                esc_html__(
4101
-                    'Messenger status needed to know whether activation or deactivation is happening. No status is given',
4102
-                    'event_espresso'
4103
-                ),
4104
-                __FILE__,
4105
-                __FUNCTION__,
4106
-                __LINE__
4107
-            );
4108
-            $success = false;
4109
-        }
4110
-
4111
-
4112
-        // do check to verify we have a valid status.
4113
-        if ($status !== 'activate' && $status !== 'deactivate') {
4114
-            EE_Error::add_error(
4115
-                sprintf(
4116
-                    esc_html__('The given status (%s) is not valid. Must be "active" or "inactive"', 'event_espresso'),
4117
-                    $status
4118
-                ),
4119
-                __FILE__,
4120
-                __FUNCTION__,
4121
-                __LINE__
4122
-            );
4123
-            $success = false;
4124
-        }
4125
-
4126
-
4127
-        // do a nonce check here since we're not arriving via a normal route
4128
-        $nonce = $this->request->getRequestParam('mt_nonce', '');
4129
-        $this->_verify_nonce($nonce, "{$this->_active_message_type_name}_nonce");
4130
-
4131
-        if ($success) {
4132
-            // made it here? um, what are you waiting for then?
4133
-            $success = $status === 'deactivate'
4134
-                ? $this->_deactivate_message_type_for_messenger(
4135
-                    $this->_active_messenger_name,
4136
-                    $this->_active_message_type_name
4137
-                )
4138
-                : $this->_activate_message_type_for_messenger(
4139
-                    $this->_active_messenger_name,
4140
-                    $this->_active_message_type_name
4141
-                );
4142
-        }
4143
-
4144
-        $this->_template_args['success'] = $success;
4145
-        $this->_return_json();
4146
-    }
4147
-
4148
-
4149
-    /**
4150
-     * Takes care of processing activating a messenger and preparing the appropriate response.
4151
-     *
4152
-     * @param string $messenger_name The name of the messenger being activated
4153
-     * @return bool
4154
-     * @throws DomainException
4155
-     * @throws EE_Error
4156
-     * @throws InvalidArgumentException
4157
-     * @throws ReflectionException
4158
-     * @throws InvalidDataTypeException
4159
-     * @throws InvalidInterfaceException
4160
-     */
4161
-    protected function _activate_messenger($messenger_name)
4162
-    {
4163
-        $active_messenger          = $this->_message_resource_manager->get_messenger($messenger_name);
4164
-        $message_types_to_activate = $active_messenger instanceof EE_Messenger
4165
-            ? $active_messenger->get_default_message_types()
4166
-            : [];
4167
-
4168
-        // ensure is active
4169
-        $this->_message_resource_manager->activate_messenger($active_messenger, $message_types_to_activate);
4170
-
4171
-        // set response_data for reload
4172
-        foreach ($message_types_to_activate as $message_type_name) {
4173
-            $message_type = $this->_message_resource_manager->get_message_type($message_type_name);
4174
-            if (
4175
-                $this->_message_resource_manager->is_message_type_active_for_messenger(
4176
-                    $messenger_name,
4177
-                    $message_type_name
4178
-                )
4179
-                && $message_type instanceof EE_message_type
4180
-            ) {
4181
-                $this->_template_args['data']['active_mts'][] = $message_type_name;
4182
-                if ($message_type->get_admin_settings_fields()) {
4183
-                    $this->_template_args['data']['mt_reload'][] = $message_type_name;
4184
-                }
4185
-            }
4186
-        }
4187
-
4188
-        // add success message for activating messenger
4189
-        return $this->_setup_response_message_for_activating_messenger_with_message_types($active_messenger);
4190
-    }
4191
-
4192
-
4193
-    /**
4194
-     * Takes care of processing deactivating a messenger and preparing the appropriate response.
4195
-     *
4196
-     * @param string $messenger_name The name of the messenger being activated
4197
-     * @return bool
4198
-     * @throws DomainException
4199
-     * @throws EE_Error
4200
-     * @throws InvalidArgumentException
4201
-     * @throws ReflectionException
4202
-     * @throws InvalidDataTypeException
4203
-     * @throws InvalidInterfaceException
4204
-     */
4205
-    protected function _deactivate_messenger($messenger_name)
4206
-    {
4207
-        $active_messenger = $this->_message_resource_manager->get_messenger($messenger_name);
4208
-        $this->_message_resource_manager->deactivate_messenger($messenger_name);
4209
-
4210
-        return $this->_setup_response_message_for_deactivating_messenger_with_message_types($active_messenger);
4211
-    }
4212
-
4213
-
4214
-    /**
4215
-     * Takes care of processing activating a message type for a messenger and preparing the appropriate response.
4216
-     *
4217
-     * @param string $messenger_name    The name of the messenger the message type is being activated for.
4218
-     * @param string $message_type_name The name of the message type being activated for the messenger
4219
-     * @return bool
4220
-     * @throws DomainException
4221
-     * @throws EE_Error
4222
-     * @throws InvalidArgumentException
4223
-     * @throws ReflectionException
4224
-     * @throws InvalidDataTypeException
4225
-     * @throws InvalidInterfaceException
4226
-     */
4227
-    protected function _activate_message_type_for_messenger($messenger_name, $message_type_name)
4228
-    {
4229
-        $active_messenger         = $this->_message_resource_manager->get_messenger($messenger_name);
4230
-        $message_type_to_activate = $this->_message_resource_manager->get_message_type($message_type_name);
4231
-
4232
-        // ensure is active
4233
-        $this->_message_resource_manager->activate_messenger($active_messenger, $message_type_name);
4234
-
4235
-        // set response for load
4236
-        if (
4237
-            $this->_message_resource_manager->is_message_type_active_for_messenger(
4238
-                $messenger_name,
4239
-                $message_type_name
4240
-            )
4241
-        ) {
4242
-            $this->_template_args['data']['active_mts'][] = $message_type_name;
4243
-            if ($message_type_to_activate->get_admin_settings_fields()) {
4244
-                $this->_template_args['data']['mt_reload'][] = $message_type_name;
4245
-            }
4246
-        }
4247
-
4248
-        return $this->_setup_response_message_for_activating_messenger_with_message_types(
4249
-            $active_messenger,
4250
-            $message_type_to_activate
4251
-        );
4252
-    }
4253
-
4254
-
4255
-    /**
4256
-     * Takes care of processing deactivating a message type for a messenger and preparing the appropriate response.
4257
-     *
4258
-     * @param string $messenger_name    The name of the messenger the message type is being deactivated for.
4259
-     * @param string $message_type_name The name of the message type being deactivated for the messenger
4260
-     * @return bool
4261
-     * @throws DomainException
4262
-     * @throws EE_Error
4263
-     * @throws InvalidArgumentException
4264
-     * @throws ReflectionException
4265
-     * @throws InvalidDataTypeException
4266
-     * @throws InvalidInterfaceException
4267
-     */
4268
-    protected function _deactivate_message_type_for_messenger($messenger_name, $message_type_name)
4269
-    {
4270
-        $active_messenger = $this->_message_resource_manager->get_messenger($messenger_name);
4271
-        /** @var EE_message_type $message_type_to_activate This will be present because it can't be toggled if it isn't */
4272
-        $message_type_to_deactivate = $this->_message_resource_manager->get_message_type($message_type_name);
4273
-        $this->_message_resource_manager->deactivate_message_type_for_messenger($message_type_name, $messenger_name);
4274
-
4275
-        return $this->_setup_response_message_for_deactivating_messenger_with_message_types(
4276
-            $active_messenger,
4277
-            $message_type_to_deactivate
4278
-        );
4279
-    }
4280
-
4281
-
4282
-    /**
4283
-     * This just initializes the defaults for activating messenger and message type responses.
4284
-     */
4285
-    protected function _prep_default_response_for_messenger_or_message_type_toggle()
4286
-    {
4287
-        $this->_template_args['data']['active_mts'] = [];
4288
-        $this->_template_args['data']['mt_reload']  = [];
4289
-    }
4290
-
4291
-
4292
-    /**
4293
-     * Setup appropriate response for activating a messenger and/or message types
4294
-     *
4295
-     * @param EE_messenger         $messenger
4296
-     * @param EE_message_type|null $message_type
4297
-     * @return bool
4298
-     * @throws DomainException
4299
-     * @throws EE_Error
4300
-     * @throws InvalidArgumentException
4301
-     * @throws ReflectionException
4302
-     * @throws InvalidDataTypeException
4303
-     * @throws InvalidInterfaceException
4304
-     */
4305
-    protected function _setup_response_message_for_activating_messenger_with_message_types(
4306
-        $messenger,
4307
-        EE_Message_Type $message_type = null
4308
-    ) {
4309
-        // if $messenger isn't a valid messenger object then get out.
4310
-        if (! $messenger instanceof EE_Messenger) {
4311
-            EE_Error::add_error(
4312
-                esc_html__('The messenger being activated is not a valid messenger', 'event_espresso'),
4313
-                __FILE__,
4314
-                __FUNCTION__,
4315
-                __LINE__
4316
-            );
4317
-            return false;
4318
-        }
4319
-        // activated
4320
-        if ($this->_template_args['data']['active_mts']) {
4321
-            EE_Error::overwrite_success();
4322
-            // activated a message type with the messenger
4323
-            if ($message_type instanceof EE_message_type) {
4324
-                EE_Error::add_success(
4325
-                    sprintf(
4326
-                        esc_html__(
4327
-                            '%s message type has been successfully activated with the %s messenger',
4328
-                            'event_espresso'
4329
-                        ),
4330
-                        ucwords($message_type->label['singular']),
4331
-                        ucwords($messenger->label['singular'])
4332
-                    )
4333
-                );
4334
-
4335
-                // if message type was invoice then let's make sure we activate the invoice payment method.
4336
-                if ($message_type->name === 'invoice') {
4337
-                    EE_Registry::instance()->load_lib('Payment_Method_Manager');
4338
-                    $pm = EE_Payment_Method_Manager::instance()->activate_a_payment_method_of_type('Invoice');
4339
-                    if ($pm instanceof EE_Payment_Method) {
4340
-                        EE_Error::add_attention(
4341
-                            esc_html__(
4342
-                                'Activating the invoice message type also automatically activates the invoice payment method.  If you do not wish the invoice payment method to be active, or to change its settings, visit the payment method admin page.',
4343
-                                'event_espresso'
4344
-                            )
4345
-                        );
4346
-                    }
4347
-                }
4348
-                // just toggles the entire messenger
4349
-            } else {
4350
-                EE_Error::add_success(
4351
-                    sprintf(
4352
-                        esc_html__('%s messenger has been successfully activated', 'event_espresso'),
4353
-                        ucwords($messenger->label['singular'])
4354
-                    )
4355
-                );
4356
-            }
4357
-
4358
-            return true;
4359
-
4360
-            // possible error condition. This will happen when our active_mts data is empty because it is validated for actual active
4361
-            // message types after the activation process.  However its possible some messengers don't HAVE any default_message_types
4362
-            // in which case we just give a success message for the messenger being successfully activated.
4363
-        } else {
4364
-            if (! $messenger->get_default_message_types()) {
4365
-                // messenger doesn't have any default message types so still a success.
4366
-                EE_Error::add_success(
4367
-                    sprintf(
4368
-                        esc_html__('%s messenger was successfully activated.', 'event_espresso'),
4369
-                        ucwords($messenger->label['singular'])
4370
-                    )
4371
-                );
4372
-
4373
-                return true;
4374
-            } else {
4375
-                EE_Error::add_error(
4376
-                    $message_type instanceof EE_message_type
4377
-                    ? sprintf(
4378
-                        esc_html__(
4379
-                            '%s message type was not successfully activated with the %s messenger',
4380
-                            'event_espresso'
4381
-                        ),
4382
-                        ucwords($message_type->label['singular']),
4383
-                        ucwords($messenger->label['singular'])
4384
-                    )
4385
-                    : sprintf(
4386
-                        esc_html__('%s messenger was not successfully activated', 'event_espresso'),
4387
-                        ucwords($messenger->label['singular'])
4388
-                    ),
4389
-                    __FILE__,
4390
-                    __FUNCTION__,
4391
-                    __LINE__
4392
-                );
4393
-
4394
-                return false;
4395
-            }
4396
-        }
4397
-    }
4398
-
4399
-
4400
-    /**
4401
-     * This sets up the appropriate response for deactivating a messenger and/or message type.
4402
-     *
4403
-     * @param EE_messenger         $messenger
4404
-     * @param EE_message_type|null $message_type
4405
-     * @return bool
4406
-     * @throws DomainException
4407
-     * @throws EE_Error
4408
-     * @throws InvalidArgumentException
4409
-     * @throws ReflectionException
4410
-     * @throws InvalidDataTypeException
4411
-     * @throws InvalidInterfaceException
4412
-     */
4413
-    protected function _setup_response_message_for_deactivating_messenger_with_message_types(
4414
-        $messenger,
4415
-        EE_message_type $message_type = null
4416
-    ) {
4417
-        EE_Error::overwrite_success();
4418
-
4419
-        // if $messenger isn't a valid messenger object then get out.
4420
-        if (! $messenger instanceof EE_Messenger) {
4421
-            EE_Error::add_error(
4422
-                esc_html__('The messenger being deactivated is not a valid messenger', 'event_espresso'),
4423
-                __FILE__,
4424
-                __FUNCTION__,
4425
-                __LINE__
4426
-            );
4427
-
4428
-            return false;
4429
-        }
4430
-
4431
-        if ($message_type instanceof EE_message_type) {
4432
-            $message_type_name = $message_type->name;
4433
-            EE_Error::add_success(
4434
-                sprintf(
4435
-                    esc_html__(
4436
-                        '%s message type has been successfully deactivated for the %s messenger.',
4437
-                        'event_espresso'
4438
-                    ),
4439
-                    ucwords($message_type->label['singular']),
4440
-                    ucwords($messenger->label['singular'])
4441
-                )
4442
-            );
4443
-        } else {
4444
-            $message_type_name = '';
4445
-            EE_Error::add_success(
4446
-                sprintf(
4447
-                    esc_html__('%s messenger has been successfully deactivated.', 'event_espresso'),
4448
-                    ucwords($messenger->label['singular'])
4449
-                )
4450
-            );
4451
-        }
4452
-
4453
-        // if messenger was html or message type was invoice then let's make sure we deactivate invoice payment method.
4454
-        if (
4455
-            $messenger->name === 'html'
4456
-            && (
4457
-                is_null($message_type)
4458
-                || $message_type_name === 'invoice'
4459
-            )
4460
-        ) {
4461
-            EE_Registry::instance()->load_lib('Payment_Method_Manager');
4462
-            $count_updated = EE_Payment_Method_Manager::instance()->deactivate_payment_method('invoice');
4463
-            if ($count_updated > 0) {
4464
-                $msg = $message_type_name === 'invoice'
4465
-                    ? esc_html__(
4466
-                        'Deactivating the invoice message type also automatically deactivates the invoice payment method. In order for invoices to be generated the invoice message type must be active. If you completed this action by mistake, simply reactivate the invoice message type and then visit the payment methods admin page to reactivate the invoice payment method.',
4467
-                        'event_espresso'
4468
-                    )
4469
-                    : esc_html__(
4470
-                        'Deactivating the html messenger also automatically deactivates the invoice payment method.  In order for invoices to be generated the html messenger must be be active.  If you completed this action by mistake, simply reactivate the html messenger, then visit the payment methods admin page to reactivate the invoice payment method.',
4471
-                        'event_espresso'
4472
-                    );
4473
-                EE_Error::add_attention($msg);
4474
-            }
4475
-        }
4476
-
4477
-        return true;
4478
-    }
4479
-
4480
-
4481
-    /**
4482
-     * handles updating a message type form on messenger activation IF the message type has settings fields. (via ajax)
4483
-     *
4484
-     * @throws DomainException
4485
-     * @throws EE_Error
4486
-     * @throws EE_Error
4487
-     */
4488
-    public function update_mt_form()
4489
-    {
4490
-        if (! $this->_active_messenger_name || ! $this->_active_message_type_name) {
4491
-            EE_Error::add_error(
4492
-                esc_html__('Require message type or messenger to send an updated form', 'event_espresso'),
4493
-                __FILE__,
4494
-                __FUNCTION__,
4495
-                __LINE__
4496
-            );
4497
-            $this->_return_json();
4498
-        }
4499
-
4500
-        $message_types = $this->get_installed_message_types();
4501
-        $message_type  = $message_types[ $this->_active_message_type_name ];
4502
-        $messenger     = $this->_message_resource_manager->get_active_messenger($this->_active_messenger_name);
4503
-        $content       = $this->_message_type_settings_content($message_type, $messenger, true);
4504
-
4505
-        $this->_template_args['success'] = true;
4506
-        $this->_template_args['content'] = $content;
4507
-        $this->_return_json();
4508
-    }
4509
-
4510
-
4511
-    /**
4512
-     * this handles saving the settings for a messenger or message type
4513
-     *
4514
-     * @throws EE_Error
4515
-     * @throws EE_Error
4516
-     */
4517
-    public function save_settings()
4518
-    {
4519
-        $type = $this->request->getRequestParam('type');
4520
-        if (! $type) {
4521
-            EE_Error::add_error(
4522
-                esc_html__(
4523
-                    'Cannot save settings because type is unknown (messenger settings or message type settings?)',
4524
-                    'event_espresso'
4525
-                ),
4526
-                __FILE__,
4527
-                __FUNCTION__,
4528
-                __LINE__
4529
-            );
4530
-            $this->_template_args['error'] = true;
4531
-            $this->_return_json();
4532
-        }
4533
-
4534
-
4535
-        if ($type === 'messenger') {
4536
-            // this should be an array.
4537
-            $settings  = $this->request->getRequestParam('messenger_settings', [], 'string', true);
4538
-            $messenger = $settings['messenger'];
4539
-            // remove messenger and message_types from settings array
4540
-            unset($settings['messenger'], $settings['message_types']);
4541
-            $this->_message_resource_manager->add_settings_for_messenger($messenger, $settings);
4542
-        } elseif ($type === 'message_type') {
4543
-            $settings     = $this->request->getRequestParam('message_type_settings', [], 'string', true);
4544
-            $messenger    = $settings['messenger'];
4545
-            $message_type = $settings['message_type'];
4546
-            // remove messenger and message_types from settings array
4547
-            unset($settings['messenger'], $settings['message_types']);
4548
-            $this->_message_resource_manager->add_settings_for_message_type($messenger, $message_type, $settings);
4549
-        }
4550
-
4551
-        // okay we should have the data all setup.  Now we just update!
4552
-        $success = $this->_message_resource_manager->update_active_messengers_option();
4553
-
4554
-        if ($success) {
4555
-            EE_Error::add_success(esc_html__('Settings updated', 'event_espresso'));
4556
-        } else {
4557
-            EE_Error::add_error(
4558
-                esc_html__('Settings did not get updated', 'event_espresso'),
4559
-                __FILE__,
4560
-                __FUNCTION__,
4561
-                __LINE__
4562
-            );
4563
-        }
4564
-
4565
-        $this->_template_args['success'] = $success;
4566
-        $this->_return_json();
4567
-    }
4568
-
4569
-
4570
-
4571
-
4572
-    /**  EE MESSAGE PROCESSING ACTIONS **/
4573
-
4574
-
4575
-    /**
4576
-     * This immediately generates any EE_Message ID's that are selected that are EEM_Message::status_incomplete
4577
-     * However, this does not send immediately, it just queues for sending.
4578
-     *
4579
-     * @throws EE_Error
4580
-     * @throws InvalidDataTypeException
4581
-     * @throws InvalidInterfaceException
4582
-     * @throws InvalidArgumentException
4583
-     * @throws ReflectionException
4584
-     * @since 4.9.0
4585
-     */
4586
-    protected function _generate_now()
4587
-    {
4588
-        EED_Messages::generate_now($this->_get_msg_ids_from_request());
4589
-        $this->_redirect_after_action(false, '', '', [], true);
4590
-    }
4591
-
4592
-
4593
-    /**
4594
-     * This immediately generates AND sends any EE_Message's selected that are EEM_Message::status_incomplete or that
4595
-     * are EEM_Message::status_resend or EEM_Message::status_idle
4596
-     *
4597
-     * @throws EE_Error
4598
-     * @throws InvalidDataTypeException
4599
-     * @throws InvalidInterfaceException
4600
-     * @throws InvalidArgumentException
4601
-     * @throws ReflectionException
4602
-     * @since 4.9.0
4603
-     */
4604
-    protected function _generate_and_send_now()
4605
-    {
4606
-        EED_Messages::generate_and_send_now($this->_get_msg_ids_from_request());
4607
-        $this->_redirect_after_action(false, '', '', [], true);
4608
-    }
4609
-
4610
-
4611
-    /**
4612
-     * This queues any EEM_Message::status_sent EE_Message ids in the request for resending.
4613
-     *
4614
-     * @throws EE_Error
4615
-     * @throws InvalidDataTypeException
4616
-     * @throws InvalidInterfaceException
4617
-     * @throws InvalidArgumentException
4618
-     * @throws ReflectionException
4619
-     * @since 4.9.0
4620
-     */
4621
-    protected function _queue_for_resending()
4622
-    {
4623
-        EED_Messages::queue_for_resending($this->_get_msg_ids_from_request());
4624
-        $this->_redirect_after_action(false, '', '', [], true);
4625
-    }
4626
-
4627
-
4628
-    /**
4629
-     *  This sends immediately any EEM_Message::status_idle or EEM_Message::status_resend messages in the queue
4630
-     *
4631
-     * @throws EE_Error
4632
-     * @throws InvalidDataTypeException
4633
-     * @throws InvalidInterfaceException
4634
-     * @throws InvalidArgumentException
4635
-     * @throws ReflectionException
4636
-     * @since 4.9.0
4637
-     */
4638
-    protected function _send_now()
4639
-    {
4640
-        EED_Messages::send_now($this->_get_msg_ids_from_request());
4641
-        $this->_redirect_after_action(false, '', '', [], true);
4642
-    }
4643
-
4644
-
4645
-    /**
4646
-     * Deletes EE_messages for IDs in the request.
4647
-     *
4648
-     * @throws EE_Error
4649
-     * @throws InvalidDataTypeException
4650
-     * @throws InvalidInterfaceException
4651
-     * @throws InvalidArgumentException
4652
-     * @since 4.9.0
4653
-     */
4654
-    protected function _delete_ee_messages()
4655
-    {
4656
-        $MSG_IDs       = $this->_get_msg_ids_from_request();
4657
-        $deleted_count = 0;
4658
-        foreach ($MSG_IDs as $MSG_ID) {
4659
-            if ($this->getMsgModel()->delete_by_ID($MSG_ID)) {
4660
-                $deleted_count++;
4661
-            }
4662
-        }
4663
-        if ($deleted_count) {
4664
-            EE_Error::add_success(
4665
-                esc_html(
4666
-                    _n(
4667
-                        'Message successfully deleted',
4668
-                        'Messages successfully deleted',
4669
-                        $deleted_count,
4670
-                        'event_espresso'
4671
-                    )
4672
-                )
4673
-            );
4674
-        } else {
4675
-            EE_Error::add_error(
4676
-                _n('The message was not deleted.', 'The messages were not deleted', count($MSG_IDs), 'event_espresso'),
4677
-                __FILE__,
4678
-                __FUNCTION__,
4679
-                __LINE__
4680
-            );
4681
-        }
4682
-        $this->_redirect_after_action(false, '', '', [], true);
4683
-    }
4684
-
4685
-
4686
-    /**
4687
-     *  This looks for 'MSG_ID' key in the request and returns an array of MSG_ID's if present.
4688
-     *
4689
-     * @return array
4690
-     * @since 4.9.0
4691
-     */
4692
-    protected function _get_msg_ids_from_request()
4693
-    {
4694
-        $MSG_IDs = $this->request->getRequestParam('MSG_ID', [], 'string', true);
4695
-        if (empty($MSG_IDs)) {
4696
-            return [];
4697
-        }
4698
-        // if 'MSG_ID' was just a single ID (not an array)
4699
-        // then $MSG_IDs will be something like [123] so $MSG_IDs[0] should be 123
4700
-        // otherwise, $MSG_IDs was already an array where message IDs were used as the keys
4701
-        return count($MSG_IDs) === 1 && isset($MSG_IDs[0])
4702
-            ? $MSG_IDs
4703
-            : array_keys($MSG_IDs);
4704
-    }
2713
+	}
2714
+
2715
+
2716
+	/**
2717
+	 * @param bool $new
2718
+	 * @throws EE_Error
2719
+	 * @throws ReflectionException
2720
+	 */
2721
+	protected function _insert_or_update_message_template($new = false)
2722
+	{
2723
+		$form_data    = $this->getMessageTemplateFormData();
2724
+		$GRP_ID       = $form_data['GRP_ID'];
2725
+		$messenger    = $form_data['MTP_messenger'];
2726
+		$message_type = $form_data['MTP_message_type'];
2727
+		$context      = $form_data['MTP_context'];
2728
+
2729
+		// if this is "new" then we need to generate the default contexts
2730
+		// for the selected messenger/message_type for user to edit.
2731
+		[$success, $query_args] = $new
2732
+			? $this->generateNewTemplates($GRP_ID, $messenger, $message_type)
2733
+			: $this->updateExistingTemplates($GRP_ID, $messenger, $message_type, $context, $form_data);
2734
+
2735
+		$success     = $success ? 1 : 0;
2736
+		$action_desc = $new ? 'created' : 'updated';
2737
+		$item_desc   = $this->generateUpdateDescription($messenger, $message_type, $context);
2738
+		$override    = $this->performTestSendAfterUpdate($messenger, $message_type, $context);
2739
+
2740
+		$this->_redirect_after_action($success, $item_desc, $action_desc, $query_args, $override);
2741
+	}
2742
+
2743
+
2744
+	/**
2745
+	 * retrieve and sanitize form data
2746
+	 *
2747
+	 * @return array
2748
+	 * @since 4.10.29.p
2749
+	 */
2750
+	protected function getMessageTemplateFormData()
2751
+	{
2752
+		return [
2753
+			'GRP_ID'           => $this->request->getRequestParam('GRP_ID', 0, 'int'),
2754
+			'MTP_context'      => strtolower($this->request->getRequestParam('MTP_context', '')),
2755
+			'MTP_messenger'    => strtolower($this->request->getRequestParam('MTP_messenger', '')),
2756
+			'MTP_message_type' => strtolower($this->request->getRequestParam('MTP_message_type', '')),
2757
+			'MTP_user_id'      => $this->request->getRequestParam('MTP_user_id', 0, 'int'),
2758
+			'MTP_is_global'    => $this->request->getRequestParam('MTP_is_global', 0, 'int'),
2759
+			'MTP_is_override'  => $this->request->getRequestParam('MTP_is_override', 0, 'int'),
2760
+			'MTP_deleted'      => $this->request->getRequestParam('MTP_deleted', 0, 'int'),
2761
+			'MTP_is_active'    => $this->request->getRequestParam('MTP_is_active', 0, 'int'),
2762
+		];
2763
+	}
2764
+
2765
+
2766
+	/**
2767
+	 * @param int    $GRP_ID
2768
+	 * @param string $messenger
2769
+	 * @param string $message_type
2770
+	 * @return array no return on AJAX requests
2771
+	 * @throws EE_Error
2772
+	 * @throws ReflectionException
2773
+	 * @since 4.10.29.p
2774
+	 */
2775
+	private function generateNewTemplates($GRP_ID, $messenger, $message_type)
2776
+	{
2777
+		$new_templates = $this->_generate_new_templates($messenger, [$message_type], $GRP_ID);
2778
+		$success       = ! empty($new_templates);
2779
+
2780
+		// we return things differently if doing ajax
2781
+		if ($this->request->isAjax()) {
2782
+			$this->_template_args['success'] = $success;
2783
+			$this->_template_args['error']   = ! $success;
2784
+			$this->_template_args['content'] = '';
2785
+			$this->_template_args['data']    = [
2786
+				'grpID'        => $new_templates['GRP_ID'],
2787
+				'templateName' => $new_templates['template_name'],
2788
+			];
2789
+			if ($success) {
2790
+				EE_Error::overwrite_success();
2791
+				EE_Error::add_success(
2792
+					esc_html__(
2793
+						'The new template has been created and automatically selected for this event.  You can edit the new template by clicking the edit button.  Note before this template is assigned to this event, the event must be saved.',
2794
+						'event_espresso'
2795
+					)
2796
+				);
2797
+			}
2798
+			$this->_return_json();
2799
+		}
2800
+		return [
2801
+			$success,
2802
+			// 'query_args'
2803
+			[
2804
+				'id'      => $new_templates['GRP_ID'],
2805
+				'context' => $new_templates['MTP_context'],
2806
+				'action'  => 'edit_message_template',
2807
+			],
2808
+		];
2809
+	}
2810
+
2811
+
2812
+	/**
2813
+	 * @param int    $GRP_ID
2814
+	 * @param string $messenger
2815
+	 * @param string $message_type
2816
+	 * @param string $context
2817
+	 * @param array  $form_data
2818
+	 * @return array
2819
+	 * @throws EE_Error
2820
+	 * @since 4.10.29.p
2821
+	 */
2822
+	private function updateExistingTemplates(
2823
+		$GRP_ID,
2824
+		$messenger,
2825
+		$message_type,
2826
+		$context,
2827
+		array $form_data
2828
+	) {
2829
+		$success         = false;
2830
+		$template_fields = $this->getTemplateFields();
2831
+		if ($template_fields) {
2832
+			// if field data is valid, then success will be true
2833
+			$success = $this->validateTemplateFields(
2834
+				$messenger,
2835
+				$message_type,
2836
+				$context,
2837
+				$template_fields
2838
+			);
2839
+			if ($success) {
2840
+				$field_data = [];
2841
+				foreach ($template_fields as $template_field => $content) {
2842
+					// combine top-level form data with content for this field
2843
+					$field_data = $this->getTemplateFieldFormData($content, $form_data);
2844
+					$success    = $this->updateMessageTemplates($template_field, $field_data) ? $success : false;
2845
+				}
2846
+				// we can use the last set_column_values for the MTPG update
2847
+				// (because its the same for all of these specific MTPs)
2848
+				$success = $this->updateMessageTemplateGroup($field_data) ? $success : false;
2849
+			}
2850
+		}
2851
+
2852
+		return [
2853
+			$success,
2854
+			// 'query_args'
2855
+			[
2856
+				'id'      => $GRP_ID,
2857
+				'context' => $context,
2858
+				'action'  => 'edit_message_template',
2859
+			],
2860
+		];
2861
+	}
2862
+
2863
+
2864
+	/**
2865
+	 * @return array
2866
+	 * @since 4.10.29.p
2867
+	 */
2868
+	private function getTemplateFields()
2869
+	{
2870
+		$template_fields = $this->request->getRequestParam('MTP_template_fields', null, 'html', true);
2871
+		if (empty($template_fields)) {
2872
+			EE_Error::add_error(
2873
+				esc_html__(
2874
+					'There was a problem saving the template fields from the form because I didn\'t receive any actual template field data.',
2875
+					'event_espresso'
2876
+				),
2877
+				__FILE__,
2878
+				__FUNCTION__,
2879
+				__LINE__
2880
+			);
2881
+			return null;
2882
+		}
2883
+		// messages content is expected to be escaped
2884
+		return EEH_Array::addSlashesRecursively($template_fields);
2885
+	}
2886
+
2887
+
2888
+	/**
2889
+	 * @param string $messenger
2890
+	 * @param string $message_type
2891
+	 * @param string $context
2892
+	 * @param array  $template_fields
2893
+	 * @return bool
2894
+	 * @throws EE_Error
2895
+	 * @since   4.10.29.p
2896
+	 */
2897
+	private function validateTemplateFields(
2898
+		$messenger,
2899
+		$message_type,
2900
+		$context,
2901
+		array $template_fields
2902
+	) {
2903
+		// first validate all fields!
2904
+		// this filter allows client code to add its own validation to the template fields as well.
2905
+		// returning an empty array means everything passed validation.
2906
+		// errors in validation should be represented in an array with the following shape:
2907
+		// array(
2908
+		//   'fieldname' => array(
2909
+		//          'msg' => 'error message'
2910
+		//          'value' => 'value for field producing error'
2911
+		// )
2912
+		$custom_validation = (array) apply_filters(
2913
+			'FHEE__Messages_Admin_Page___insert_or_update_message_template__validates',
2914
+			[],
2915
+			$template_fields,
2916
+			$context,
2917
+			$messenger,
2918
+			$message_type
2919
+		);
2920
+
2921
+		$system_validation = $this->getMtgModel()->validate(
2922
+			$template_fields,
2923
+			$context,
2924
+			$messenger,
2925
+			$message_type
2926
+		);
2927
+
2928
+		$system_validation = ! is_array($system_validation) && $system_validation ? [] : $system_validation;
2929
+		$validates         = array_merge($custom_validation, $system_validation);
2930
+
2931
+		// if $validate returned error messages (i.e. is_array()) then we need to process them and setup an
2932
+		// appropriate response. HMM, dang this isn't correct, $validates will ALWAYS be an array.
2933
+		//  WE need to make sure there is no actual error messages in validates.
2934
+		if (empty($validates)) {
2935
+			return true;
2936
+		}
2937
+
2938
+		// add the transient so when the form loads we know which fields to highlight
2939
+		$this->_add_transient('edit_message_template', $validates);
2940
+		// setup notices
2941
+		foreach ($validates as $error) {
2942
+			if (isset($error['msg'])) {
2943
+				EE_Error::add_error($error['msg'], __FILE__, __FUNCTION__, __LINE__);
2944
+			}
2945
+		}
2946
+		return false;
2947
+	}
2948
+
2949
+
2950
+	/**
2951
+	 * @param array $field_data
2952
+	 * @param array $form_data
2953
+	 * @return array
2954
+	 * @since   4.10.29.p
2955
+	 */
2956
+	private function getTemplateFieldFormData(array $field_data, array $form_data)
2957
+	{
2958
+		return $form_data + [
2959
+				'MTP_ID'             => $field_data['MTP_ID'],
2960
+				'MTP_template_field' => $field_data['name'],
2961
+				// if they aren't allowed to use all JS, restrict them to standard allowed post tags
2962
+				'MTP_content'        => ! current_user_can('unfiltered_html')
2963
+					? $this->sanitizeMessageTemplateContent($field_data['content'])
2964
+					: $field_data['content'],
2965
+			];
2966
+	}
2967
+
2968
+
2969
+	/**
2970
+	 * @param string $template_field
2971
+	 * @param array  $form_data
2972
+	 * @return bool
2973
+	 * @throws EE_Error
2974
+	 * @since 4.10.29.p
2975
+	 */
2976
+	private function updateMessageTemplates($template_field, array $form_data)
2977
+	{
2978
+		$MTP_ID                  = $form_data['MTP_ID'];
2979
+		$message_template_fields = [
2980
+			'GRP_ID'             => $form_data['GRP_ID'],
2981
+			'MTP_template_field' => $form_data['MTP_template_field'],
2982
+			'MTP_context'        => $form_data['MTP_context'],
2983
+			'MTP_content'        => $form_data['MTP_content'],
2984
+		];
2985
+
2986
+		$hasMtpID = ! empty($MTP_ID);
2987
+		// if we have a MTP_ID for this field then update it, otherwise insert.
2988
+		// this has already been through the template field validator and sanitized, so it will be
2989
+		// safe to insert this field.  Why insert?  This typically happens when we introduce a new
2990
+		// message template field in a messenger/message type and existing users don't have the
2991
+		// default setup for it.
2992
+		// @link https://events.codebasehq.com/projects/event-espresso/tickets/9465
2993
+		$updated = $hasMtpID
2994
+			? $this->getMtpModel()->update($message_template_fields, [['MTP_ID' => $MTP_ID]])
2995
+			: $this->getMtpModel()->insert($message_template_fields);
2996
+
2997
+		$insert_failed = ! $hasMtpID && ! $updated;
2998
+		// updates will return 0 if the field was not changed (ie: no changes = nothing actually updated)
2999
+		// but we won't consider that a problem, but if it returns false, then something went BOOM!
3000
+		$update_failed = $hasMtpID && $updated === false;
3001
+
3002
+		if ($insert_failed || $update_failed) {
3003
+			EE_Error::add_error(
3004
+				sprintf(
3005
+					esc_html__('%s field was NOT updated for some reason', 'event_espresso'),
3006
+					$template_field
3007
+				),
3008
+				__FILE__,
3009
+				__FUNCTION__,
3010
+				__LINE__
3011
+			);
3012
+			return false;
3013
+		}
3014
+		return true;
3015
+	}
3016
+
3017
+
3018
+	/**
3019
+	 * @param array $form_data
3020
+	 * @return bool
3021
+	 * @throws EE_Error
3022
+	 * @since 4.10.29.p
3023
+	 */
3024
+	private function updateMessageTemplateGroup(array $form_data)
3025
+	{
3026
+		$GRP_ID  = $form_data['GRP_ID'];
3027
+		$updated = $this->getMtgModel()->update(
3028
+		// fields and values
3029
+			[
3030
+				'MTP_user_id'      => $form_data['MTP_user_id'],
3031
+				'MTP_messenger'    => $form_data['MTP_messenger'],
3032
+				'MTP_message_type' => $form_data['MTP_message_type'],
3033
+				'MTP_is_global'    => $form_data['MTP_is_global'],
3034
+				'MTP_is_override'  => $form_data['MTP_is_override'],
3035
+				'MTP_deleted'      => $form_data['MTP_deleted'],
3036
+				'MTP_is_active'    => $form_data['MTP_is_active'],
3037
+				'MTP_name'         => $this->request->getRequestParam('ee_msg_non_global_fields[MTP_name]', ''),
3038
+				'MTP_description'  => $this->request->getRequestParam(
3039
+					'ee_msg_non_global_fields[MTP_description]',
3040
+					''
3041
+				),
3042
+			],
3043
+			// where
3044
+			[['GRP_ID' => $GRP_ID]]
3045
+		);
3046
+
3047
+		if ($updated === false) {
3048
+			EE_Error::add_error(
3049
+				sprintf(
3050
+					esc_html__(
3051
+						'The Message Template Group (%d) was NOT updated for some reason',
3052
+						'event_espresso'
3053
+					),
3054
+					$form_data['GRP_ID']
3055
+				),
3056
+				__FILE__,
3057
+				__FUNCTION__,
3058
+				__LINE__
3059
+			);
3060
+			return false;
3061
+		}
3062
+		// k now we need to ensure the template_pack and template_variation fields are set.
3063
+		$template_pack      = $this->request->getRequestParam('MTP_template_pack', 'default');
3064
+		$template_variation = $this->request->getRequestParam('MTP_template_variation', 'default');
3065
+
3066
+		$message_template_group = $this->getMtgModel()->get_one_by_ID($GRP_ID);
3067
+		if ($message_template_group instanceof EE_Message_Template_Group) {
3068
+			$message_template_group->set_template_pack_name($template_pack);
3069
+			$message_template_group->set_template_pack_variation($template_variation);
3070
+		}
3071
+		return true;
3072
+	}
3073
+
3074
+
3075
+	/**
3076
+	 * recursively runs wp_kses() on message template content in a model safe manner
3077
+	 *
3078
+	 * @param array|string $content
3079
+	 * @return array|string
3080
+	 * @since   4.10.29.p
3081
+	 */
3082
+	private function sanitizeMessageTemplateContent($content)
3083
+	{
3084
+		if (is_array($content)) {
3085
+			foreach ($content as $key => $value) {
3086
+				$content[ $key ] = $this->sanitizeMessageTemplateContent($value);
3087
+			}
3088
+			return $content;
3089
+		}
3090
+		// remove slashes so wp_kses() works properly
3091
+		// wp_kses_stripslashes() only removes slashes from double-quotes,
3092
+		// so attributes using single quotes always appear invalid.
3093
+		$content = stripslashes($content);
3094
+		$content = wp_kses($content, wp_kses_allowed_html('post'));
3095
+		// But currently the models expect slashed data, so after wp_kses()
3096
+		// runs we need to re-slash the data. Sheesh.
3097
+		// See https://events.codebasehq.com/projects/event-espresso/tickets/11211#update-47321587
3098
+		return addslashes($content);
3099
+	}
3100
+
3101
+
3102
+	/**
3103
+	 * @param string $messenger
3104
+	 * @param string $message_type
3105
+	 * @param string $context
3106
+	 * @return string
3107
+	 * @since 4.10.29.p
3108
+	 */
3109
+	private function generateUpdateDescription($messenger, $message_type, $context)
3110
+	{
3111
+		// need the message type and messenger objects to be able to use the labels for the notices
3112
+		$messenger_object = $this->_message_resource_manager->get_messenger($messenger);
3113
+		$messenger_label  = $messenger_object instanceof EE_messenger
3114
+			? ucwords($messenger_object->label['singular'])
3115
+			: '';
3116
+
3117
+		$message_type_object = $this->_message_resource_manager->get_message_type($message_type);
3118
+		$message_type_label  = $message_type_object instanceof EE_message_type
3119
+			? ucwords($message_type_object->label['singular'])
3120
+			: '';
3121
+
3122
+		$context   = ucwords(str_replace('_', ' ', $context));
3123
+		$item_desc = $messenger_label && $message_type_label
3124
+			? $messenger_label . ' ' . $message_type_label . ' ' . $context . ' '
3125
+			: '';
3126
+		$item_desc .= 'Message Template';
3127
+		return $item_desc;
3128
+	}
3129
+
3130
+
3131
+	/**
3132
+	 * @param string $messenger
3133
+	 * @param string $message_type
3134
+	 * @param string $context
3135
+	 * @return bool
3136
+	 * @throws EE_Error
3137
+	 * @throws ReflectionException
3138
+	 * @since 4.10.29.p
3139
+	 */
3140
+	private function performTestSendAfterUpdate($messenger, $message_type, $context)
3141
+	{
3142
+		// was a test send triggered?
3143
+		if ($this->request->requestParamIsSet('test_button')) {
3144
+			EE_Error::overwrite_success();
3145
+			$this->_do_test_send($context, $messenger, $message_type);
3146
+			return true;
3147
+		}
3148
+		return false;
3149
+	}
3150
+
3151
+
3152
+	/**
3153
+	 * processes a test send request to do an actual messenger delivery test for the given message template being tested
3154
+	 *
3155
+	 * @param string $context      what context being tested
3156
+	 * @param string $messenger    messenger being tested
3157
+	 * @param string $message_type message type being tested
3158
+	 * @throws EE_Error
3159
+	 * @throws InvalidArgumentException
3160
+	 * @throws InvalidDataTypeException
3161
+	 * @throws InvalidInterfaceException
3162
+	 * @throws ReflectionException
3163
+	 */
3164
+	protected function _do_test_send($context, $messenger, $message_type)
3165
+	{
3166
+		// set things up for preview
3167
+		$this->request->setRequestParam('messenger', $messenger);
3168
+		$this->request->setRequestParam('message_type', $message_type);
3169
+		$this->request->setRequestParam('context', $context);
3170
+		$GRP_ID = $this->request->getRequestParam('GRP_ID', 0, 'int');
3171
+		$this->request->setRequestParam('GRP_ID', $GRP_ID);
3172
+
3173
+		$active_messenger  = $this->_message_resource_manager->get_active_messenger($messenger);
3174
+		$test_settings_fld = $this->request->getRequestParam('test_settings_fld', [], 'string', true);
3175
+
3176
+		// let's save any existing fields that might be required by the messenger
3177
+		if (
3178
+			! empty($test_settings_fld)
3179
+			&& $active_messenger instanceof EE_messenger
3180
+			&& apply_filters(
3181
+				'FHEE__Messages_Admin_Page__do_test_send__set_existing_test_settings',
3182
+				true,
3183
+				$test_settings_fld,
3184
+				$active_messenger
3185
+			)
3186
+		) {
3187
+			$active_messenger->set_existing_test_settings($test_settings_fld);
3188
+		}
3189
+
3190
+		/**
3191
+		 * Use filter to add additional controls on whether message can send or not
3192
+		 */
3193
+		if (
3194
+			apply_filters(
3195
+				'FHEE__Messages_Admin_Page__do_test_send__can_send',
3196
+				true,
3197
+				$context,
3198
+				$this->request->requestParams(),
3199
+				$messenger,
3200
+				$message_type
3201
+			)
3202
+		) {
3203
+			if (EEM_Event::instance()->count() > 0) {
3204
+				$success = $this->_preview_message(true);
3205
+				if ($success) {
3206
+					EE_Error::add_success(esc_html__('Test message sent', 'event_espresso'));
3207
+				} else {
3208
+					EE_Error::add_error(
3209
+						esc_html__('The test message was not sent', 'event_espresso'),
3210
+						__FILE__,
3211
+						__FUNCTION__,
3212
+						__LINE__
3213
+					);
3214
+				}
3215
+			} else {
3216
+				$this->noEventsErrorMessage(true);
3217
+			}
3218
+		}
3219
+	}
3220
+
3221
+
3222
+	/**
3223
+	 * _generate_new_templates
3224
+	 * This will handle the messenger, message_type selection when "adding a new custom template" for an event and will
3225
+	 * automatically create the defaults for the event.  The user would then be redirected to edit the default context
3226
+	 * for the event.
3227
+	 *
3228
+	 *
3229
+	 * @param string $messenger      the messenger we are generating templates for
3230
+	 * @param array  $message_types  array of message types that the templates are generated for.
3231
+	 * @param int    $GRP_ID         If this is a custom template being generated then a GRP_ID needs to be included to
3232
+	 *                               indicate the message_template_group being used as the base.
3233
+	 *
3234
+	 * @param bool   $global
3235
+	 *
3236
+	 * @return array|bool array of data required for the redirect to the correct edit page or bool if
3237
+	 *                               encountering problems.
3238
+	 * @throws EE_Error
3239
+	 * @throws ReflectionException
3240
+	 */
3241
+	protected function _generate_new_templates($messenger, $message_types, $GRP_ID = 0, $global = false)
3242
+	{
3243
+		// if no $message_types are given then that's okay... this may be a messenger that just adds shortcodes, so we
3244
+		// just don't generate any templates.
3245
+		if (empty($message_types)) {
3246
+			return [];
3247
+		}
3248
+
3249
+		$templates = EEH_MSG_Template::generate_new_templates($messenger, $message_types, $GRP_ID, $global);
3250
+		return $templates[0];
3251
+	}
3252
+
3253
+
3254
+	/**
3255
+	 * [_trash_or_restore_message_template]
3256
+	 *
3257
+	 * @param boolean $trash  whether to move an item to trash/restore (TRUE) or restore it (FALSE)
3258
+	 * @param boolean $all    whether this is going to trash/restore all contexts within a template group (TRUE) OR just
3259
+	 *                        an individual context (FALSE).
3260
+	 * @return void
3261
+	 * @throws EE_Error
3262
+	 * @throws InvalidArgumentException
3263
+	 * @throws InvalidDataTypeException
3264
+	 * @throws InvalidInterfaceException
3265
+	 */
3266
+	protected function _trash_or_restore_message_template($trash = true, $all = false)
3267
+	{
3268
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3269
+
3270
+		$success = 1;
3271
+
3272
+		// incoming GRP_IDs
3273
+		if ($all) {
3274
+			// Checkboxes
3275
+			$checkboxes = $this->request->getRequestParam('checkbox', [], 'int', true);
3276
+			if (! empty($checkboxes)) {
3277
+				// if array has more than one element then success message should be plural.
3278
+				// todo: what about nonce?
3279
+				$success = count($checkboxes) > 1 ? 2 : 1;
3280
+
3281
+				// cycle through checkboxes
3282
+				while (list($GRP_ID, $value) = each($checkboxes)) {
3283
+					$trashed_or_restored = $trash
3284
+						? $this->getMtgModel()->delete_by_ID($GRP_ID)
3285
+						: $this->getMtgModel()->restore_by_ID($GRP_ID);
3286
+					if (! $trashed_or_restored) {
3287
+						$success = 0;
3288
+					}
3289
+				}
3290
+			} else {
3291
+				// grab single GRP_ID and handle
3292
+				$GRP_ID = $this->request->getRequestParam('id', 0, 'int');
3293
+				if (! empty($GRP_ID)) {
3294
+					$trashed_or_restored = $trash
3295
+						? $this->getMtgModel()->delete_by_ID($GRP_ID)
3296
+						: $this->getMtgModel()->restore_by_ID($GRP_ID);
3297
+					if (! $trashed_or_restored) {
3298
+						$success = 0;
3299
+					}
3300
+				} else {
3301
+					$success = 0;
3302
+				}
3303
+			}
3304
+		}
3305
+
3306
+		$action_desc = $trash
3307
+			? esc_html__('moved to the trash', 'event_espresso')
3308
+			: esc_html__('restored', 'event_espresso');
3309
+
3310
+		$template_switch = $this->request->getRequestParam('template_switch', false, 'bool');
3311
+		$action_desc     = $template_switch ? esc_html__('switched', 'event_espresso') : $action_desc;
3312
+
3313
+		$item_desc = $all ? _n(
3314
+			'Message Template Group',
3315
+			'Message Template Groups',
3316
+			$success,
3317
+			'event_espresso'
3318
+		) : _n('Message Template Context', 'Message Template Contexts', $success, 'event_espresso');
3319
+
3320
+		$item_desc = $template_switch
3321
+			? _n('template', 'templates', $success, 'event_espresso')
3322
+			: $item_desc;
3323
+
3324
+		$this->_redirect_after_action($success, $item_desc, $action_desc, []);
3325
+	}
3326
+
3327
+
3328
+	/**
3329
+	 * [_delete_message_template]
3330
+	 * NOTE: this handles not only the deletion of the groups but also all the templates belonging to that group.
3331
+	 *
3332
+	 * @return void
3333
+	 * @throws EE_Error
3334
+	 * @throws InvalidArgumentException
3335
+	 * @throws InvalidDataTypeException
3336
+	 * @throws InvalidInterfaceException
3337
+	 * @throws ReflectionException
3338
+	 */
3339
+	protected function _delete_message_template()
3340
+	{
3341
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3342
+
3343
+		// checkboxes
3344
+		$checkboxes = $this->request->getRequestParam('checkbox', [], 'int', true);
3345
+		if (! empty($checkboxes)) {
3346
+			// if array has more than one element then success message should be plural
3347
+			$success = count($checkboxes) > 1 ? 2 : 1;
3348
+
3349
+			// cycle through bulk action checkboxes
3350
+			while (list($GRP_ID, $value) = each($checkboxes)) {
3351
+				$success = $this->_delete_mtp_permanently($GRP_ID) ? $success : false;
3352
+			}
3353
+		} else {
3354
+			// grab single grp_id and delete
3355
+			$GRP_ID  = $this->request->getRequestParam('id', 0, 'int');
3356
+			$success = $this->_delete_mtp_permanently($GRP_ID);
3357
+		}
3358
+
3359
+		$this->_redirect_after_action($success, 'Message Templates', 'deleted', []);
3360
+	}
3361
+
3362
+
3363
+	/**
3364
+	 * helper for permanently deleting a mtP group and all related message_templates
3365
+	 *
3366
+	 * @param int  $GRP_ID        The group being deleted
3367
+	 * @param bool $include_group whether to delete the Message Template Group as well.
3368
+	 * @return bool boolean to indicate the success of the deletes or not.
3369
+	 * @throws EE_Error
3370
+	 * @throws InvalidArgumentException
3371
+	 * @throws InvalidDataTypeException
3372
+	 * @throws InvalidInterfaceException
3373
+	 * @throws ReflectionException
3374
+	 * @throws ReflectionException
3375
+	 */
3376
+	private function _delete_mtp_permanently($GRP_ID, $include_group = true)
3377
+	{
3378
+		$success = true;
3379
+		// first let's GET this group
3380
+		$MTG = $this->getMtgModel()->get_one_by_ID($GRP_ID);
3381
+		// then delete permanently all the related Message Templates
3382
+		$deleted = $MTG->delete_related_permanently('Message_Template');
3383
+
3384
+		if ($deleted === 0) {
3385
+			$success = false;
3386
+		}
3387
+
3388
+		// now delete permanently this particular group
3389
+
3390
+		if ($include_group && ! $MTG->delete_permanently()) {
3391
+			$success = false;
3392
+		}
3393
+
3394
+		return $success;
3395
+	}
3396
+
3397
+
3398
+	/**
3399
+	 *    _learn_more_about_message_templates_link
3400
+	 *
3401
+	 * @access protected
3402
+	 * @return string
3403
+	 */
3404
+	protected function _learn_more_about_message_templates_link()
3405
+	{
3406
+		return '<a class="hidden" style="margin:0 20px; cursor:pointer; font-size:12px;" >'
3407
+			   . esc_html__('learn more about how message templates works', 'event_espresso')
3408
+			   . '</a>';
3409
+	}
3410
+
3411
+
3412
+	/**
3413
+	 * Used for setting up messenger/message type activation.  This loads up the initial view.  The rest is handled by
3414
+	 * ajax and other routes.
3415
+	 *
3416
+	 * @return void
3417
+	 * @throws DomainException
3418
+	 * @throws EE_Error
3419
+	 */
3420
+	protected function _settings()
3421
+	{
3422
+		$this->_set_m_mt_settings();
3423
+
3424
+		// let's setup the messenger tabs
3425
+		$this->_template_args['admin_page_header'] = EEH_Tabbed_Content::tab_text_links(
3426
+			$this->_m_mt_settings['messenger_tabs'],
3427
+			'messenger_links',
3428
+			'|',
3429
+			$this->request->getRequestParam('selected_messenger', 'email')
3430
+		);
3431
+
3432
+		$this->_template_args['before_admin_page_content'] = '<div class="ui-widget ui-helper-clearfix">';
3433
+		$this->_template_args['after_admin_page_content']  = '</div><!-- end .ui-widget -->';
3434
+
3435
+		$this->display_admin_page_with_sidebar();
3436
+	}
3437
+
3438
+
3439
+	/**
3440
+	 * This sets the $_m_mt_settings property for when needed (used on the Messages settings page)
3441
+	 *
3442
+	 * @access protected
3443
+	 * @return void
3444
+	 * @throws DomainException
3445
+	 */
3446
+	protected function _set_m_mt_settings()
3447
+	{
3448
+		// first if this is already set then lets get out no need to regenerate data.
3449
+		if (! empty($this->_m_mt_settings)) {
3450
+			return;
3451
+		}
3452
+
3453
+		// get all installed messengers and message_types
3454
+		$messengers    = $this->_message_resource_manager->installed_messengers();
3455
+		$message_types = $this->_message_resource_manager->installed_message_types();
3456
+
3457
+
3458
+		// assemble the array for the _tab_text_links helper
3459
+
3460
+		foreach ($messengers as $messenger) {
3461
+			$active = $this->_message_resource_manager->is_messenger_active($messenger->name);
3462
+			$class = 'ee-messenger-' .  sanitize_key($messenger->label['singular']);
3463
+			$this->_m_mt_settings['messenger_tabs'][ $messenger->name ] = [
3464
+				'label' => ucwords($messenger->label['singular']),
3465
+				'class' => $active ? "{$class} messenger-active" : $class,
3466
+				'href'  => $messenger->name,
3467
+				'title' => esc_html__('Modify this Messenger', 'event_espresso'),
3468
+				'slug'  => $messenger->name,
3469
+				'obj'   => $messenger,
3470
+				'icon' => $active
3471
+					? '<span class="dashicons dashicons-yes-alt"></span>'
3472
+					: '<span class="dashicons dashicons-remove"></span>',
3473
+			];
3474
+
3475
+
3476
+			$message_types_for_messenger = $messenger->get_valid_message_types();
3477
+
3478
+			foreach ($message_types as $message_type) {
3479
+				// first we need to verify that this message type is valid with this messenger. Cause if it isn't then
3480
+				// it shouldn't show in either the inactive OR active metabox.
3481
+				if (! in_array($message_type->name, $message_types_for_messenger, true)) {
3482
+					continue;
3483
+				}
3484
+
3485
+				$a_or_i = $this->_message_resource_manager->is_message_type_active_for_messenger(
3486
+					$messenger->name,
3487
+					$message_type->name
3488
+				)
3489
+					? 'active'
3490
+					: 'inactive';
3491
+
3492
+				$this->_m_mt_settings['message_type_tabs'][ $messenger->name ][ $a_or_i ][ $message_type->name ] = [
3493
+					'label'    => ucwords($message_type->label['singular']),
3494
+					'class'    => 'message-type-' . $a_or_i,
3495
+					'slug_id'  => $message_type->name . '-messagetype-' . $messenger->name,
3496
+					'mt_nonce' => wp_create_nonce($message_type->name . '_nonce'),
3497
+					'href'     => 'espresso_' . $message_type->name . '_message_type_settings',
3498
+					'title'    => $a_or_i === 'active'
3499
+						? esc_html__('Drag this message type to the Inactive window to deactivate', 'event_espresso')
3500
+						: esc_html__('Drag this message type to the messenger to activate', 'event_espresso'),
3501
+					'content'  => $a_or_i === 'active'
3502
+						? $this->_message_type_settings_content($message_type, $messenger, true)
3503
+						: $this->_message_type_settings_content($message_type, $messenger),
3504
+					'slug'     => $message_type->name,
3505
+					'active'   => $a_or_i === 'active',
3506
+					'obj'      => $message_type,
3507
+				];
3508
+			}
3509
+		}
3510
+	}
3511
+
3512
+
3513
+	/**
3514
+	 * This just prepares the content for the message type settings
3515
+	 *
3516
+	 * @param EE_message_type $message_type The message type object
3517
+	 * @param EE_messenger    $messenger    The messenger object
3518
+	 * @param boolean         $active       Whether the message type is active or not
3519
+	 * @return string html output for the content
3520
+	 * @throws DomainException
3521
+	 */
3522
+	protected function _message_type_settings_content($message_type, $messenger, $active = false)
3523
+	{
3524
+		// get message type fields
3525
+		$fields                                         = $message_type->get_admin_settings_fields();
3526
+		$settings_template_args['template_form_fields'] = '';
3527
+
3528
+		if (! empty($fields) && $active) {
3529
+			$existing_settings = $message_type->get_existing_admin_settings($messenger->name);
3530
+			foreach ($fields as $fldname => $fldprops) {
3531
+				$field_id                         = $messenger->name . '-' . $message_type->name . '-' . $fldname;
3532
+				$template_form_field[ $field_id ] = [
3533
+					'name'       => 'message_type_settings[' . $fldname . ']',
3534
+					'label'      => $fldprops['label'],
3535
+					'input'      => $fldprops['field_type'],
3536
+					'type'       => $fldprops['value_type'],
3537
+					'required'   => $fldprops['required'],
3538
+					'validation' => $fldprops['validation'],
3539
+					'value'      => isset($existing_settings[ $fldname ])
3540
+						? $existing_settings[ $fldname ]
3541
+						: $fldprops['default'],
3542
+					'options'    => isset($fldprops['options'])
3543
+						? $fldprops['options']
3544
+						: [],
3545
+					'default'    => isset($existing_settings[ $fldname ])
3546
+						? $existing_settings[ $fldname ]
3547
+						: $fldprops['default'],
3548
+					'css_class'  => 'no-drag',
3549
+					'format'     => $fldprops['format'],
3550
+				];
3551
+			}
3552
+
3553
+
3554
+			$settings_template_args['template_form_fields'] = ! empty($template_form_field)
3555
+				? $this->_generate_admin_form_fields(
3556
+					$template_form_field,
3557
+					'string',
3558
+					'ee_mt_activate_form'
3559
+				)
3560
+				: '';
3561
+		}
3562
+
3563
+		$settings_template_args['description'] = $message_type->description;
3564
+		// we also need some hidden fields
3565
+		$hidden_fields = [
3566
+			'message_type_settings[messenger]' . $message_type->name    => [
3567
+				'type'  => 'hidden',
3568
+				'value' => $messenger->name,
3569
+			],
3570
+			'message_type_settings[message_type]' . $message_type->name => [
3571
+				'type'  => 'hidden',
3572
+				'value' => $message_type->name,
3573
+			],
3574
+			'type' . $message_type->name                                => [
3575
+				'type'  => 'hidden',
3576
+				'value' => 'message_type',
3577
+			],
3578
+		];
3579
+
3580
+		$settings_template_args['hidden_fields'] = $this->_generate_admin_form_fields(
3581
+			$hidden_fields,
3582
+			'array'
3583
+		);
3584
+		$settings_template_args['show_form']     = empty($settings_template_args['template_form_fields'])
3585
+			? ' hidden'
3586
+			: '';
3587
+
3588
+
3589
+		$template = EE_MSG_TEMPLATE_PATH . 'ee_msg_mt_settings_content.template.php';
3590
+		return EEH_Template::display_template($template, $settings_template_args, true);
3591
+	}
3592
+
3593
+
3594
+	/**
3595
+	 * Generate all the metaboxes for the message types and register them for the messages settings page.
3596
+	 *
3597
+	 * @access protected
3598
+	 * @return void
3599
+	 * @throws DomainException
3600
+	 */
3601
+	protected function _messages_settings_metaboxes()
3602
+	{
3603
+		$this->_set_m_mt_settings();
3604
+		$m_boxes         = $mt_boxes = [];
3605
+		$m_template_args = $mt_template_args = [];
3606
+
3607
+		$selected_messenger = $this->request->getRequestParam('selected_messenger', 'email');
3608
+
3609
+		if (isset($this->_m_mt_settings['messenger_tabs'])) {
3610
+			foreach ($this->_m_mt_settings['messenger_tabs'] as $messenger => $tab_array) {
3611
+				$is_messenger_active = $this->_message_resource_manager->is_messenger_active($messenger);
3612
+				$hide_on_message     = $is_messenger_active ? '' : 'hidden';
3613
+				$hide_off_message    = $is_messenger_active ? 'hidden' : '';
3614
+
3615
+				// messenger meta boxes
3616
+				$active         = $selected_messenger === $messenger;
3617
+				$active_mt_tabs = isset($this->_m_mt_settings['message_type_tabs'][ $messenger ]['active'])
3618
+					? $this->_m_mt_settings['message_type_tabs'][ $messenger ]['active']
3619
+					: '';
3620
+
3621
+				$m_boxes[ $messenger . '_a_box' ] = sprintf(
3622
+					esc_html__('%s Settings', 'event_espresso'),
3623
+					$tab_array['label']
3624
+				);
3625
+
3626
+				$m_template_args[ $messenger . '_a_box' ] = [
3627
+					'active_message_types'   => ! empty($active_mt_tabs) ? $this->_get_mt_tabs($active_mt_tabs) : '',
3628
+					'inactive_message_types' => isset(
3629
+						$this->_m_mt_settings['message_type_tabs'][ $messenger ]['inactive']
3630
+					)
3631
+						? $this->_get_mt_tabs($this->_m_mt_settings['message_type_tabs'][ $messenger ]['inactive'])
3632
+						: '',
3633
+					'content'                => $this->_get_messenger_box_content($tab_array['obj']),
3634
+					'hidden'                 => $active ? '' : ' hidden',
3635
+					'hide_on_message'        => $hide_on_message,
3636
+					'messenger'              => $messenger,
3637
+					'active'                 => $active,
3638
+				];
3639
+
3640
+				// message type meta boxes
3641
+				// (which is really just the inactive container for each messenger
3642
+				// showing inactive message types for that messenger)
3643
+				$mt_boxes[ $messenger . '_i_box' ]         = esc_html__('Inactive Message Types', 'event_espresso');
3644
+				$mt_template_args[ $messenger . '_i_box' ] = [
3645
+					'active_message_types'   => ! empty($active_mt_tabs) ? $this->_get_mt_tabs($active_mt_tabs) : '',
3646
+					'inactive_message_types' => isset(
3647
+						$this->_m_mt_settings['message_type_tabs'][ $messenger ]['inactive']
3648
+					)
3649
+						? $this->_get_mt_tabs($this->_m_mt_settings['message_type_tabs'][ $messenger ]['inactive'])
3650
+						: '',
3651
+					'hidden'                 => $active ? '' : ' hidden',
3652
+					'hide_on_message'        => $hide_on_message,
3653
+					'hide_off_message'       => $hide_off_message,
3654
+					'messenger'              => $messenger,
3655
+					'active'                 => $active,
3656
+				];
3657
+			}
3658
+		}
3659
+
3660
+
3661
+		// register messenger metaboxes
3662
+		$m_template_path = EE_MSG_TEMPLATE_PATH . 'ee_msg_details_messenger_mt_meta_box.template.php';
3663
+		foreach ($m_boxes as $box => $label) {
3664
+			$callback_args = ['template_path' => $m_template_path, 'template_args' => $m_template_args[ $box ]];
3665
+			$msgr          = str_replace('_a_box', '', $box);
3666
+			$this->addMetaBox(
3667
+				'espresso_' . $msgr . '_settings',
3668
+				$label,
3669
+				function ($post, $metabox) {
3670
+					EEH_Template::display_template(
3671
+						$metabox['args']['template_path'],
3672
+						$metabox['args']['template_args']
3673
+					);
3674
+				},
3675
+				$this->_current_screen->id,
3676
+				'normal',
3677
+				'high',
3678
+				$callback_args
3679
+			);
3680
+		}
3681
+
3682
+		// register message type metaboxes
3683
+		$mt_template_path = EE_MSG_TEMPLATE_PATH . 'ee_msg_details_messenger_meta_box.template.php';
3684
+		foreach ($mt_boxes as $box => $label) {
3685
+			$callback_args = [
3686
+				'template_path' => $mt_template_path,
3687
+				'template_args' => $mt_template_args[ $box ],
3688
+			];
3689
+			$mt            = str_replace('_i_box', '', $box);
3690
+			$this->addMetaBox(
3691
+				'espresso_' . $mt . '_inactive_mts',
3692
+				$label,
3693
+				function ($post, $metabox) {
3694
+					EEH_Template::display_template(
3695
+						$metabox['args']['template_path'],
3696
+						$metabox['args']['template_args']
3697
+					);
3698
+				},
3699
+				$this->_current_screen->id,
3700
+				'side',
3701
+				'high',
3702
+				$callback_args
3703
+			);
3704
+		}
3705
+
3706
+		// register metabox for global messages settings but only when on the main site.  On single site installs this
3707
+		// will always result in the metabox showing, on multisite installs the metabox will only show on the main site.
3708
+		if (is_main_site()) {
3709
+			$this->addMetaBox(
3710
+				'espresso_global_message_settings',
3711
+				esc_html__('Global Message Settings', 'event_espresso'),
3712
+				[$this, 'global_messages_settings_metabox_content'],
3713
+				$this->_current_screen->id,
3714
+				'normal',
3715
+				'low',
3716
+				[]
3717
+			);
3718
+		}
3719
+	}
3720
+
3721
+
3722
+	/**
3723
+	 *  This generates the content for the global messages settings metabox.
3724
+	 *
3725
+	 * @return void
3726
+	 * @throws EE_Error
3727
+	 * @throws InvalidArgumentException
3728
+	 * @throws ReflectionException
3729
+	 * @throws InvalidDataTypeException
3730
+	 * @throws InvalidInterfaceException
3731
+	 */
3732
+	public function global_messages_settings_metabox_content()
3733
+	{
3734
+		$form = $this->_generate_global_settings_form();
3735
+		echo wp_kses(
3736
+			$form->form_open(
3737
+				$this->add_query_args_and_nonce(['action' => 'update_global_settings'], EE_MSG_ADMIN_URL),
3738
+				'POST'
3739
+			),
3740
+			AllowedTags::getWithFormTags()
3741
+		);
3742
+		echo wp_kses($form->get_html(), AllowedTags::getWithFormTags());
3743
+		echo wp_kses($form->form_close(), AllowedTags::getWithFormTags());
3744
+	}
3745
+
3746
+
3747
+	/**
3748
+	 * This generates and returns the form object for the global messages settings.
3749
+	 *
3750
+	 * @return EE_Form_Section_Proper
3751
+	 * @throws EE_Error
3752
+	 * @throws InvalidArgumentException
3753
+	 * @throws ReflectionException
3754
+	 * @throws InvalidDataTypeException
3755
+	 * @throws InvalidInterfaceException
3756
+	 */
3757
+	protected function _generate_global_settings_form()
3758
+	{
3759
+		/** @var EE_Network_Core_Config $network_config */
3760
+		$network_config = EE_Registry::instance()->NET_CFG->core;
3761
+
3762
+		return new EE_Form_Section_Proper(
3763
+			[
3764
+				'name'            => 'global_messages_settings',
3765
+				'html_id'         => 'global_messages_settings',
3766
+				'html_class'      => 'form-table',
3767
+				'layout_strategy' => new EE_Admin_Two_Column_Layout(),
3768
+				'subsections'     => apply_filters(
3769
+					'FHEE__Messages_Admin_Page__global_messages_settings_metabox_content__form_subsections',
3770
+					[
3771
+						'do_messages_on_same_request' => new EE_Select_Input(
3772
+							[
3773
+								true  => esc_html__('On the same request', 'event_espresso'),
3774
+								false => esc_html__('On a separate request', 'event_espresso'),
3775
+							],
3776
+							[
3777
+								'default'         => $network_config->do_messages_on_same_request,
3778
+								'html_label_text' => esc_html__(
3779
+									'Generate and send all messages:',
3780
+									'event_espresso'
3781
+								),
3782
+								'html_help_text'  => esc_html__(
3783
+									'By default the messages system uses a more efficient means of processing messages on separate requests and utilizes the wp-cron scheduling system.  This makes things execute faster for people registering for your events.  However, if the wp-cron system is disabled on your site and there is no alternative in place, then you can change this so messages are always executed on the same request.',
3784
+									'event_espresso'
3785
+								),
3786
+							]
3787
+						),
3788
+						'delete_threshold'            => new EE_Select_Input(
3789
+							[
3790
+								0  => esc_html__('Forever', 'event_espresso'),
3791
+								3  => esc_html__('3 Months', 'event_espresso'),
3792
+								6  => esc_html__('6 Months', 'event_espresso'),
3793
+								9  => esc_html__('9 Months', 'event_espresso'),
3794
+								12 => esc_html__('12 Months', 'event_espresso'),
3795
+								24 => esc_html__('24 Months', 'event_espresso'),
3796
+								36 => esc_html__('36 Months', 'event_espresso'),
3797
+							],
3798
+							[
3799
+								'default'         => EE_Registry::instance()->CFG->messages->delete_threshold,
3800
+								'html_label_text' => esc_html__('Cleanup of old messages:', 'event_espresso'),
3801
+								'html_help_text'  => esc_html__(
3802
+									'You can control how long a record of processed messages is kept via this option.',
3803
+									'event_espresso'
3804
+								),
3805
+							]
3806
+						),
3807
+						'update_settings'             => new EE_Submit_Input(
3808
+							[
3809
+								'default'         => esc_html__('Update', 'event_espresso'),
3810
+								'html_label_text' => '',
3811
+							]
3812
+						),
3813
+					]
3814
+				),
3815
+			]
3816
+		);
3817
+	}
3818
+
3819
+
3820
+	/**
3821
+	 * This handles updating the global settings set on the admin page.
3822
+	 *
3823
+	 * @throws EE_Error
3824
+	 * @throws InvalidDataTypeException
3825
+	 * @throws InvalidInterfaceException
3826
+	 * @throws InvalidArgumentException
3827
+	 * @throws ReflectionException
3828
+	 */
3829
+	protected function _update_global_settings()
3830
+	{
3831
+		/** @var EE_Network_Core_Config $network_config */
3832
+		$network_config  = EE_Registry::instance()->NET_CFG->core;
3833
+		$messages_config = EE_Registry::instance()->CFG->messages;
3834
+		$form            = $this->_generate_global_settings_form();
3835
+		if ($form->was_submitted()) {
3836
+			$form->receive_form_submission();
3837
+			if ($form->is_valid()) {
3838
+				$valid_data = $form->valid_data();
3839
+				foreach ($valid_data as $property => $value) {
3840
+					$setter = 'set_' . $property;
3841
+					if (method_exists($network_config, $setter)) {
3842
+						$network_config->{$setter}($value);
3843
+					} elseif (
3844
+						property_exists($network_config, $property)
3845
+						&& $network_config->{$property} !== $value
3846
+					) {
3847
+						$network_config->{$property} = $value;
3848
+					} elseif (
3849
+						property_exists($messages_config, $property)
3850
+						&& $messages_config->{$property} !== $value
3851
+					) {
3852
+						$messages_config->{$property} = $value;
3853
+					}
3854
+				}
3855
+				// only update if the form submission was valid!
3856
+				EE_Registry::instance()->NET_CFG->update_config(true, false);
3857
+				EE_Registry::instance()->CFG->update_espresso_config();
3858
+				EE_Error::overwrite_success();
3859
+				EE_Error::add_success(esc_html__('Global message settings were updated', 'event_espresso'));
3860
+			}
3861
+		}
3862
+		$this->_redirect_after_action(0, '', '', ['action' => 'settings'], true);
3863
+	}
3864
+
3865
+
3866
+	/**
3867
+	 * this prepares the messenger tabs that can be dragged in and out of messenger boxes to activate/deactivate
3868
+	 *
3869
+	 * @param array $tab_array This is an array of message type tab details used to generate the tabs
3870
+	 * @return string html formatted tabs
3871
+	 * @throws DomainException
3872
+	 */
3873
+	protected function _get_mt_tabs($tab_array)
3874
+	{
3875
+		$tab_array = (array) $tab_array;
3876
+		$template  = EE_MSG_TEMPLATE_PATH . 'ee_msg_details_mt_settings_tab_item.template.php';
3877
+		$tabs      = '';
3878
+
3879
+		foreach ($tab_array as $tab) {
3880
+			$tabs .= EEH_Template::display_template($template, $tab, true);
3881
+		}
3882
+
3883
+		return $tabs;
3884
+	}
3885
+
3886
+
3887
+	/**
3888
+	 * This prepares the content of the messenger meta box admin settings
3889
+	 *
3890
+	 * @param EE_messenger $messenger The messenger we're setting up content for
3891
+	 * @return string html formatted content
3892
+	 * @throws DomainException
3893
+	 */
3894
+	protected function _get_messenger_box_content(EE_messenger $messenger)
3895
+	{
3896
+
3897
+		$fields                                         = $messenger->get_admin_settings_fields();
3898
+		$settings_template_args['template_form_fields'] = '';
3899
+
3900
+		// is $messenger active?
3901
+		$settings_template_args['active'] = $this->_message_resource_manager->is_messenger_active($messenger->name);
3902
+
3903
+
3904
+		if (! empty($fields)) {
3905
+			$existing_settings = $messenger->get_existing_admin_settings();
3906
+
3907
+			foreach ($fields as $fldname => $fldprops) {
3908
+				$field_id                         = $messenger->name . '-' . $fldname;
3909
+				$template_form_field[ $field_id ] = [
3910
+					'name'       => 'messenger_settings[' . $field_id . ']',
3911
+					'label'      => $fldprops['label'],
3912
+					'input'      => $fldprops['field_type'],
3913
+					'type'       => $fldprops['value_type'],
3914
+					'required'   => $fldprops['required'],
3915
+					'validation' => $fldprops['validation'],
3916
+					'value'      => isset($existing_settings[ $field_id ])
3917
+						? $existing_settings[ $field_id ]
3918
+						: $fldprops['default'],
3919
+					'css_class'  => '',
3920
+					'format'     => $fldprops['format'],
3921
+				];
3922
+			}
3923
+
3924
+
3925
+			$settings_template_args['template_form_fields'] = ! empty($template_form_field)
3926
+				? $this->_generate_admin_form_fields($template_form_field, 'string', 'ee_m_activate_form')
3927
+				: '';
3928
+		}
3929
+
3930
+		// we also need some hidden fields
3931
+		$settings_template_args['hidden_fields'] = [
3932
+			'messenger_settings[messenger]' . $messenger->name => [
3933
+				'type'  => 'hidden',
3934
+				'value' => $messenger->name,
3935
+			],
3936
+			'type' . $messenger->name                          => [
3937
+				'type'  => 'hidden',
3938
+				'value' => 'messenger',
3939
+			],
3940
+		];
3941
+
3942
+		// make sure any active message types that are existing are included in the hidden fields
3943
+		if (isset($this->_m_mt_settings['message_type_tabs'][ $messenger->name ]['active'])) {
3944
+			foreach ($this->_m_mt_settings['message_type_tabs'][ $messenger->name ]['active'] as $mt => $values) {
3945
+				$settings_template_args['hidden_fields'][ 'messenger_settings[message_types][' . $mt . ']' ] = [
3946
+					'type'  => 'hidden',
3947
+					'value' => $mt,
3948
+				];
3949
+			}
3950
+		}
3951
+		$settings_template_args['hidden_fields'] = $this->_generate_admin_form_fields(
3952
+			$settings_template_args['hidden_fields'],
3953
+			'array'
3954
+		);
3955
+		$active                                  =
3956
+			$this->_message_resource_manager->is_messenger_active($messenger->name);
3957
+
3958
+		$settings_template_args['messenger']           = $messenger->name;
3959
+		$settings_template_args['description']         = $messenger->description;
3960
+		$settings_template_args['show_hide_edit_form'] = $active ? '' : ' hidden';
3961
+
3962
+
3963
+		$settings_template_args['show_hide_edit_form'] = $this->_message_resource_manager->is_messenger_active(
3964
+			$messenger->name
3965
+		)
3966
+			? $settings_template_args['show_hide_edit_form']
3967
+			: ' hidden';
3968
+
3969
+		$settings_template_args['show_hide_edit_form'] = empty($settings_template_args['template_form_fields'])
3970
+			? ' hidden'
3971
+			: $settings_template_args['show_hide_edit_form'];
3972
+
3973
+
3974
+		$settings_template_args['on_off_action'] = $active ? 'messenger-off' : 'messenger-on';
3975
+		$settings_template_args['nonce']         = wp_create_nonce('activate_' . $messenger->name . '_toggle_nonce');
3976
+		$settings_template_args['on_off_status'] = $active;
3977
+		$template                                = EE_MSG_TEMPLATE_PATH . 'ee_msg_m_settings_content.template.php';
3978
+		return EEH_Template::display_template(
3979
+			$template,
3980
+			$settings_template_args,
3981
+			true
3982
+		);
3983
+	}
3984
+
3985
+
3986
+	/**
3987
+	 * used by ajax on the messages settings page to activate|deactivate the messenger
3988
+	 *
3989
+	 * @throws DomainException
3990
+	 * @throws EE_Error
3991
+	 * @throws InvalidDataTypeException
3992
+	 * @throws InvalidInterfaceException
3993
+	 * @throws InvalidArgumentException
3994
+	 * @throws ReflectionException
3995
+	 */
3996
+	public function activate_messenger_toggle()
3997
+	{
3998
+		$success = true;
3999
+		$this->_prep_default_response_for_messenger_or_message_type_toggle();
4000
+		// let's check that we have required data
4001
+
4002
+		if (! $this->_active_messenger_name) {
4003
+			EE_Error::add_error(
4004
+				esc_html__('Messenger name needed to toggle activation. None given', 'event_espresso'),
4005
+				__FILE__,
4006
+				__FUNCTION__,
4007
+				__LINE__
4008
+			);
4009
+			$success = false;
4010
+		}
4011
+
4012
+		// do a nonce check here since we're not arriving via a normal route
4013
+		$nonce     = $this->request->getRequestParam('activate_nonce', '');
4014
+		$nonce_ref = "activate_{$this->_active_messenger_name}_toggle_nonce";
4015
+
4016
+		$this->_verify_nonce($nonce, $nonce_ref);
4017
+
4018
+
4019
+		$status = $this->request->getRequestParam('status');
4020
+		if (! $status) {
4021
+			EE_Error::add_error(
4022
+				esc_html__(
4023
+					'Messenger status needed to know whether activation or deactivation is happening. No status is given',
4024
+					'event_espresso'
4025
+				),
4026
+				__FILE__,
4027
+				__FUNCTION__,
4028
+				__LINE__
4029
+			);
4030
+			$success = false;
4031
+		}
4032
+
4033
+		// do check to verify we have a valid status.
4034
+		if ($status !== 'off' && $status !== 'on') {
4035
+			EE_Error::add_error(
4036
+				sprintf(
4037
+					esc_html__('The given status (%s) is not valid. Must be "off" or "on"', 'event_espresso'),
4038
+					$status
4039
+				),
4040
+				__FILE__,
4041
+				__FUNCTION__,
4042
+				__LINE__
4043
+			);
4044
+			$success = false;
4045
+		}
4046
+
4047
+		if ($success) {
4048
+			// made it here?  Stop dawdling then!!
4049
+			$success = $status === 'off'
4050
+				? $this->_deactivate_messenger($this->_active_messenger_name)
4051
+				: $this->_activate_messenger($this->_active_messenger_name);
4052
+		}
4053
+
4054
+		$this->_template_args['success'] = $success;
4055
+
4056
+		// no special instructions so let's just do the json return (which should automatically do all the special stuff).
4057
+		$this->_return_json();
4058
+	}
4059
+
4060
+
4061
+	/**
4062
+	 * used by ajax from the messages settings page to activate|deactivate a message type
4063
+	 *
4064
+	 * @throws DomainException
4065
+	 * @throws EE_Error
4066
+	 * @throws ReflectionException
4067
+	 * @throws InvalidDataTypeException
4068
+	 * @throws InvalidInterfaceException
4069
+	 * @throws InvalidArgumentException
4070
+	 */
4071
+	public function activate_mt_toggle()
4072
+	{
4073
+		$success = true;
4074
+		$this->_prep_default_response_for_messenger_or_message_type_toggle();
4075
+
4076
+		// let's make sure we have the necessary data
4077
+		if (! $this->_active_message_type_name) {
4078
+			EE_Error::add_error(
4079
+				esc_html__('Message Type name needed to toggle activation. None given', 'event_espresso'),
4080
+				__FILE__,
4081
+				__FUNCTION__,
4082
+				__LINE__
4083
+			);
4084
+			$success = false;
4085
+		}
4086
+
4087
+		if (! $this->_active_messenger_name) {
4088
+			EE_Error::add_error(
4089
+				esc_html__('Messenger name needed to toggle activation. None given', 'event_espresso'),
4090
+				__FILE__,
4091
+				__FUNCTION__,
4092
+				__LINE__
4093
+			);
4094
+			$success = false;
4095
+		}
4096
+
4097
+		$status = $this->request->getRequestParam('status');
4098
+		if (! $status) {
4099
+			EE_Error::add_error(
4100
+				esc_html__(
4101
+					'Messenger status needed to know whether activation or deactivation is happening. No status is given',
4102
+					'event_espresso'
4103
+				),
4104
+				__FILE__,
4105
+				__FUNCTION__,
4106
+				__LINE__
4107
+			);
4108
+			$success = false;
4109
+		}
4110
+
4111
+
4112
+		// do check to verify we have a valid status.
4113
+		if ($status !== 'activate' && $status !== 'deactivate') {
4114
+			EE_Error::add_error(
4115
+				sprintf(
4116
+					esc_html__('The given status (%s) is not valid. Must be "active" or "inactive"', 'event_espresso'),
4117
+					$status
4118
+				),
4119
+				__FILE__,
4120
+				__FUNCTION__,
4121
+				__LINE__
4122
+			);
4123
+			$success = false;
4124
+		}
4125
+
4126
+
4127
+		// do a nonce check here since we're not arriving via a normal route
4128
+		$nonce = $this->request->getRequestParam('mt_nonce', '');
4129
+		$this->_verify_nonce($nonce, "{$this->_active_message_type_name}_nonce");
4130
+
4131
+		if ($success) {
4132
+			// made it here? um, what are you waiting for then?
4133
+			$success = $status === 'deactivate'
4134
+				? $this->_deactivate_message_type_for_messenger(
4135
+					$this->_active_messenger_name,
4136
+					$this->_active_message_type_name
4137
+				)
4138
+				: $this->_activate_message_type_for_messenger(
4139
+					$this->_active_messenger_name,
4140
+					$this->_active_message_type_name
4141
+				);
4142
+		}
4143
+
4144
+		$this->_template_args['success'] = $success;
4145
+		$this->_return_json();
4146
+	}
4147
+
4148
+
4149
+	/**
4150
+	 * Takes care of processing activating a messenger and preparing the appropriate response.
4151
+	 *
4152
+	 * @param string $messenger_name The name of the messenger being activated
4153
+	 * @return bool
4154
+	 * @throws DomainException
4155
+	 * @throws EE_Error
4156
+	 * @throws InvalidArgumentException
4157
+	 * @throws ReflectionException
4158
+	 * @throws InvalidDataTypeException
4159
+	 * @throws InvalidInterfaceException
4160
+	 */
4161
+	protected function _activate_messenger($messenger_name)
4162
+	{
4163
+		$active_messenger          = $this->_message_resource_manager->get_messenger($messenger_name);
4164
+		$message_types_to_activate = $active_messenger instanceof EE_Messenger
4165
+			? $active_messenger->get_default_message_types()
4166
+			: [];
4167
+
4168
+		// ensure is active
4169
+		$this->_message_resource_manager->activate_messenger($active_messenger, $message_types_to_activate);
4170
+
4171
+		// set response_data for reload
4172
+		foreach ($message_types_to_activate as $message_type_name) {
4173
+			$message_type = $this->_message_resource_manager->get_message_type($message_type_name);
4174
+			if (
4175
+				$this->_message_resource_manager->is_message_type_active_for_messenger(
4176
+					$messenger_name,
4177
+					$message_type_name
4178
+				)
4179
+				&& $message_type instanceof EE_message_type
4180
+			) {
4181
+				$this->_template_args['data']['active_mts'][] = $message_type_name;
4182
+				if ($message_type->get_admin_settings_fields()) {
4183
+					$this->_template_args['data']['mt_reload'][] = $message_type_name;
4184
+				}
4185
+			}
4186
+		}
4187
+
4188
+		// add success message for activating messenger
4189
+		return $this->_setup_response_message_for_activating_messenger_with_message_types($active_messenger);
4190
+	}
4191
+
4192
+
4193
+	/**
4194
+	 * Takes care of processing deactivating a messenger and preparing the appropriate response.
4195
+	 *
4196
+	 * @param string $messenger_name The name of the messenger being activated
4197
+	 * @return bool
4198
+	 * @throws DomainException
4199
+	 * @throws EE_Error
4200
+	 * @throws InvalidArgumentException
4201
+	 * @throws ReflectionException
4202
+	 * @throws InvalidDataTypeException
4203
+	 * @throws InvalidInterfaceException
4204
+	 */
4205
+	protected function _deactivate_messenger($messenger_name)
4206
+	{
4207
+		$active_messenger = $this->_message_resource_manager->get_messenger($messenger_name);
4208
+		$this->_message_resource_manager->deactivate_messenger($messenger_name);
4209
+
4210
+		return $this->_setup_response_message_for_deactivating_messenger_with_message_types($active_messenger);
4211
+	}
4212
+
4213
+
4214
+	/**
4215
+	 * Takes care of processing activating a message type for a messenger and preparing the appropriate response.
4216
+	 *
4217
+	 * @param string $messenger_name    The name of the messenger the message type is being activated for.
4218
+	 * @param string $message_type_name The name of the message type being activated for the messenger
4219
+	 * @return bool
4220
+	 * @throws DomainException
4221
+	 * @throws EE_Error
4222
+	 * @throws InvalidArgumentException
4223
+	 * @throws ReflectionException
4224
+	 * @throws InvalidDataTypeException
4225
+	 * @throws InvalidInterfaceException
4226
+	 */
4227
+	protected function _activate_message_type_for_messenger($messenger_name, $message_type_name)
4228
+	{
4229
+		$active_messenger         = $this->_message_resource_manager->get_messenger($messenger_name);
4230
+		$message_type_to_activate = $this->_message_resource_manager->get_message_type($message_type_name);
4231
+
4232
+		// ensure is active
4233
+		$this->_message_resource_manager->activate_messenger($active_messenger, $message_type_name);
4234
+
4235
+		// set response for load
4236
+		if (
4237
+			$this->_message_resource_manager->is_message_type_active_for_messenger(
4238
+				$messenger_name,
4239
+				$message_type_name
4240
+			)
4241
+		) {
4242
+			$this->_template_args['data']['active_mts'][] = $message_type_name;
4243
+			if ($message_type_to_activate->get_admin_settings_fields()) {
4244
+				$this->_template_args['data']['mt_reload'][] = $message_type_name;
4245
+			}
4246
+		}
4247
+
4248
+		return $this->_setup_response_message_for_activating_messenger_with_message_types(
4249
+			$active_messenger,
4250
+			$message_type_to_activate
4251
+		);
4252
+	}
4253
+
4254
+
4255
+	/**
4256
+	 * Takes care of processing deactivating a message type for a messenger and preparing the appropriate response.
4257
+	 *
4258
+	 * @param string $messenger_name    The name of the messenger the message type is being deactivated for.
4259
+	 * @param string $message_type_name The name of the message type being deactivated for the messenger
4260
+	 * @return bool
4261
+	 * @throws DomainException
4262
+	 * @throws EE_Error
4263
+	 * @throws InvalidArgumentException
4264
+	 * @throws ReflectionException
4265
+	 * @throws InvalidDataTypeException
4266
+	 * @throws InvalidInterfaceException
4267
+	 */
4268
+	protected function _deactivate_message_type_for_messenger($messenger_name, $message_type_name)
4269
+	{
4270
+		$active_messenger = $this->_message_resource_manager->get_messenger($messenger_name);
4271
+		/** @var EE_message_type $message_type_to_activate This will be present because it can't be toggled if it isn't */
4272
+		$message_type_to_deactivate = $this->_message_resource_manager->get_message_type($message_type_name);
4273
+		$this->_message_resource_manager->deactivate_message_type_for_messenger($message_type_name, $messenger_name);
4274
+
4275
+		return $this->_setup_response_message_for_deactivating_messenger_with_message_types(
4276
+			$active_messenger,
4277
+			$message_type_to_deactivate
4278
+		);
4279
+	}
4280
+
4281
+
4282
+	/**
4283
+	 * This just initializes the defaults for activating messenger and message type responses.
4284
+	 */
4285
+	protected function _prep_default_response_for_messenger_or_message_type_toggle()
4286
+	{
4287
+		$this->_template_args['data']['active_mts'] = [];
4288
+		$this->_template_args['data']['mt_reload']  = [];
4289
+	}
4290
+
4291
+
4292
+	/**
4293
+	 * Setup appropriate response for activating a messenger and/or message types
4294
+	 *
4295
+	 * @param EE_messenger         $messenger
4296
+	 * @param EE_message_type|null $message_type
4297
+	 * @return bool
4298
+	 * @throws DomainException
4299
+	 * @throws EE_Error
4300
+	 * @throws InvalidArgumentException
4301
+	 * @throws ReflectionException
4302
+	 * @throws InvalidDataTypeException
4303
+	 * @throws InvalidInterfaceException
4304
+	 */
4305
+	protected function _setup_response_message_for_activating_messenger_with_message_types(
4306
+		$messenger,
4307
+		EE_Message_Type $message_type = null
4308
+	) {
4309
+		// if $messenger isn't a valid messenger object then get out.
4310
+		if (! $messenger instanceof EE_Messenger) {
4311
+			EE_Error::add_error(
4312
+				esc_html__('The messenger being activated is not a valid messenger', 'event_espresso'),
4313
+				__FILE__,
4314
+				__FUNCTION__,
4315
+				__LINE__
4316
+			);
4317
+			return false;
4318
+		}
4319
+		// activated
4320
+		if ($this->_template_args['data']['active_mts']) {
4321
+			EE_Error::overwrite_success();
4322
+			// activated a message type with the messenger
4323
+			if ($message_type instanceof EE_message_type) {
4324
+				EE_Error::add_success(
4325
+					sprintf(
4326
+						esc_html__(
4327
+							'%s message type has been successfully activated with the %s messenger',
4328
+							'event_espresso'
4329
+						),
4330
+						ucwords($message_type->label['singular']),
4331
+						ucwords($messenger->label['singular'])
4332
+					)
4333
+				);
4334
+
4335
+				// if message type was invoice then let's make sure we activate the invoice payment method.
4336
+				if ($message_type->name === 'invoice') {
4337
+					EE_Registry::instance()->load_lib('Payment_Method_Manager');
4338
+					$pm = EE_Payment_Method_Manager::instance()->activate_a_payment_method_of_type('Invoice');
4339
+					if ($pm instanceof EE_Payment_Method) {
4340
+						EE_Error::add_attention(
4341
+							esc_html__(
4342
+								'Activating the invoice message type also automatically activates the invoice payment method.  If you do not wish the invoice payment method to be active, or to change its settings, visit the payment method admin page.',
4343
+								'event_espresso'
4344
+							)
4345
+						);
4346
+					}
4347
+				}
4348
+				// just toggles the entire messenger
4349
+			} else {
4350
+				EE_Error::add_success(
4351
+					sprintf(
4352
+						esc_html__('%s messenger has been successfully activated', 'event_espresso'),
4353
+						ucwords($messenger->label['singular'])
4354
+					)
4355
+				);
4356
+			}
4357
+
4358
+			return true;
4359
+
4360
+			// possible error condition. This will happen when our active_mts data is empty because it is validated for actual active
4361
+			// message types after the activation process.  However its possible some messengers don't HAVE any default_message_types
4362
+			// in which case we just give a success message for the messenger being successfully activated.
4363
+		} else {
4364
+			if (! $messenger->get_default_message_types()) {
4365
+				// messenger doesn't have any default message types so still a success.
4366
+				EE_Error::add_success(
4367
+					sprintf(
4368
+						esc_html__('%s messenger was successfully activated.', 'event_espresso'),
4369
+						ucwords($messenger->label['singular'])
4370
+					)
4371
+				);
4372
+
4373
+				return true;
4374
+			} else {
4375
+				EE_Error::add_error(
4376
+					$message_type instanceof EE_message_type
4377
+					? sprintf(
4378
+						esc_html__(
4379
+							'%s message type was not successfully activated with the %s messenger',
4380
+							'event_espresso'
4381
+						),
4382
+						ucwords($message_type->label['singular']),
4383
+						ucwords($messenger->label['singular'])
4384
+					)
4385
+					: sprintf(
4386
+						esc_html__('%s messenger was not successfully activated', 'event_espresso'),
4387
+						ucwords($messenger->label['singular'])
4388
+					),
4389
+					__FILE__,
4390
+					__FUNCTION__,
4391
+					__LINE__
4392
+				);
4393
+
4394
+				return false;
4395
+			}
4396
+		}
4397
+	}
4398
+
4399
+
4400
+	/**
4401
+	 * This sets up the appropriate response for deactivating a messenger and/or message type.
4402
+	 *
4403
+	 * @param EE_messenger         $messenger
4404
+	 * @param EE_message_type|null $message_type
4405
+	 * @return bool
4406
+	 * @throws DomainException
4407
+	 * @throws EE_Error
4408
+	 * @throws InvalidArgumentException
4409
+	 * @throws ReflectionException
4410
+	 * @throws InvalidDataTypeException
4411
+	 * @throws InvalidInterfaceException
4412
+	 */
4413
+	protected function _setup_response_message_for_deactivating_messenger_with_message_types(
4414
+		$messenger,
4415
+		EE_message_type $message_type = null
4416
+	) {
4417
+		EE_Error::overwrite_success();
4418
+
4419
+		// if $messenger isn't a valid messenger object then get out.
4420
+		if (! $messenger instanceof EE_Messenger) {
4421
+			EE_Error::add_error(
4422
+				esc_html__('The messenger being deactivated is not a valid messenger', 'event_espresso'),
4423
+				__FILE__,
4424
+				__FUNCTION__,
4425
+				__LINE__
4426
+			);
4427
+
4428
+			return false;
4429
+		}
4430
+
4431
+		if ($message_type instanceof EE_message_type) {
4432
+			$message_type_name = $message_type->name;
4433
+			EE_Error::add_success(
4434
+				sprintf(
4435
+					esc_html__(
4436
+						'%s message type has been successfully deactivated for the %s messenger.',
4437
+						'event_espresso'
4438
+					),
4439
+					ucwords($message_type->label['singular']),
4440
+					ucwords($messenger->label['singular'])
4441
+				)
4442
+			);
4443
+		} else {
4444
+			$message_type_name = '';
4445
+			EE_Error::add_success(
4446
+				sprintf(
4447
+					esc_html__('%s messenger has been successfully deactivated.', 'event_espresso'),
4448
+					ucwords($messenger->label['singular'])
4449
+				)
4450
+			);
4451
+		}
4452
+
4453
+		// if messenger was html or message type was invoice then let's make sure we deactivate invoice payment method.
4454
+		if (
4455
+			$messenger->name === 'html'
4456
+			&& (
4457
+				is_null($message_type)
4458
+				|| $message_type_name === 'invoice'
4459
+			)
4460
+		) {
4461
+			EE_Registry::instance()->load_lib('Payment_Method_Manager');
4462
+			$count_updated = EE_Payment_Method_Manager::instance()->deactivate_payment_method('invoice');
4463
+			if ($count_updated > 0) {
4464
+				$msg = $message_type_name === 'invoice'
4465
+					? esc_html__(
4466
+						'Deactivating the invoice message type also automatically deactivates the invoice payment method. In order for invoices to be generated the invoice message type must be active. If you completed this action by mistake, simply reactivate the invoice message type and then visit the payment methods admin page to reactivate the invoice payment method.',
4467
+						'event_espresso'
4468
+					)
4469
+					: esc_html__(
4470
+						'Deactivating the html messenger also automatically deactivates the invoice payment method.  In order for invoices to be generated the html messenger must be be active.  If you completed this action by mistake, simply reactivate the html messenger, then visit the payment methods admin page to reactivate the invoice payment method.',
4471
+						'event_espresso'
4472
+					);
4473
+				EE_Error::add_attention($msg);
4474
+			}
4475
+		}
4476
+
4477
+		return true;
4478
+	}
4479
+
4480
+
4481
+	/**
4482
+	 * handles updating a message type form on messenger activation IF the message type has settings fields. (via ajax)
4483
+	 *
4484
+	 * @throws DomainException
4485
+	 * @throws EE_Error
4486
+	 * @throws EE_Error
4487
+	 */
4488
+	public function update_mt_form()
4489
+	{
4490
+		if (! $this->_active_messenger_name || ! $this->_active_message_type_name) {
4491
+			EE_Error::add_error(
4492
+				esc_html__('Require message type or messenger to send an updated form', 'event_espresso'),
4493
+				__FILE__,
4494
+				__FUNCTION__,
4495
+				__LINE__
4496
+			);
4497
+			$this->_return_json();
4498
+		}
4499
+
4500
+		$message_types = $this->get_installed_message_types();
4501
+		$message_type  = $message_types[ $this->_active_message_type_name ];
4502
+		$messenger     = $this->_message_resource_manager->get_active_messenger($this->_active_messenger_name);
4503
+		$content       = $this->_message_type_settings_content($message_type, $messenger, true);
4504
+
4505
+		$this->_template_args['success'] = true;
4506
+		$this->_template_args['content'] = $content;
4507
+		$this->_return_json();
4508
+	}
4509
+
4510
+
4511
+	/**
4512
+	 * this handles saving the settings for a messenger or message type
4513
+	 *
4514
+	 * @throws EE_Error
4515
+	 * @throws EE_Error
4516
+	 */
4517
+	public function save_settings()
4518
+	{
4519
+		$type = $this->request->getRequestParam('type');
4520
+		if (! $type) {
4521
+			EE_Error::add_error(
4522
+				esc_html__(
4523
+					'Cannot save settings because type is unknown (messenger settings or message type settings?)',
4524
+					'event_espresso'
4525
+				),
4526
+				__FILE__,
4527
+				__FUNCTION__,
4528
+				__LINE__
4529
+			);
4530
+			$this->_template_args['error'] = true;
4531
+			$this->_return_json();
4532
+		}
4533
+
4534
+
4535
+		if ($type === 'messenger') {
4536
+			// this should be an array.
4537
+			$settings  = $this->request->getRequestParam('messenger_settings', [], 'string', true);
4538
+			$messenger = $settings['messenger'];
4539
+			// remove messenger and message_types from settings array
4540
+			unset($settings['messenger'], $settings['message_types']);
4541
+			$this->_message_resource_manager->add_settings_for_messenger($messenger, $settings);
4542
+		} elseif ($type === 'message_type') {
4543
+			$settings     = $this->request->getRequestParam('message_type_settings', [], 'string', true);
4544
+			$messenger    = $settings['messenger'];
4545
+			$message_type = $settings['message_type'];
4546
+			// remove messenger and message_types from settings array
4547
+			unset($settings['messenger'], $settings['message_types']);
4548
+			$this->_message_resource_manager->add_settings_for_message_type($messenger, $message_type, $settings);
4549
+		}
4550
+
4551
+		// okay we should have the data all setup.  Now we just update!
4552
+		$success = $this->_message_resource_manager->update_active_messengers_option();
4553
+
4554
+		if ($success) {
4555
+			EE_Error::add_success(esc_html__('Settings updated', 'event_espresso'));
4556
+		} else {
4557
+			EE_Error::add_error(
4558
+				esc_html__('Settings did not get updated', 'event_espresso'),
4559
+				__FILE__,
4560
+				__FUNCTION__,
4561
+				__LINE__
4562
+			);
4563
+		}
4564
+
4565
+		$this->_template_args['success'] = $success;
4566
+		$this->_return_json();
4567
+	}
4568
+
4569
+
4570
+
4571
+
4572
+	/**  EE MESSAGE PROCESSING ACTIONS **/
4573
+
4574
+
4575
+	/**
4576
+	 * This immediately generates any EE_Message ID's that are selected that are EEM_Message::status_incomplete
4577
+	 * However, this does not send immediately, it just queues for sending.
4578
+	 *
4579
+	 * @throws EE_Error
4580
+	 * @throws InvalidDataTypeException
4581
+	 * @throws InvalidInterfaceException
4582
+	 * @throws InvalidArgumentException
4583
+	 * @throws ReflectionException
4584
+	 * @since 4.9.0
4585
+	 */
4586
+	protected function _generate_now()
4587
+	{
4588
+		EED_Messages::generate_now($this->_get_msg_ids_from_request());
4589
+		$this->_redirect_after_action(false, '', '', [], true);
4590
+	}
4591
+
4592
+
4593
+	/**
4594
+	 * This immediately generates AND sends any EE_Message's selected that are EEM_Message::status_incomplete or that
4595
+	 * are EEM_Message::status_resend or EEM_Message::status_idle
4596
+	 *
4597
+	 * @throws EE_Error
4598
+	 * @throws InvalidDataTypeException
4599
+	 * @throws InvalidInterfaceException
4600
+	 * @throws InvalidArgumentException
4601
+	 * @throws ReflectionException
4602
+	 * @since 4.9.0
4603
+	 */
4604
+	protected function _generate_and_send_now()
4605
+	{
4606
+		EED_Messages::generate_and_send_now($this->_get_msg_ids_from_request());
4607
+		$this->_redirect_after_action(false, '', '', [], true);
4608
+	}
4609
+
4610
+
4611
+	/**
4612
+	 * This queues any EEM_Message::status_sent EE_Message ids in the request for resending.
4613
+	 *
4614
+	 * @throws EE_Error
4615
+	 * @throws InvalidDataTypeException
4616
+	 * @throws InvalidInterfaceException
4617
+	 * @throws InvalidArgumentException
4618
+	 * @throws ReflectionException
4619
+	 * @since 4.9.0
4620
+	 */
4621
+	protected function _queue_for_resending()
4622
+	{
4623
+		EED_Messages::queue_for_resending($this->_get_msg_ids_from_request());
4624
+		$this->_redirect_after_action(false, '', '', [], true);
4625
+	}
4626
+
4627
+
4628
+	/**
4629
+	 *  This sends immediately any EEM_Message::status_idle or EEM_Message::status_resend messages in the queue
4630
+	 *
4631
+	 * @throws EE_Error
4632
+	 * @throws InvalidDataTypeException
4633
+	 * @throws InvalidInterfaceException
4634
+	 * @throws InvalidArgumentException
4635
+	 * @throws ReflectionException
4636
+	 * @since 4.9.0
4637
+	 */
4638
+	protected function _send_now()
4639
+	{
4640
+		EED_Messages::send_now($this->_get_msg_ids_from_request());
4641
+		$this->_redirect_after_action(false, '', '', [], true);
4642
+	}
4643
+
4644
+
4645
+	/**
4646
+	 * Deletes EE_messages for IDs in the request.
4647
+	 *
4648
+	 * @throws EE_Error
4649
+	 * @throws InvalidDataTypeException
4650
+	 * @throws InvalidInterfaceException
4651
+	 * @throws InvalidArgumentException
4652
+	 * @since 4.9.0
4653
+	 */
4654
+	protected function _delete_ee_messages()
4655
+	{
4656
+		$MSG_IDs       = $this->_get_msg_ids_from_request();
4657
+		$deleted_count = 0;
4658
+		foreach ($MSG_IDs as $MSG_ID) {
4659
+			if ($this->getMsgModel()->delete_by_ID($MSG_ID)) {
4660
+				$deleted_count++;
4661
+			}
4662
+		}
4663
+		if ($deleted_count) {
4664
+			EE_Error::add_success(
4665
+				esc_html(
4666
+					_n(
4667
+						'Message successfully deleted',
4668
+						'Messages successfully deleted',
4669
+						$deleted_count,
4670
+						'event_espresso'
4671
+					)
4672
+				)
4673
+			);
4674
+		} else {
4675
+			EE_Error::add_error(
4676
+				_n('The message was not deleted.', 'The messages were not deleted', count($MSG_IDs), 'event_espresso'),
4677
+				__FILE__,
4678
+				__FUNCTION__,
4679
+				__LINE__
4680
+			);
4681
+		}
4682
+		$this->_redirect_after_action(false, '', '', [], true);
4683
+	}
4684
+
4685
+
4686
+	/**
4687
+	 *  This looks for 'MSG_ID' key in the request and returns an array of MSG_ID's if present.
4688
+	 *
4689
+	 * @return array
4690
+	 * @since 4.9.0
4691
+	 */
4692
+	protected function _get_msg_ids_from_request()
4693
+	{
4694
+		$MSG_IDs = $this->request->getRequestParam('MSG_ID', [], 'string', true);
4695
+		if (empty($MSG_IDs)) {
4696
+			return [];
4697
+		}
4698
+		// if 'MSG_ID' was just a single ID (not an array)
4699
+		// then $MSG_IDs will be something like [123] so $MSG_IDs[0] should be 123
4700
+		// otherwise, $MSG_IDs was already an array where message IDs were used as the keys
4701
+		return count($MSG_IDs) === 1 && isset($MSG_IDs[0])
4702
+			? $MSG_IDs
4703
+			: array_keys($MSG_IDs);
4704
+	}
4705 4705
 }
Please login to merge, or discard this patch.
admin_pages/registrations/Registrations_Admin_Page.core.php 2 patches
Indentation   +3653 added lines, -3653 removed lines patch added patch discarded remove patch
@@ -20,2209 +20,2209 @@  discard block
 block discarded – undo
20 20
  */
21 21
 class Registrations_Admin_Page extends EE_Admin_Page_CPT
22 22
 {
23
-    /**
24
-     * @var EE_Registration
25
-     */
26
-    private $_registration;
27
-
28
-    /**
29
-     * @var EE_Event
30
-     */
31
-    private $_reg_event;
32
-
33
-    /**
34
-     * @var EE_Session
35
-     */
36
-    private $_session;
37
-
38
-    /**
39
-     * @var array
40
-     */
41
-    private static $_reg_status;
42
-
43
-    /**
44
-     * Form for displaying the custom questions for this registration.
45
-     * This gets used a few times throughout the request so its best to cache it
46
-     *
47
-     * @var EE_Registration_Custom_Questions_Form
48
-     */
49
-    protected $_reg_custom_questions_form;
50
-
51
-    /**
52
-     * @var EEM_Registration $registration_model
53
-     */
54
-    private $registration_model;
55
-
56
-    /**
57
-     * @var EEM_Attendee $attendee_model
58
-     */
59
-    private $attendee_model;
60
-
61
-    /**
62
-     * @var EEM_Event $event_model
63
-     */
64
-    private $event_model;
65
-
66
-    /**
67
-     * @var EEM_Status $status_model
68
-     */
69
-    private $status_model;
70
-
71
-
72
-    /**
73
-     * @param bool $routing
74
-     * @throws EE_Error
75
-     * @throws InvalidArgumentException
76
-     * @throws InvalidDataTypeException
77
-     * @throws InvalidInterfaceException
78
-     * @throws ReflectionException
79
-     */
80
-    public function __construct($routing = true)
81
-    {
82
-        parent::__construct($routing);
83
-        add_action('wp_loaded', [$this, 'wp_loaded']);
84
-    }
85
-
86
-
87
-    /**
88
-     * @return EEM_Registration
89
-     * @throws InvalidArgumentException
90
-     * @throws InvalidDataTypeException
91
-     * @throws InvalidInterfaceException
92
-     * @since 4.10.2.p
93
-     */
94
-    protected function getRegistrationModel()
95
-    {
96
-        if (! $this->registration_model instanceof EEM_Registration) {
97
-            $this->registration_model = $this->loader->getShared('EEM_Registration');
98
-        }
99
-        return $this->registration_model;
100
-    }
101
-
102
-
103
-    /**
104
-     * @return EEM_Attendee
105
-     * @throws InvalidArgumentException
106
-     * @throws InvalidDataTypeException
107
-     * @throws InvalidInterfaceException
108
-     * @since 4.10.2.p
109
-     */
110
-    protected function getAttendeeModel()
111
-    {
112
-        if (! $this->attendee_model instanceof EEM_Attendee) {
113
-            $this->attendee_model = $this->loader->getShared('EEM_Attendee');
114
-        }
115
-        return $this->attendee_model;
116
-    }
117
-
118
-
119
-    /**
120
-     * @return EEM_Event
121
-     * @throws InvalidArgumentException
122
-     * @throws InvalidDataTypeException
123
-     * @throws InvalidInterfaceException
124
-     * @since 4.10.2.p
125
-     */
126
-    protected function getEventModel()
127
-    {
128
-        if (! $this->event_model instanceof EEM_Event) {
129
-            $this->event_model = $this->loader->getShared('EEM_Event');
130
-        }
131
-        return $this->event_model;
132
-    }
133
-
134
-
135
-    /**
136
-     * @return EEM_Status
137
-     * @throws InvalidArgumentException
138
-     * @throws InvalidDataTypeException
139
-     * @throws InvalidInterfaceException
140
-     * @since 4.10.2.p
141
-     */
142
-    protected function getStatusModel()
143
-    {
144
-        if (! $this->status_model instanceof EEM_Status) {
145
-            $this->status_model = $this->loader->getShared('EEM_Status');
146
-        }
147
-        return $this->status_model;
148
-    }
149
-
150
-
151
-    public function wp_loaded()
152
-    {
153
-        // when adding a new registration...
154
-        $action = $this->request->getRequestParam('action');
155
-        if ($action === 'new_registration') {
156
-            EE_System::do_not_cache();
157
-            if ($this->request->getRequestParam('processing_registration', 0, 'int') !== 1) {
158
-                // and it's NOT the attendee information reg step
159
-                // force cookie expiration by setting time to last week
160
-                setcookie('ee_registration_added', 0, time() - WEEK_IN_SECONDS, '/');
161
-                // and update the global
162
-                $_COOKIE['ee_registration_added'] = 0;
163
-            }
164
-        }
165
-    }
166
-
167
-
168
-    protected function _init_page_props()
169
-    {
170
-        $this->page_slug        = REG_PG_SLUG;
171
-        $this->_admin_base_url  = REG_ADMIN_URL;
172
-        $this->_admin_base_path = REG_ADMIN;
173
-        $this->page_label       = esc_html__('Registrations', 'event_espresso');
174
-        $this->_cpt_routes      = [
175
-            'add_new_attendee' => 'espresso_attendees',
176
-            'edit_attendee'    => 'espresso_attendees',
177
-            'insert_attendee'  => 'espresso_attendees',
178
-            'update_attendee'  => 'espresso_attendees',
179
-        ];
180
-        $this->_cpt_model_names = [
181
-            'add_new_attendee' => 'EEM_Attendee',
182
-            'edit_attendee'    => 'EEM_Attendee',
183
-        ];
184
-        $this->_cpt_edit_routes = [
185
-            'espresso_attendees' => 'edit_attendee',
186
-        ];
187
-        $this->_pagenow_map     = [
188
-            'add_new_attendee' => 'post-new.php',
189
-            'edit_attendee'    => 'post.php',
190
-            'trash'            => 'post.php',
191
-        ];
192
-        add_action('edit_form_after_title', [$this, 'after_title_form_fields'], 10);
193
-        // add filters so that the comment urls don't take users to a confusing 404 page
194
-        add_filter('get_comment_link', [$this, 'clear_comment_link'], 10, 2);
195
-    }
196
-
197
-
198
-    /**
199
-     * @param string     $link    The comment permalink with '#comment-$id' appended.
200
-     * @param WP_Comment $comment The current comment object.
201
-     * @return string
202
-     */
203
-    public function clear_comment_link($link, WP_Comment $comment)
204
-    {
205
-        // gotta make sure this only happens on this route
206
-        $post_type = get_post_type($comment->comment_post_ID);
207
-        if ($post_type === 'espresso_attendees') {
208
-            return '#commentsdiv';
209
-        }
210
-        return $link;
211
-    }
212
-
213
-
214
-    protected function _ajax_hooks()
215
-    {
216
-        // todo: all hooks for registrations ajax goes in here
217
-        add_action('wp_ajax_toggle_checkin_status', [$this, 'toggle_checkin_status']);
218
-    }
219
-
220
-
221
-    protected function _define_page_props()
222
-    {
223
-        $this->_admin_page_title = $this->page_label;
224
-        $this->_labels           = [
225
-            'buttons'                      => [
226
-                'add-registrant'      => esc_html__('Add New Registration', 'event_espresso'),
227
-                'add-attendee'        => esc_html__('Add Contact', 'event_espresso'),
228
-                'edit'                => esc_html__('Edit Contact', 'event_espresso'),
229
-                'report'              => esc_html__('Event Registrations CSV Report', 'event_espresso'),
230
-                'report_datetime'     => esc_html__('Datetime Registrations CSV Report', 'event_espresso'),
231
-                'report_all'          => esc_html__('All Registrations CSV Report', 'event_espresso'),
232
-                'report_filtered'     => esc_html__('Filtered CSV Report', 'event_espresso'),
233
-                'contact_list_report' => esc_html__('Contact List Report', 'event_espresso'),
234
-                'contact_list_export' => esc_html__('Export Data', 'event_espresso'),
235
-            ],
236
-            'publishbox'                   => [
237
-                'add_new_attendee' => esc_html__('Add Contact Record', 'event_espresso'),
238
-                'edit_attendee'    => esc_html__('Update Contact Record', 'event_espresso'),
239
-            ],
240
-            'hide_add_button_on_cpt_route' => [
241
-                'edit_attendee' => true,
242
-            ],
243
-        ];
244
-    }
245
-
246
-
247
-    /**
248
-     * grab url requests and route them
249
-     *
250
-     * @return void
251
-     * @throws EE_Error
252
-     */
253
-    public function _set_page_routes()
254
-    {
255
-        $this->_get_registration_status_array();
256
-        $REG_ID             = $this->request->getRequestParam('_REG_ID', 0, 'int');
257
-        $REG_ID             = $this->request->getRequestParam('reg_status_change_form[REG_ID]', $REG_ID, 'int');
258
-        $ATT_ID             = $this->request->getRequestParam('ATT_ID', 0, 'int');
259
-        $ATT_ID             = $this->request->getRequestParam('post', $ATT_ID, 'int');
260
-        $this->_page_routes = [
261
-            'default'                             => [
262
-                'func'       => '_registrations_overview_list_table',
263
-                'capability' => 'ee_read_registrations',
264
-            ],
265
-            'view_registration'                   => [
266
-                'func'       => '_registration_details',
267
-                'capability' => 'ee_read_registration',
268
-                'obj_id'     => $REG_ID,
269
-            ],
270
-            'edit_registration'                   => [
271
-                'func'               => '_update_attendee_registration_form',
272
-                'noheader'           => true,
273
-                'headers_sent_route' => 'view_registration',
274
-                'capability'         => 'ee_edit_registration',
275
-                'obj_id'             => $REG_ID,
276
-                '_REG_ID'            => $REG_ID,
277
-            ],
278
-            'trash_registrations'                 => [
279
-                'func'       => '_trash_or_restore_registrations',
280
-                'args'       => ['trash' => true],
281
-                'noheader'   => true,
282
-                'capability' => 'ee_delete_registrations',
283
-            ],
284
-            'restore_registrations'               => [
285
-                'func'       => '_trash_or_restore_registrations',
286
-                'args'       => ['trash' => false],
287
-                'noheader'   => true,
288
-                'capability' => 'ee_delete_registrations',
289
-            ],
290
-            'delete_registrations'                => [
291
-                'func'       => '_delete_registrations',
292
-                'noheader'   => true,
293
-                'capability' => 'ee_delete_registrations',
294
-            ],
295
-            'new_registration'                    => [
296
-                'func'       => 'new_registration',
297
-                'capability' => 'ee_edit_registrations',
298
-            ],
299
-            'process_reg_step'                    => [
300
-                'func'       => 'process_reg_step',
301
-                'noheader'   => true,
302
-                'capability' => 'ee_edit_registrations',
303
-            ],
304
-            'redirect_to_txn'                     => [
305
-                'func'       => 'redirect_to_txn',
306
-                'noheader'   => true,
307
-                'capability' => 'ee_edit_registrations',
308
-            ],
309
-            'change_reg_status'                   => [
310
-                'func'       => '_change_reg_status',
311
-                'noheader'   => true,
312
-                'capability' => 'ee_edit_registration',
313
-                'obj_id'     => $REG_ID,
314
-            ],
315
-            'approve_registration'                => [
316
-                'func'       => 'approve_registration',
317
-                'noheader'   => true,
318
-                'capability' => 'ee_edit_registration',
319
-                'obj_id'     => $REG_ID,
320
-            ],
321
-            'approve_and_notify_registration'     => [
322
-                'func'       => 'approve_registration',
323
-                'noheader'   => true,
324
-                'args'       => [true],
325
-                'capability' => 'ee_edit_registration',
326
-                'obj_id'     => $REG_ID,
327
-            ],
328
-            'approve_registrations'               => [
329
-                'func'       => 'bulk_action_on_registrations',
330
-                'noheader'   => true,
331
-                'capability' => 'ee_edit_registrations',
332
-                'args'       => ['approve'],
333
-            ],
334
-            'approve_and_notify_registrations'    => [
335
-                'func'       => 'bulk_action_on_registrations',
336
-                'noheader'   => true,
337
-                'capability' => 'ee_edit_registrations',
338
-                'args'       => ['approve', true],
339
-            ],
340
-            'decline_registration'                => [
341
-                'func'       => 'decline_registration',
342
-                'noheader'   => true,
343
-                'capability' => 'ee_edit_registration',
344
-                'obj_id'     => $REG_ID,
345
-            ],
346
-            'decline_and_notify_registration'     => [
347
-                'func'       => 'decline_registration',
348
-                'noheader'   => true,
349
-                'args'       => [true],
350
-                'capability' => 'ee_edit_registration',
351
-                'obj_id'     => $REG_ID,
352
-            ],
353
-            'decline_registrations'               => [
354
-                'func'       => 'bulk_action_on_registrations',
355
-                'noheader'   => true,
356
-                'capability' => 'ee_edit_registrations',
357
-                'args'       => ['decline'],
358
-            ],
359
-            'decline_and_notify_registrations'    => [
360
-                'func'       => 'bulk_action_on_registrations',
361
-                'noheader'   => true,
362
-                'capability' => 'ee_edit_registrations',
363
-                'args'       => ['decline', true],
364
-            ],
365
-            'pending_registration'                => [
366
-                'func'       => 'pending_registration',
367
-                'noheader'   => true,
368
-                'capability' => 'ee_edit_registration',
369
-                'obj_id'     => $REG_ID,
370
-            ],
371
-            'pending_and_notify_registration'     => [
372
-                'func'       => 'pending_registration',
373
-                'noheader'   => true,
374
-                'args'       => [true],
375
-                'capability' => 'ee_edit_registration',
376
-                'obj_id'     => $REG_ID,
377
-            ],
378
-            'pending_registrations'               => [
379
-                'func'       => 'bulk_action_on_registrations',
380
-                'noheader'   => true,
381
-                'capability' => 'ee_edit_registrations',
382
-                'args'       => ['pending'],
383
-            ],
384
-            'pending_and_notify_registrations'    => [
385
-                'func'       => 'bulk_action_on_registrations',
386
-                'noheader'   => true,
387
-                'capability' => 'ee_edit_registrations',
388
-                'args'       => ['pending', true],
389
-            ],
390
-            'no_approve_registration'             => [
391
-                'func'       => 'not_approve_registration',
392
-                'noheader'   => true,
393
-                'capability' => 'ee_edit_registration',
394
-                'obj_id'     => $REG_ID,
395
-            ],
396
-            'no_approve_and_notify_registration'  => [
397
-                'func'       => 'not_approve_registration',
398
-                'noheader'   => true,
399
-                'args'       => [true],
400
-                'capability' => 'ee_edit_registration',
401
-                'obj_id'     => $REG_ID,
402
-            ],
403
-            'no_approve_registrations'            => [
404
-                'func'       => 'bulk_action_on_registrations',
405
-                'noheader'   => true,
406
-                'capability' => 'ee_edit_registrations',
407
-                'args'       => ['not_approve'],
408
-            ],
409
-            'no_approve_and_notify_registrations' => [
410
-                'func'       => 'bulk_action_on_registrations',
411
-                'noheader'   => true,
412
-                'capability' => 'ee_edit_registrations',
413
-                'args'       => ['not_approve', true],
414
-            ],
415
-            'cancel_registration'                 => [
416
-                'func'       => 'cancel_registration',
417
-                'noheader'   => true,
418
-                'capability' => 'ee_edit_registration',
419
-                'obj_id'     => $REG_ID,
420
-            ],
421
-            'cancel_and_notify_registration'      => [
422
-                'func'       => 'cancel_registration',
423
-                'noheader'   => true,
424
-                'args'       => [true],
425
-                'capability' => 'ee_edit_registration',
426
-                'obj_id'     => $REG_ID,
427
-            ],
428
-            'cancel_registrations'                => [
429
-                'func'       => 'bulk_action_on_registrations',
430
-                'noheader'   => true,
431
-                'capability' => 'ee_edit_registrations',
432
-                'args'       => ['cancel'],
433
-            ],
434
-            'cancel_and_notify_registrations'     => [
435
-                'func'       => 'bulk_action_on_registrations',
436
-                'noheader'   => true,
437
-                'capability' => 'ee_edit_registrations',
438
-                'args'       => ['cancel', true],
439
-            ],
440
-            'wait_list_registration'              => [
441
-                'func'       => 'wait_list_registration',
442
-                'noheader'   => true,
443
-                'capability' => 'ee_edit_registration',
444
-                'obj_id'     => $REG_ID,
445
-            ],
446
-            'wait_list_and_notify_registration'   => [
447
-                'func'       => 'wait_list_registration',
448
-                'noheader'   => true,
449
-                'args'       => [true],
450
-                'capability' => 'ee_edit_registration',
451
-                'obj_id'     => $REG_ID,
452
-            ],
453
-            'contact_list'                        => [
454
-                'func'       => '_attendee_contact_list_table',
455
-                'capability' => 'ee_read_contacts',
456
-            ],
457
-            'add_new_attendee'                    => [
458
-                'func' => '_create_new_cpt_item',
459
-                'args' => [
460
-                    'new_attendee' => true,
461
-                    'capability'   => 'ee_edit_contacts',
462
-                ],
463
-            ],
464
-            'edit_attendee'                       => [
465
-                'func'       => '_edit_cpt_item',
466
-                'capability' => 'ee_edit_contacts',
467
-                'obj_id'     => $ATT_ID,
468
-            ],
469
-            'duplicate_attendee'                  => [
470
-                'func'       => '_duplicate_attendee',
471
-                'noheader'   => true,
472
-                'capability' => 'ee_edit_contacts',
473
-                'obj_id'     => $ATT_ID,
474
-            ],
475
-            'insert_attendee'                     => [
476
-                'func'       => '_insert_or_update_attendee',
477
-                'args'       => [
478
-                    'new_attendee' => true,
479
-                ],
480
-                'noheader'   => true,
481
-                'capability' => 'ee_edit_contacts',
482
-            ],
483
-            'update_attendee'                     => [
484
-                'func'       => '_insert_or_update_attendee',
485
-                'args'       => [
486
-                    'new_attendee' => false,
487
-                ],
488
-                'noheader'   => true,
489
-                'capability' => 'ee_edit_contacts',
490
-                'obj_id'     => $ATT_ID,
491
-            ],
492
-            'trash_attendees'                     => [
493
-                'func'       => '_trash_or_restore_attendees',
494
-                'args'       => [
495
-                    'trash' => 'true',
496
-                ],
497
-                'noheader'   => true,
498
-                'capability' => 'ee_delete_contacts',
499
-            ],
500
-            'trash_attendee'                      => [
501
-                'func'       => '_trash_or_restore_attendees',
502
-                'args'       => [
503
-                    'trash' => true,
504
-                ],
505
-                'noheader'   => true,
506
-                'capability' => 'ee_delete_contacts',
507
-                'obj_id'     => $ATT_ID,
508
-            ],
509
-            'restore_attendees'                   => [
510
-                'func'       => '_trash_or_restore_attendees',
511
-                'args'       => [
512
-                    'trash' => false,
513
-                ],
514
-                'noheader'   => true,
515
-                'capability' => 'ee_delete_contacts',
516
-                'obj_id'     => $ATT_ID,
517
-            ],
518
-            'resend_registration'                 => [
519
-                'func'       => '_resend_registration',
520
-                'noheader'   => true,
521
-                'capability' => 'ee_send_message',
522
-            ],
523
-            'registrations_report'                => [
524
-                'func'       => '_registrations_report',
525
-                'noheader'   => true,
526
-                'capability' => 'ee_read_registrations',
527
-            ],
528
-            'contact_list_export'                 => [
529
-                'func'       => '_contact_list_export',
530
-                'noheader'   => true,
531
-                'capability' => 'export',
532
-            ],
533
-            'contact_list_report'                 => [
534
-                'func'       => '_contact_list_report',
535
-                'noheader'   => true,
536
-                'capability' => 'ee_read_contacts',
537
-            ],
538
-        ];
539
-    }
540
-
541
-
542
-    protected function _set_page_config()
543
-    {
544
-        $REG_ID             = $this->request->getRequestParam('_REG_ID', 0, 'int');
545
-        $ATT_ID             = $this->request->getRequestParam('ATT_ID', 0, 'int');
546
-        $this->_page_config = [
547
-            'default'           => [
548
-                'nav'           => [
549
-                    'label' => esc_html__('Overview', 'event_espresso'),
550
-                    'icon' => 'dashicons-list-view',
551
-                    'order' => 5,
552
-                ],
553
-                'help_tabs'     => [
554
-                    'registrations_overview_help_tab'                       => [
555
-                        'title'    => esc_html__('Registrations Overview', 'event_espresso'),
556
-                        'filename' => 'registrations_overview',
557
-                    ],
558
-                    'registrations_overview_table_column_headings_help_tab' => [
559
-                        'title'    => esc_html__('Registrations Table Column Headings', 'event_espresso'),
560
-                        'filename' => 'registrations_overview_table_column_headings',
561
-                    ],
562
-                    'registrations_overview_filters_help_tab'               => [
563
-                        'title'    => esc_html__('Registration Filters', 'event_espresso'),
564
-                        'filename' => 'registrations_overview_filters',
565
-                    ],
566
-                    'registrations_overview_views_help_tab'                 => [
567
-                        'title'    => esc_html__('Registration Views', 'event_espresso'),
568
-                        'filename' => 'registrations_overview_views',
569
-                    ],
570
-                    'registrations_regoverview_other_help_tab'              => [
571
-                        'title'    => esc_html__('Registrations Other', 'event_espresso'),
572
-                        'filename' => 'registrations_overview_other',
573
-                    ],
574
-                ],
575
-                'list_table'    => 'EE_Registrations_List_Table',
576
-                'require_nonce' => false,
577
-            ],
578
-            'view_registration' => [
579
-                'nav'           => [
580
-                    'label'      => esc_html__('REG Details', 'event_espresso'),
581
-                    'icon' => 'dashicons-clipboard',
582
-                    'order'      => 15,
583
-                    'url'        => $REG_ID
584
-                        ? add_query_arg(['_REG_ID' => $REG_ID], $this->_current_page_view_url)
585
-                        : $this->_admin_base_url,
586
-                    'persistent' => false,
587
-                ],
588
-                'help_tabs'     => [
589
-                    'registrations_details_help_tab'                    => [
590
-                        'title'    => esc_html__('Registration Details', 'event_espresso'),
591
-                        'filename' => 'registrations_details',
592
-                    ],
593
-                    'registrations_details_table_help_tab'              => [
594
-                        'title'    => esc_html__('Registration Details Table', 'event_espresso'),
595
-                        'filename' => 'registrations_details_table',
596
-                    ],
597
-                    'registrations_details_form_answers_help_tab'       => [
598
-                        'title'    => esc_html__('Registration Form Answers', 'event_espresso'),
599
-                        'filename' => 'registrations_details_form_answers',
600
-                    ],
601
-                    'registrations_details_registrant_details_help_tab' => [
602
-                        'title'    => esc_html__('Contact Details', 'event_espresso'),
603
-                        'filename' => 'registrations_details_registrant_details',
604
-                    ],
605
-                ],
606
-                'metaboxes'     => array_merge(
607
-                    $this->_default_espresso_metaboxes,
608
-                    ['_registration_details_metaboxes']
609
-                ),
610
-                'require_nonce' => false,
611
-            ],
612
-            'new_registration'  => [
613
-                'nav'           => [
614
-                    'label'      => esc_html__('Add New Registration', 'event_espresso'),
615
-                    'icon' => 'dashicons-plus-alt',
616
-                    'url'        => '#',
617
-                    'order'      => 15,
618
-                    'persistent' => false,
619
-                ],
620
-                'metaboxes'     => $this->_default_espresso_metaboxes,
621
-                'labels'        => [
622
-                    'publishbox' => esc_html__('Save Registration', 'event_espresso'),
623
-                ],
624
-                'require_nonce' => false,
625
-            ],
626
-            'add_new_attendee'  => [
627
-                'nav'           => [
628
-                    'label'      => esc_html__('Add Contact', 'event_espresso'),
629
-                    'icon' => 'dashicons-plus-alt',
630
-                    'order'      => 15,
631
-                    'persistent' => false,
632
-                ],
633
-                'metaboxes'     => array_merge(
634
-                    $this->_default_espresso_metaboxes,
635
-                    ['_publish_post_box', 'attendee_editor_metaboxes']
636
-                ),
637
-                'require_nonce' => false,
638
-            ],
639
-            'edit_attendee'     => [
640
-                'nav'           => [
641
-                    'label'      => esc_html__('Edit Contact', 'event_espresso'),
642
-                    'icon' => 'dashicons-edit-large',
643
-                    'order'      => 15,
644
-                    'persistent' => false,
645
-                    'url'        => $ATT_ID
646
-                        ? add_query_arg(['ATT_ID' => $ATT_ID], $this->_current_page_view_url)
647
-                        : $this->_admin_base_url,
648
-                ],
649
-                'metaboxes'     => array_merge(
650
-                    $this->_default_espresso_metaboxes,
651
-                    ['attendee_editor_metaboxes']
652
-                ),
653
-                'require_nonce' => false,
654
-            ],
655
-            'contact_list'      => [
656
-                'nav'           => [
657
-                    'label' => esc_html__('Contact List', 'event_espresso'),
658
-                    'icon' => 'dashicons-id-alt',
659
-                    'order' => 20,
660
-                ],
661
-                'list_table'    => 'EE_Attendee_Contact_List_Table',
662
-                'help_tabs'     => [
663
-                    'registrations_contact_list_help_tab'                       => [
664
-                        'title'    => esc_html__('Registrations Contact List', 'event_espresso'),
665
-                        'filename' => 'registrations_contact_list',
666
-                    ],
667
-                    'registrations_contact-list_table_column_headings_help_tab' => [
668
-                        'title'    => esc_html__('Contact List Table Column Headings', 'event_espresso'),
669
-                        'filename' => 'registrations_contact_list_table_column_headings',
670
-                    ],
671
-                    'registrations_contact_list_views_help_tab'                 => [
672
-                        'title'    => esc_html__('Contact List Views', 'event_espresso'),
673
-                        'filename' => 'registrations_contact_list_views',
674
-                    ],
675
-                    'registrations_contact_list_other_help_tab'                 => [
676
-                        'title'    => esc_html__('Contact List Other', 'event_espresso'),
677
-                        'filename' => 'registrations_contact_list_other',
678
-                    ],
679
-                ],
680
-                'metaboxes'     => [],
681
-                'require_nonce' => false,
682
-            ],
683
-            // override default cpt routes
684
-            'create_new'        => '',
685
-            'edit'              => '',
686
-        ];
687
-    }
688
-
689
-
690
-    /**
691
-     * The below methods aren't used by this class currently
692
-     */
693
-    protected function _add_screen_options()
694
-    {
695
-    }
696
-
697
-
698
-    protected function _add_feature_pointers()
699
-    {
700
-    }
701
-
702
-
703
-    public function admin_init()
704
-    {
705
-        EE_Registry::$i18n_js_strings['update_att_qstns'] = esc_html__(
706
-            'click "Update Registration Questions" to save your changes',
707
-            'event_espresso'
708
-        );
709
-    }
710
-
711
-
712
-    public function admin_notices()
713
-    {
714
-    }
715
-
716
-
717
-    public function admin_footer_scripts()
718
-    {
719
-    }
720
-
721
-
722
-    /**
723
-     * get list of registration statuses
724
-     *
725
-     * @return void
726
-     * @throws EE_Error
727
-     */
728
-    private function _get_registration_status_array()
729
-    {
730
-        self::$_reg_status = EEM_Registration::reg_status_array([], true);
731
-    }
732
-
733
-
734
-    /**
735
-     * @throws InvalidArgumentException
736
-     * @throws InvalidDataTypeException
737
-     * @throws InvalidInterfaceException
738
-     * @since 4.10.2.p
739
-     */
740
-    protected function _add_screen_options_default()
741
-    {
742
-        $this->_per_page_screen_option();
743
-    }
744
-
745
-
746
-    /**
747
-     * @throws InvalidArgumentException
748
-     * @throws InvalidDataTypeException
749
-     * @throws InvalidInterfaceException
750
-     * @since 4.10.2.p
751
-     */
752
-    protected function _add_screen_options_contact_list()
753
-    {
754
-        $page_title              = $this->_admin_page_title;
755
-        $this->_admin_page_title = esc_html__('Contacts', 'event_espresso');
756
-        $this->_per_page_screen_option();
757
-        $this->_admin_page_title = $page_title;
758
-    }
759
-
760
-
761
-    public function load_scripts_styles()
762
-    {
763
-        // style
764
-        wp_register_style(
765
-            'espresso_reg',
766
-            REG_ASSETS_URL . 'espresso_registrations_admin.css',
767
-            ['ee-admin-css'],
768
-            EVENT_ESPRESSO_VERSION
769
-        );
770
-        wp_enqueue_style('espresso_reg');
771
-        // script
772
-        wp_register_script(
773
-            'espresso_reg',
774
-            REG_ASSETS_URL . 'espresso_registrations_admin.js',
775
-            ['jquery-ui-datepicker', 'jquery-ui-draggable', 'ee_admin_js'],
776
-            EVENT_ESPRESSO_VERSION,
777
-            true
778
-        );
779
-        wp_enqueue_script('espresso_reg');
780
-    }
781
-
782
-
783
-    /**
784
-     * @throws EE_Error
785
-     * @throws InvalidArgumentException
786
-     * @throws InvalidDataTypeException
787
-     * @throws InvalidInterfaceException
788
-     * @throws ReflectionException
789
-     * @since 4.10.2.p
790
-     */
791
-    public function load_scripts_styles_edit_attendee()
792
-    {
793
-        // stuff to only show up on our attendee edit details page.
794
-        $attendee_details_translations = [
795
-            'att_publish_text' => sprintf(
796
-            /* translators: The date and time */
797
-                wp_strip_all_tags(__('Created on: %s', 'event_espresso')),
798
-                '<b>' . $this->_cpt_model_obj->get_datetime('ATT_created') . '</b>'
799
-            ),
800
-        ];
801
-        wp_localize_script('espresso_reg', 'ATTENDEE_DETAILS', $attendee_details_translations);
802
-        wp_enqueue_script('jquery-validate');
803
-    }
804
-
805
-
806
-    /**
807
-     * @throws EE_Error
808
-     * @throws InvalidArgumentException
809
-     * @throws InvalidDataTypeException
810
-     * @throws InvalidInterfaceException
811
-     * @throws ReflectionException
812
-     * @since 4.10.2.p
813
-     */
814
-    public function load_scripts_styles_view_registration()
815
-    {
816
-        // styles
817
-        wp_enqueue_style('espresso-ui-theme');
818
-        // scripts
819
-        $this->_get_reg_custom_questions_form($this->_registration->ID());
820
-        $this->_reg_custom_questions_form->wp_enqueue_scripts();
821
-    }
822
-
823
-
824
-    public function load_scripts_styles_contact_list()
825
-    {
826
-        wp_dequeue_style('espresso_reg');
827
-        wp_register_style(
828
-            'espresso_att',
829
-            REG_ASSETS_URL . 'espresso_attendees_admin.css',
830
-            ['ee-admin-css'],
831
-            EVENT_ESPRESSO_VERSION
832
-        );
833
-        wp_enqueue_style('espresso_att');
834
-    }
835
-
836
-
837
-    public function load_scripts_styles_new_registration()
838
-    {
839
-        wp_register_script(
840
-            'ee-spco-for-admin',
841
-            REG_ASSETS_URL . 'spco_for_admin.js',
842
-            ['underscore', 'jquery'],
843
-            EVENT_ESPRESSO_VERSION,
844
-            true
845
-        );
846
-        wp_enqueue_script('ee-spco-for-admin');
847
-        add_filter('FHEE__EED_Ticket_Selector__load_tckt_slctr_assets', '__return_true');
848
-        EE_Form_Section_Proper::wp_enqueue_scripts();
849
-        EED_Ticket_Selector::load_tckt_slctr_assets();
850
-        EE_Datepicker_Input::enqueue_styles_and_scripts();
851
-    }
852
-
853
-
854
-    public function AHEE__EE_Admin_Page__route_admin_request_resend_registration()
855
-    {
856
-        add_filter('FHEE_load_EE_messages', '__return_true');
857
-    }
858
-
859
-
860
-    public function AHEE__EE_Admin_Page__route_admin_request_approve_registration()
861
-    {
862
-        add_filter('FHEE_load_EE_messages', '__return_true');
863
-    }
864
-
865
-
866
-    /**
867
-     * @throws EE_Error
868
-     * @throws InvalidArgumentException
869
-     * @throws InvalidDataTypeException
870
-     * @throws InvalidInterfaceException
871
-     * @throws ReflectionException
872
-     * @since 4.10.2.p
873
-     */
874
-    protected function _set_list_table_views_default()
875
-    {
876
-        // for notification related bulk actions we need to make sure only active messengers have an option.
877
-        EED_Messages::set_autoloaders();
878
-        /** @type EE_Message_Resource_Manager $message_resource_manager */
879
-        $message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
880
-        $active_mts               = $message_resource_manager->list_of_active_message_types();
881
-        // key= bulk_action_slug, value= message type.
882
-        $match_array = [
883
-            'approve_registrations'    => 'registration',
884
-            'decline_registrations'    => 'declined_registration',
885
-            'pending_registrations'    => 'pending_approval',
886
-            'no_approve_registrations' => 'not_approved_registration',
887
-            'cancel_registrations'     => 'cancelled_registration',
888
-        ];
889
-        $can_send    = EE_Registry::instance()->CAP->current_user_can(
890
-            'ee_send_message',
891
-            'batch_send_messages'
892
-        );
893
-        /** setup reg status bulk actions **/
894
-        $def_reg_status_actions['approve_registrations'] = esc_html__('Approve Registrations', 'event_espresso');
895
-        if ($can_send && in_array($match_array['approve_registrations'], $active_mts, true)) {
896
-            $def_reg_status_actions['approve_and_notify_registrations'] = esc_html__(
897
-                'Approve and Notify Registrations',
898
-                'event_espresso'
899
-            );
900
-        }
901
-        $def_reg_status_actions['decline_registrations'] = esc_html__('Decline Registrations', 'event_espresso');
902
-        if ($can_send && in_array($match_array['decline_registrations'], $active_mts, true)) {
903
-            $def_reg_status_actions['decline_and_notify_registrations'] = esc_html__(
904
-                'Decline and Notify Registrations',
905
-                'event_espresso'
906
-            );
907
-        }
908
-        $def_reg_status_actions['pending_registrations'] = esc_html__(
909
-            'Set Registrations to Pending Payment',
910
-            'event_espresso'
911
-        );
912
-        if ($can_send && in_array($match_array['pending_registrations'], $active_mts, true)) {
913
-            $def_reg_status_actions['pending_and_notify_registrations'] = esc_html__(
914
-                'Set Registrations to Pending Payment and Notify',
915
-                'event_espresso'
916
-            );
917
-        }
918
-        $def_reg_status_actions['no_approve_registrations'] = esc_html__(
919
-            'Set Registrations to Not Approved',
920
-            'event_espresso'
921
-        );
922
-        if ($can_send && in_array($match_array['no_approve_registrations'], $active_mts, true)) {
923
-            $def_reg_status_actions['no_approve_and_notify_registrations'] = esc_html__(
924
-                'Set Registrations to Not Approved and Notify',
925
-                'event_espresso'
926
-            );
927
-        }
928
-        $def_reg_status_actions['cancel_registrations'] = esc_html__('Cancel Registrations', 'event_espresso');
929
-        if ($can_send && in_array($match_array['cancel_registrations'], $active_mts, true)) {
930
-            $def_reg_status_actions['cancel_and_notify_registrations'] = esc_html__(
931
-                'Cancel Registrations and Notify',
932
-                'event_espresso'
933
-            );
934
-        }
935
-        $def_reg_status_actions = apply_filters(
936
-            'FHEE__Registrations_Admin_Page___set_list_table_views_default__def_reg_status_actions_array',
937
-            $def_reg_status_actions,
938
-            $active_mts,
939
-            $can_send
940
-        );
941
-
942
-        $this->_views = [
943
-            'all'   => [
944
-                'slug'        => 'all',
945
-                'label'       => esc_html__('View All Registrations', 'event_espresso'),
946
-                'count'       => 0,
947
-                'bulk_action' => array_merge(
948
-                    $def_reg_status_actions,
949
-                    [
950
-                        'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
951
-                    ]
952
-                ),
953
-            ],
954
-            'month' => [
955
-                'slug'        => 'month',
956
-                'label'       => esc_html__('This Month', 'event_espresso'),
957
-                'count'       => 0,
958
-                'bulk_action' => array_merge(
959
-                    $def_reg_status_actions,
960
-                    [
961
-                        'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
962
-                    ]
963
-                ),
964
-            ],
965
-            'today' => [
966
-                'slug'        => 'today',
967
-                'label'       => sprintf(
968
-                    esc_html__('Today - %s', 'event_espresso'),
969
-                    date('M d, Y', current_time('timestamp'))
970
-                ),
971
-                'count'       => 0,
972
-                'bulk_action' => array_merge(
973
-                    $def_reg_status_actions,
974
-                    [
975
-                        'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
976
-                    ]
977
-                ),
978
-            ],
979
-        ];
980
-        if (
981
-            EE_Registry::instance()->CAP->current_user_can(
982
-                'ee_delete_registrations',
983
-                'espresso_registrations_delete_registration'
984
-            )
985
-        ) {
986
-            $this->_views['incomplete'] = [
987
-                'slug'        => 'incomplete',
988
-                'label'       => esc_html__('Incomplete', 'event_espresso'),
989
-                'count'       => 0,
990
-                'bulk_action' => [
991
-                    'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
992
-                ],
993
-            ];
994
-            $this->_views['trash']      = [
995
-                'slug'        => 'trash',
996
-                'label'       => esc_html__('Trash', 'event_espresso'),
997
-                'count'       => 0,
998
-                'bulk_action' => [
999
-                    'restore_registrations' => esc_html__('Restore Registrations', 'event_espresso'),
1000
-                    'delete_registrations'  => esc_html__('Delete Registrations Permanently', 'event_espresso'),
1001
-                ],
1002
-            ];
1003
-        }
1004
-    }
1005
-
1006
-
1007
-    protected function _set_list_table_views_contact_list()
1008
-    {
1009
-        $this->_views = [
1010
-            'in_use' => [
1011
-                'slug'        => 'in_use',
1012
-                'label'       => esc_html__('In Use', 'event_espresso'),
1013
-                'count'       => 0,
1014
-                'bulk_action' => [
1015
-                    'trash_attendees' => esc_html__('Move to Trash', 'event_espresso'),
1016
-                ],
1017
-            ],
1018
-        ];
1019
-        if (
1020
-            EE_Registry::instance()->CAP->current_user_can(
1021
-                'ee_delete_contacts',
1022
-                'espresso_registrations_trash_attendees'
1023
-            )
1024
-        ) {
1025
-            $this->_views['trash'] = [
1026
-                'slug'        => 'trash',
1027
-                'label'       => esc_html__('Trash', 'event_espresso'),
1028
-                'count'       => 0,
1029
-                'bulk_action' => [
1030
-                    'restore_attendees' => esc_html__('Restore from Trash', 'event_espresso'),
1031
-                ],
1032
-            ];
1033
-        }
1034
-    }
1035
-
1036
-
1037
-    /**
1038
-     * @return array
1039
-     * @throws EE_Error
1040
-     */
1041
-    protected function _registration_legend_items()
1042
-    {
1043
-        $fc_items = [
1044
-            'star-icon'        => [
1045
-                'class' => 'dashicons dashicons-star-filled gold-icon',
1046
-                'desc'  => esc_html__('This is the Primary Registrant', 'event_espresso'),
1047
-            ],
1048
-            'view_details'     => [
1049
-                'class' => 'dashicons dashicons-clipboard',
1050
-                'desc'  => esc_html__('View Registration Details', 'event_espresso'),
1051
-            ],
1052
-            'edit_attendee'    => [
1053
-                'class' => 'dashicons dashicons-admin-users',
1054
-                'desc'  => esc_html__('Edit Contact Details', 'event_espresso'),
1055
-            ],
1056
-            'view_transaction' => [
1057
-                'class' => 'dashicons dashicons-cart',
1058
-                'desc'  => esc_html__('View Transaction Details', 'event_espresso'),
1059
-            ],
1060
-            'view_invoice'     => [
1061
-                'class' => 'dashicons dashicons-media-spreadsheet',
1062
-                'desc'  => esc_html__('View Transaction Invoice', 'event_espresso'),
1063
-            ],
1064
-        ];
1065
-        if (
1066
-            EE_Registry::instance()->CAP->current_user_can(
1067
-                'ee_send_message',
1068
-                'espresso_registrations_resend_registration'
1069
-            )
1070
-        ) {
1071
-            $fc_items['resend_registration'] = [
1072
-                'class' => 'dashicons dashicons-email-alt',
1073
-                'desc'  => esc_html__('Resend Registration Details', 'event_espresso'),
1074
-            ];
1075
-        } else {
1076
-            $fc_items['blank'] = ['class' => 'blank', 'desc' => ''];
1077
-        }
1078
-        if (
1079
-            EE_Registry::instance()->CAP->current_user_can(
1080
-                'ee_read_global_messages',
1081
-                'view_filtered_messages'
1082
-            )
1083
-        ) {
1084
-            $related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
1085
-            if (is_array($related_for_icon) && isset($related_for_icon['css_class'], $related_for_icon['label'])) {
1086
-                $fc_items['view_related_messages'] = [
1087
-                    'class' => $related_for_icon['css_class'],
1088
-                    'desc'  => $related_for_icon['label'],
1089
-                ];
1090
-            }
1091
-        }
1092
-        $sc_items = [
1093
-            'approved_status'   => [
1094
-                'class' => 'ee-status-legend ee-status-bg--' . EEM_Registration::status_id_approved,
1095
-                'desc'  => EEH_Template::pretty_status(
1096
-                    EEM_Registration::status_id_approved,
1097
-                    false,
1098
-                    'sentence'
1099
-                ),
1100
-            ],
1101
-            'pending_status'    => [
1102
-                'class' => 'ee-status-legend ee-status-bg--' . EEM_Registration::status_id_pending_payment,
1103
-                'desc'  => EEH_Template::pretty_status(
1104
-                    EEM_Registration::status_id_pending_payment,
1105
-                    false,
1106
-                    'sentence'
1107
-                ),
1108
-            ],
1109
-            'wait_list'         => [
1110
-                'class' => 'ee-status-legend ee-status-bg--' . EEM_Registration::status_id_wait_list,
1111
-                'desc'  => EEH_Template::pretty_status(
1112
-                    EEM_Registration::status_id_wait_list,
1113
-                    false,
1114
-                    'sentence'
1115
-                ),
1116
-            ],
1117
-            'incomplete_status' => [
1118
-                'class' => 'ee-status-legend ee-status-bg--' . EEM_Registration::status_id_incomplete,
1119
-                'desc'  => EEH_Template::pretty_status(
1120
-                    EEM_Registration::status_id_incomplete,
1121
-                    false,
1122
-                    'sentence'
1123
-                ),
1124
-            ],
1125
-            'not_approved'      => [
1126
-                'class' => 'ee-status-legend ee-status-bg--' . EEM_Registration::status_id_not_approved,
1127
-                'desc'  => EEH_Template::pretty_status(
1128
-                    EEM_Registration::status_id_not_approved,
1129
-                    false,
1130
-                    'sentence'
1131
-                ),
1132
-            ],
1133
-            'declined_status'   => [
1134
-                'class' => 'ee-status-legend ee-status-bg--' . EEM_Registration::status_id_declined,
1135
-                'desc'  => EEH_Template::pretty_status(
1136
-                    EEM_Registration::status_id_declined,
1137
-                    false,
1138
-                    'sentence'
1139
-                ),
1140
-            ],
1141
-            'cancelled_status'  => [
1142
-                'class' => 'ee-status-legend ee-status-bg--' . EEM_Registration::status_id_cancelled,
1143
-                'desc'  => EEH_Template::pretty_status(
1144
-                    EEM_Registration::status_id_cancelled,
1145
-                    false,
1146
-                    'sentence'
1147
-                ),
1148
-            ],
1149
-        ];
1150
-        return array_merge($fc_items, $sc_items);
1151
-    }
1152
-
1153
-
1154
-
1155
-    /***************************************        REGISTRATION OVERVIEW        **************************************/
1156
-
1157
-
1158
-    /**
1159
-     * @throws DomainException
1160
-     * @throws EE_Error
1161
-     * @throws InvalidArgumentException
1162
-     * @throws InvalidDataTypeException
1163
-     * @throws InvalidInterfaceException
1164
-     */
1165
-    protected function _registrations_overview_list_table()
1166
-    {
1167
-        $this->appendAddNewRegistrationButtonToPageTitle();
1168
-        $header_text                  = '';
1169
-        $admin_page_header_decorators = [
1170
-            'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\AttendeeFilterHeader',
1171
-            'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\EventFilterHeader',
1172
-            'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\DateFilterHeader',
1173
-            'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\TicketFilterHeader',
1174
-        ];
1175
-        foreach ($admin_page_header_decorators as $admin_page_header_decorator) {
1176
-            $filter_header_decorator = $this->loader->getNew($admin_page_header_decorator);
1177
-            $header_text = $filter_header_decorator->getHeaderText($header_text);
1178
-        }
1179
-        $this->_template_args['before_list_table']  = $header_text;
1180
-        $this->_template_args['after_list_table']  = $this->_display_legend($this->_registration_legend_items());
1181
-        $this->display_admin_list_table_page_with_no_sidebar();
1182
-    }
1183
-
1184
-
1185
-    /**
1186
-     * @throws EE_Error
1187
-     * @throws InvalidArgumentException
1188
-     * @throws InvalidDataTypeException
1189
-     * @throws InvalidInterfaceException
1190
-     */
1191
-    private function appendAddNewRegistrationButtonToPageTitle()
1192
-    {
1193
-        $EVT_ID = $this->request->getRequestParam('event_id', 0, 'int');
1194
-        if (
1195
-            $EVT_ID
1196
-            && EE_Registry::instance()->CAP->current_user_can(
1197
-                'ee_edit_registrations',
1198
-                'espresso_registrations_new_registration',
1199
-                $EVT_ID
1200
-            )
1201
-        ) {
1202
-            $this->_admin_page_title .= ' ' . $this->get_action_link_or_button(
1203
-                'new_registration',
1204
-                'add-registrant',
1205
-                ['event_id' => $EVT_ID],
1206
-                'add-new-h2'
1207
-            );
1208
-        }
1209
-    }
1210
-
1211
-
1212
-    /**
1213
-     * This sets the _registration property for the registration details screen
1214
-     *
1215
-     * @return void
1216
-     * @throws EE_Error
1217
-     * @throws InvalidArgumentException
1218
-     * @throws InvalidDataTypeException
1219
-     * @throws InvalidInterfaceException
1220
-     */
1221
-    private function _set_registration_object()
1222
-    {
1223
-        // get out if we've already set the object
1224
-        if ($this->_registration instanceof EE_Registration) {
1225
-            return;
1226
-        }
1227
-        $REG_ID = $this->request->getRequestParam('_REG_ID', 0, 'int');
1228
-        if ($this->_registration = $this->getRegistrationModel()->get_one_by_ID($REG_ID)) {
1229
-            return;
1230
-        }
1231
-        $error_msg = sprintf(
1232
-            esc_html__(
1233
-                'An error occurred and the details for Registration ID #%s could not be retrieved.',
1234
-                'event_espresso'
1235
-            ),
1236
-            $REG_ID
1237
-        );
1238
-        EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
1239
-        $this->_registration = null;
1240
-    }
1241
-
1242
-
1243
-    /**
1244
-     * Used to retrieve registrations for the list table.
1245
-     *
1246
-     * @param int  $per_page
1247
-     * @param bool $count
1248
-     * @param bool $this_month
1249
-     * @param bool $today
1250
-     * @return EE_Registration[]|int
1251
-     * @throws EE_Error
1252
-     * @throws InvalidArgumentException
1253
-     * @throws InvalidDataTypeException
1254
-     * @throws InvalidInterfaceException
1255
-     */
1256
-    public function get_registrations(
1257
-        $per_page = 10,
1258
-        $count = false,
1259
-        $this_month = false,
1260
-        $today = false
1261
-    ) {
1262
-        if ($this_month) {
1263
-            $this->request->setRequestParam('status', 'month');
1264
-        }
1265
-        if ($today) {
1266
-            $this->request->setRequestParam('status', 'today');
1267
-        }
1268
-        $query_params = $this->_get_registration_query_parameters($this->request->requestParams(), $per_page, $count);
1269
-        /**
1270
-         * Override the default groupby added by EEM_Base so that sorts with multiple order bys work as expected
1271
-         *
1272
-         * @link https://events.codebasehq.com/projects/event-espresso/tickets/10093
1273
-         * @see  https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1274
-         *                      or if you have the development copy of EE you can view this at the path:
1275
-         *                      /docs/G--Model-System/model-query-params.md
1276
-         */
1277
-        $query_params['group_by'] = '';
1278
-
1279
-        return $count
1280
-            ? $this->getRegistrationModel()->count($query_params)
1281
-            /** @type EE_Registration[] */
1282
-            : $this->getRegistrationModel()->get_all($query_params);
1283
-    }
1284
-
1285
-
1286
-    /**
1287
-     * Retrieves the query parameters to be used by the Registration model for getting registrations.
1288
-     * Note: this listens to values on the request for some of the query parameters.
1289
-     *
1290
-     * @param array $request
1291
-     * @param int   $per_page
1292
-     * @param bool  $count
1293
-     * @return array
1294
-     * @throws EE_Error
1295
-     * @throws InvalidArgumentException
1296
-     * @throws InvalidDataTypeException
1297
-     * @throws InvalidInterfaceException
1298
-     */
1299
-    protected function _get_registration_query_parameters(
1300
-        $request = [],
1301
-        $per_page = 10,
1302
-        $count = false
1303
-    ) {
1304
-        /** @var EventEspresso\core\domain\services\admin\registrations\list_table\QueryBuilder $list_table_query_builder */
1305
-        $list_table_query_builder = $this->loader->getNew(
1306
-            'EventEspresso\core\domain\services\admin\registrations\list_table\QueryBuilder',
1307
-            [null, null, $request]
1308
-        );
1309
-        return $list_table_query_builder->getQueryParams($per_page, $count);
1310
-    }
1311
-
1312
-
1313
-    public function get_registration_status_array()
1314
-    {
1315
-        return self::$_reg_status;
1316
-    }
1317
-
1318
-
1319
-
1320
-
1321
-    /***************************************        REGISTRATION DETAILS        ***************************************/
1322
-    /**
1323
-     * generates HTML for the View Registration Details Admin page
1324
-     *
1325
-     * @return void
1326
-     * @throws DomainException
1327
-     * @throws EE_Error
1328
-     * @throws InvalidArgumentException
1329
-     * @throws InvalidDataTypeException
1330
-     * @throws InvalidInterfaceException
1331
-     * @throws EntityNotFoundException
1332
-     * @throws ReflectionException
1333
-     */
1334
-    protected function _registration_details()
1335
-    {
1336
-        $this->_template_args = [];
1337
-        $this->_set_registration_object();
1338
-        if (is_object($this->_registration)) {
1339
-            $transaction                                   = $this->_registration->transaction()
1340
-                ? $this->_registration->transaction()
1341
-                : EE_Transaction::new_instance();
1342
-            $this->_session                                = $transaction->session_data();
1343
-            $event_id                                      = $this->_registration->event_ID();
1344
-            $this->_template_args['reg_nmbr']['value']     = $this->_registration->ID();
1345
-            $this->_template_args['reg_nmbr']['label']     = esc_html__('Registration Number', 'event_espresso');
1346
-            $this->_template_args['reg_datetime']['value'] = $this->_registration->get_i18n_datetime('REG_date');
1347
-            $this->_template_args['reg_datetime']['label'] = esc_html__('Date', 'event_espresso');
1348
-            $this->_template_args['grand_total']           = $transaction->total();
1349
-            $this->_template_args['currency_sign']         = EE_Registry::instance()->CFG->currency->sign;
1350
-            // link back to overview
1351
-            $this->_template_args['reg_overview_url']            = REG_ADMIN_URL;
1352
-            $this->_template_args['registration']                = $this->_registration;
1353
-            $this->_template_args['filtered_registrations_link'] = EE_Admin_Page::add_query_args_and_nonce(
1354
-                [
1355
-                    'action'   => 'default',
1356
-                    'event_id' => $event_id,
1357
-                ],
1358
-                REG_ADMIN_URL
1359
-            );
1360
-            $this->_template_args['filtered_transactions_link']  = EE_Admin_Page::add_query_args_and_nonce(
1361
-                [
1362
-                    'action' => 'default',
1363
-                    'EVT_ID' => $event_id,
1364
-                    'page'   => 'espresso_transactions',
1365
-                ],
1366
-                admin_url('admin.php')
1367
-            );
1368
-            $this->_template_args['event_link']                  = EE_Admin_Page::add_query_args_and_nonce(
1369
-                [
1370
-                    'page'   => 'espresso_events',
1371
-                    'action' => 'edit',
1372
-                    'post'   => $event_id,
1373
-                ],
1374
-                admin_url('admin.php')
1375
-            );
1376
-            // next and previous links
1377
-            $next_reg                                      = $this->_registration->next(
1378
-                null,
1379
-                [],
1380
-                'REG_ID'
1381
-            );
1382
-            $this->_template_args['next_registration']     = $next_reg
1383
-                ? $this->_next_link(
1384
-                    EE_Admin_Page::add_query_args_and_nonce(
1385
-                        [
1386
-                            'action'  => 'view_registration',
1387
-                            '_REG_ID' => $next_reg['REG_ID'],
1388
-                        ],
1389
-                        REG_ADMIN_URL
1390
-                    ),
1391
-                    'dashicons dashicons-arrow-right ee-icon-size-22'
1392
-                )
1393
-                : '';
1394
-            $previous_reg                                  = $this->_registration->previous(
1395
-                null,
1396
-                [],
1397
-                'REG_ID'
1398
-            );
1399
-            $this->_template_args['previous_registration'] = $previous_reg
1400
-                ? $this->_previous_link(
1401
-                    EE_Admin_Page::add_query_args_and_nonce(
1402
-                        [
1403
-                            'action'  => 'view_registration',
1404
-                            '_REG_ID' => $previous_reg['REG_ID'],
1405
-                        ],
1406
-                        REG_ADMIN_URL
1407
-                    ),
1408
-                    'dashicons dashicons-arrow-left ee-icon-size-22'
1409
-                )
1410
-                : '';
1411
-            // grab header
1412
-            $template_path                             = REG_TEMPLATE_PATH . 'reg_admin_details_header.template.php';
1413
-            $this->_template_args['REG_ID']            = $this->_registration->ID();
1414
-            $this->_template_args['admin_page_header'] = EEH_Template::display_template(
1415
-                $template_path,
1416
-                $this->_template_args,
1417
-                true
1418
-            );
1419
-        } else {
1420
-            $this->_template_args['admin_page_header'] = '';
1421
-            $this->_display_espresso_notices();
1422
-        }
1423
-        // the details template wrapper
1424
-        $this->display_admin_page_with_sidebar();
1425
-    }
1426
-
1427
-
1428
-    /**
1429
-     * @throws EE_Error
1430
-     * @throws InvalidArgumentException
1431
-     * @throws InvalidDataTypeException
1432
-     * @throws InvalidInterfaceException
1433
-     * @throws ReflectionException
1434
-     * @since 4.10.2.p
1435
-     */
1436
-    protected function _registration_details_metaboxes()
1437
-    {
1438
-        do_action('AHEE__Registrations_Admin_Page___registration_details_metabox__start', $this);
1439
-        $this->_set_registration_object();
1440
-        $attendee = $this->_registration instanceof EE_Registration ? $this->_registration->attendee() : null;
1441
-        $this->addMetaBox(
1442
-            'edit-reg-status-mbox',
1443
-            esc_html__('Registration Status', 'event_espresso'),
1444
-            [$this, 'set_reg_status_buttons_metabox'],
1445
-            $this->_wp_page_slug
1446
-        );
1447
-        $this->addMetaBox(
1448
-            'edit-reg-details-mbox',
1449
-            '<span>' . esc_html__('Registration Details', 'event_espresso')
1450
-            . '&nbsp;<span class="dashicons dashicons-clipboard"></span></span>',
1451
-            [$this, '_reg_details_meta_box'],
1452
-            $this->_wp_page_slug
1453
-        );
1454
-        if (
1455
-            $attendee instanceof EE_Attendee
1456
-            && EE_Registry::instance()->CAP->current_user_can(
1457
-                'ee_read_registration',
1458
-                'edit-reg-questions-mbox',
1459
-                $this->_registration->ID()
1460
-            )
1461
-        ) {
1462
-            $this->addMetaBox(
1463
-                'edit-reg-questions-mbox',
1464
-                esc_html__('Registration Form Answers', 'event_espresso'),
1465
-                [$this, '_reg_questions_meta_box'],
1466
-                $this->_wp_page_slug
1467
-            );
1468
-        }
1469
-        $this->addMetaBox(
1470
-            'edit-reg-registrant-mbox',
1471
-            esc_html__('Contact Details', 'event_espresso'),
1472
-            [$this, '_reg_registrant_side_meta_box'],
1473
-            $this->_wp_page_slug,
1474
-            'side'
1475
-        );
1476
-        if ($this->_registration->group_size() > 1) {
1477
-            $this->addMetaBox(
1478
-                'edit-reg-attendees-mbox',
1479
-                esc_html__('Other Registrations in this Transaction', 'event_espresso'),
1480
-                [$this, '_reg_attendees_meta_box'],
1481
-                $this->_wp_page_slug
1482
-            );
1483
-        }
1484
-    }
1485
-
1486
-
1487
-    /**
1488
-     * set_reg_status_buttons_metabox
1489
-     *
1490
-     * @return void
1491
-     * @throws EE_Error
1492
-     * @throws EntityNotFoundException
1493
-     * @throws InvalidArgumentException
1494
-     * @throws InvalidDataTypeException
1495
-     * @throws InvalidInterfaceException
1496
-     * @throws ReflectionException
1497
-     */
1498
-    public function set_reg_status_buttons_metabox()
1499
-    {
1500
-        $this->_set_registration_object();
1501
-        $change_reg_status_form = $this->_generate_reg_status_change_form();
1502
-        $output                 = $change_reg_status_form->form_open(
1503
-            self::add_query_args_and_nonce(
1504
-                [
1505
-                    'action' => 'change_reg_status',
1506
-                ],
1507
-                REG_ADMIN_URL
1508
-            )
1509
-        );
1510
-        $output                 .= $change_reg_status_form->get_html();
1511
-        $output                 .= $change_reg_status_form->form_close();
1512
-        echo wp_kses($output, AllowedTags::getWithFormTags());
1513
-    }
1514
-
1515
-
1516
-    /**
1517
-     * @return EE_Form_Section_Proper
1518
-     * @throws EE_Error
1519
-     * @throws InvalidArgumentException
1520
-     * @throws InvalidDataTypeException
1521
-     * @throws InvalidInterfaceException
1522
-     * @throws EntityNotFoundException
1523
-     * @throws ReflectionException
1524
-     */
1525
-    protected function _generate_reg_status_change_form()
1526
-    {
1527
-        $reg_status_change_form_array = [
1528
-            'name'            => 'reg_status_change_form',
1529
-            'html_id'         => 'reg-status-change-form',
1530
-            'layout_strategy' => new EE_Admin_Two_Column_Layout(),
1531
-            'subsections'     => [
1532
-                'return'         => new EE_Hidden_Input(
1533
-                    [
1534
-                        'name'    => 'return',
1535
-                        'default' => 'view_registration',
1536
-                    ]
1537
-                ),
1538
-                'REG_ID'         => new EE_Hidden_Input(
1539
-                    [
1540
-                        'name'    => 'REG_ID',
1541
-                        'default' => $this->_registration->ID(),
1542
-                    ]
1543
-                ),
1544
-            ],
1545
-        ];
1546
-        if (
1547
-            EE_Registry::instance()->CAP->current_user_can(
1548
-                'ee_edit_registration',
1549
-                'toggle_registration_status',
1550
-                $this->_registration->ID()
1551
-            )
1552
-        ) {
1553
-            $reg_status_change_form_array['subsections']['reg_status']         = new EE_Select_Input(
1554
-                $this->_get_reg_statuses(),
1555
-                [
1556
-                    'html_label_text' => esc_html__('Change Registration Status to', 'event_espresso'),
1557
-                    'default'         => $this->_registration->status_ID(),
1558
-                ]
1559
-            );
1560
-            $reg_status_change_form_array['subsections']['send_notifications'] = new EE_Yes_No_Input(
1561
-                [
1562
-                    'html_label_text' => esc_html__('Send Related Messages', 'event_espresso'),
1563
-                    'default'         => false,
1564
-                    'html_help_text'  => esc_html__(
1565
-                        'If set to "Yes", then the related messages will be sent to the registrant.',
1566
-                        'event_espresso'
1567
-                    ),
1568
-                ]
1569
-            );
1570
-            $reg_status_change_form_array['subsections']['submit']             = new EE_Submit_Input(
1571
-                [
1572
-                    'html_class'      => 'button--primary',
1573
-                    'html_label_text' => '&nbsp;',
1574
-                    'default'         => esc_html__('Update Registration Status', 'event_espresso'),
1575
-                ]
1576
-            );
1577
-        }
1578
-        return new EE_Form_Section_Proper($reg_status_change_form_array);
1579
-    }
1580
-
1581
-
1582
-    /**
1583
-     * Returns an array of all the buttons for the various statuses and switch status actions
1584
-     *
1585
-     * @return array
1586
-     * @throws EE_Error
1587
-     * @throws InvalidArgumentException
1588
-     * @throws InvalidDataTypeException
1589
-     * @throws InvalidInterfaceException
1590
-     * @throws EntityNotFoundException
1591
-     */
1592
-    protected function _get_reg_statuses()
1593
-    {
1594
-        $reg_status_array = $this->getRegistrationModel()->reg_status_array();
1595
-        unset($reg_status_array[ EEM_Registration::status_id_incomplete ]);
1596
-        // get current reg status
1597
-        $current_status = $this->_registration->status_ID();
1598
-        // is registration for free event? This will determine whether to display the pending payment option
1599
-        if (
1600
-            $current_status !== EEM_Registration::status_id_pending_payment
1601
-            && EEH_Money::compare_floats($this->_registration->ticket()->price(), 0.00)
1602
-        ) {
1603
-            unset($reg_status_array[ EEM_Registration::status_id_pending_payment ]);
1604
-        }
1605
-        return $this->getStatusModel()->localized_status($reg_status_array, false, 'sentence');
1606
-    }
1607
-
1608
-
1609
-    /**
1610
-     * This method is used when using _REG_ID from request which may or may not be an array of reg_ids.
1611
-     *
1612
-     * @param bool $status REG status given for changing registrations to.
1613
-     * @param bool $notify Whether to send messages notifications or not.
1614
-     * @return array (array with reg_id(s) updated and whether update was successful.
1615
-     * @throws DomainException
1616
-     * @throws EE_Error
1617
-     * @throws EntityNotFoundException
1618
-     * @throws InvalidArgumentException
1619
-     * @throws InvalidDataTypeException
1620
-     * @throws InvalidInterfaceException
1621
-     * @throws ReflectionException
1622
-     * @throws RuntimeException
1623
-     */
1624
-    protected function _set_registration_status_from_request($status = false, $notify = false)
1625
-    {
1626
-        $REG_IDs = $this->request->requestParamIsSet('reg_status_change_form')
1627
-            ? $this->request->getRequestParam('reg_status_change_form[REG_ID]', [], 'int', true)
1628
-            : $this->request->getRequestParam('_REG_ID', [], 'int', true);
1629
-
1630
-        // sanitize $REG_IDs
1631
-        $REG_IDs = array_map('absint', $REG_IDs);
1632
-        // and remove empty entries
1633
-        $REG_IDs = array_filter($REG_IDs);
1634
-
1635
-        $result = $this->_set_registration_status($REG_IDs, $status, $notify);
1636
-
1637
-        /**
1638
-         * Set and filter $_req_data['_REG_ID'] for any potential future messages notifications.
1639
-         * Currently this value is used downstream by the _process_resend_registration method.
1640
-         *
1641
-         * @param int|array                $registration_ids The registration ids that have had their status changed successfully.
1642
-         * @param bool                     $status           The status registrations were changed to.
1643
-         * @param bool                     $success          If the status was changed successfully for all registrations.
1644
-         * @param Registrations_Admin_Page $admin_page_object
1645
-         */
1646
-        $REG_ID = apply_filters(
1647
-            'FHEE__Registrations_Admin_Page___set_registration_status_from_request__REG_IDs',
1648
-            $result['REG_ID'],
1649
-            $status,
1650
-            $result['success'],
1651
-            $this
1652
-        );
1653
-        $this->request->setRequestParam('_REG_ID', $REG_ID);
1654
-
1655
-        // notify?
1656
-        if (
1657
-            $notify
1658
-            && $result['success']
1659
-            && ! empty($REG_ID)
1660
-            && EE_Registry::instance()->CAP->current_user_can(
1661
-                'ee_send_message',
1662
-                'espresso_registrations_resend_registration'
1663
-            )
1664
-        ) {
1665
-            $this->_process_resend_registration();
1666
-        }
1667
-        return $result;
1668
-    }
1669
-
1670
-
1671
-    /**
1672
-     * Set the registration status for the given reg_id (which may or may not be an array, it gets typecast to an
1673
-     * array). Note, this method does NOT take care of possible notifications.  That is required by calling code.
1674
-     *
1675
-     * @param array  $REG_IDs
1676
-     * @param string $status
1677
-     * @param bool   $notify Used to indicate whether notification was requested or not.  This determines the context
1678
-     *                       slug sent with setting the registration status.
1679
-     * @return array (an array with 'success' key representing whether status change was successful, and 'REG_ID' as
1680
-     * @throws EE_Error
1681
-     * @throws InvalidArgumentException
1682
-     * @throws InvalidDataTypeException
1683
-     * @throws InvalidInterfaceException
1684
-     * @throws ReflectionException
1685
-     * @throws RuntimeException
1686
-     * @throws EntityNotFoundException
1687
-     * @throws DomainException
1688
-     */
1689
-    protected function _set_registration_status($REG_IDs = [], $status = '', $notify = false)
1690
-    {
1691
-        $success = false;
1692
-        // typecast $REG_IDs
1693
-        $REG_IDs = (array) $REG_IDs;
1694
-        if (! empty($REG_IDs)) {
1695
-            $success = true;
1696
-            // set default status if none is passed
1697
-            $status         = $status ?: EEM_Registration::status_id_pending_payment;
1698
-            $status_context = $notify
1699
-                ? Domain::CONTEXT_REGISTRATION_STATUS_CHANGE_REGISTRATION_ADMIN_NOTIFY
1700
-                : Domain::CONTEXT_REGISTRATION_STATUS_CHANGE_REGISTRATION_ADMIN;
1701
-            // loop through REG_ID's and change status
1702
-            foreach ($REG_IDs as $REG_ID) {
1703
-                $registration = $this->getRegistrationModel()->get_one_by_ID($REG_ID);
1704
-                if ($registration instanceof EE_Registration) {
1705
-                    $registration->set_status(
1706
-                        $status,
1707
-                        false,
1708
-                        new Context(
1709
-                            $status_context,
1710
-                            esc_html__(
1711
-                                'Manually triggered status change on a Registration Admin Page route.',
1712
-                                'event_espresso'
1713
-                            )
1714
-                        )
1715
-                    );
1716
-                    $result = $registration->save();
1717
-                    // verifying explicit fails because update *may* just return 0 for 0 rows affected
1718
-                    $success = $result !== false ? $success : false;
1719
-                }
1720
-            }
1721
-        }
1722
-
1723
-        // return $success and processed registrations
1724
-        return ['REG_ID' => $REG_IDs, 'success' => $success];
1725
-    }
1726
-
1727
-
1728
-    /**
1729
-     * Common logic for setting up success message and redirecting to appropriate route
1730
-     *
1731
-     * @param string $STS_ID status id for the registration changed to
1732
-     * @param bool   $notify indicates whether the _set_registration_status_from_request does notifications or not.
1733
-     * @return void
1734
-     * @throws DomainException
1735
-     * @throws EE_Error
1736
-     * @throws EntityNotFoundException
1737
-     * @throws InvalidArgumentException
1738
-     * @throws InvalidDataTypeException
1739
-     * @throws InvalidInterfaceException
1740
-     * @throws ReflectionException
1741
-     * @throws RuntimeException
1742
-     */
1743
-    protected function _reg_status_change_return($STS_ID, $notify = false)
1744
-    {
1745
-        $result  = ! empty($STS_ID) ? $this->_set_registration_status_from_request($STS_ID, $notify)
1746
-            : ['success' => false];
1747
-        $success = isset($result['success']) && $result['success'];
1748
-        // setup success message
1749
-        if ($success) {
1750
-            if (is_array($result['REG_ID']) && count($result['REG_ID']) === 1) {
1751
-                $msg = sprintf(
1752
-                    esc_html__('Registration status has been set to %s', 'event_espresso'),
1753
-                    EEH_Template::pretty_status($STS_ID, false, 'lower')
1754
-                );
1755
-            } else {
1756
-                $msg = sprintf(
1757
-                    esc_html__('Registrations have been set to %s.', 'event_espresso'),
1758
-                    EEH_Template::pretty_status($STS_ID, false, 'lower')
1759
-                );
1760
-            }
1761
-            EE_Error::add_success($msg);
1762
-        } else {
1763
-            EE_Error::add_error(
1764
-                esc_html__(
1765
-                    'Something went wrong, and the status was not changed',
1766
-                    'event_espresso'
1767
-                ),
1768
-                __FILE__,
1769
-                __LINE__,
1770
-                __FUNCTION__
1771
-            );
1772
-        }
1773
-        $return = $this->request->getRequestParam('return');
1774
-        $route  = $return === 'view_registration'
1775
-            ? ['action' => 'view_registration', '_REG_ID' => reset($result['REG_ID'])]
1776
-            : ['action' => 'default'];
1777
-        $route  = $this->mergeExistingRequestParamsWithRedirectArgs($route);
1778
-        $this->_redirect_after_action($success, '', '', $route, true);
1779
-    }
1780
-
1781
-
1782
-    /**
1783
-     * incoming reg status change from reg details page.
1784
-     *
1785
-     * @return void
1786
-     * @throws EE_Error
1787
-     * @throws EntityNotFoundException
1788
-     * @throws InvalidArgumentException
1789
-     * @throws InvalidDataTypeException
1790
-     * @throws InvalidInterfaceException
1791
-     * @throws ReflectionException
1792
-     * @throws RuntimeException
1793
-     * @throws DomainException
1794
-     */
1795
-    protected function _change_reg_status()
1796
-    {
1797
-        $this->request->setRequestParam('return', 'view_registration');
1798
-        // set notify based on whether the send notifications toggle is set or not
1799
-        $notify     = $this->request->getRequestParam('reg_status_change_form[send_notifications]', false, 'bool');
1800
-        $reg_status = $this->request->getRequestParam('reg_status_change_form[reg_status]', '');
1801
-        $this->request->setRequestParam('reg_status_change_form[reg_status]', $reg_status);
1802
-        switch ($reg_status) {
1803
-            case EEM_Registration::status_id_approved:
1804
-            case EEH_Template::pretty_status(EEM_Registration::status_id_approved, false, 'sentence'):
1805
-                $this->approve_registration($notify);
1806
-                break;
1807
-            case EEM_Registration::status_id_pending_payment:
1808
-            case EEH_Template::pretty_status(EEM_Registration::status_id_pending_payment, false, 'sentence'):
1809
-                $this->pending_registration($notify);
1810
-                break;
1811
-            case EEM_Registration::status_id_not_approved:
1812
-            case EEH_Template::pretty_status(EEM_Registration::status_id_not_approved, false, 'sentence'):
1813
-                $this->not_approve_registration($notify);
1814
-                break;
1815
-            case EEM_Registration::status_id_declined:
1816
-            case EEH_Template::pretty_status(EEM_Registration::status_id_declined, false, 'sentence'):
1817
-                $this->decline_registration($notify);
1818
-                break;
1819
-            case EEM_Registration::status_id_cancelled:
1820
-            case EEH_Template::pretty_status(EEM_Registration::status_id_cancelled, false, 'sentence'):
1821
-                $this->cancel_registration($notify);
1822
-                break;
1823
-            case EEM_Registration::status_id_wait_list:
1824
-            case EEH_Template::pretty_status(EEM_Registration::status_id_wait_list, false, 'sentence'):
1825
-                $this->wait_list_registration($notify);
1826
-                break;
1827
-            case EEM_Registration::status_id_incomplete:
1828
-            default:
1829
-                $this->request->unSetRequestParam('return');
1830
-                $this->_reg_status_change_return('');
1831
-                break;
1832
-        }
1833
-    }
1834
-
1835
-
1836
-    /**
1837
-     * Callback for bulk action routes.
1838
-     * Note: although we could just register the singular route callbacks for each bulk action route as well, this
1839
-     * method was chosen so there is one central place all the registration status bulk actions are going through.
1840
-     * Potentially, this provides an easier place to locate logic that is specific to these bulk actions (as opposed to
1841
-     * when an action is happening on just a single registration).
1842
-     *
1843
-     * @param      $action
1844
-     * @param bool $notify
1845
-     */
1846
-    protected function bulk_action_on_registrations($action, $notify = false)
1847
-    {
1848
-        do_action(
1849
-            'AHEE__Registrations_Admin_Page__bulk_action_on_registrations__before_execution',
1850
-            $this,
1851
-            $action,
1852
-            $notify
1853
-        );
1854
-        $method = $action . '_registration';
1855
-        if (method_exists($this, $method)) {
1856
-            $this->$method($notify);
1857
-        }
1858
-    }
1859
-
1860
-
1861
-    /**
1862
-     * approve_registration
1863
-     *
1864
-     * @param bool $notify whether or not to notify the registrant about their approval.
1865
-     * @return void
1866
-     * @throws EE_Error
1867
-     * @throws EntityNotFoundException
1868
-     * @throws InvalidArgumentException
1869
-     * @throws InvalidDataTypeException
1870
-     * @throws InvalidInterfaceException
1871
-     * @throws ReflectionException
1872
-     * @throws RuntimeException
1873
-     * @throws DomainException
1874
-     */
1875
-    protected function approve_registration($notify = false)
1876
-    {
1877
-        $this->_reg_status_change_return(EEM_Registration::status_id_approved, $notify);
1878
-    }
1879
-
1880
-
1881
-    /**
1882
-     * decline_registration
1883
-     *
1884
-     * @param bool $notify whether or not to notify the registrant about their status change.
1885
-     * @return void
1886
-     * @throws EE_Error
1887
-     * @throws EntityNotFoundException
1888
-     * @throws InvalidArgumentException
1889
-     * @throws InvalidDataTypeException
1890
-     * @throws InvalidInterfaceException
1891
-     * @throws ReflectionException
1892
-     * @throws RuntimeException
1893
-     * @throws DomainException
1894
-     */
1895
-    protected function decline_registration($notify = false)
1896
-    {
1897
-        $this->_reg_status_change_return(EEM_Registration::status_id_declined, $notify);
1898
-    }
1899
-
1900
-
1901
-    /**
1902
-     * cancel_registration
1903
-     *
1904
-     * @param bool $notify whether or not to notify the registrant about their status change.
1905
-     * @return void
1906
-     * @throws EE_Error
1907
-     * @throws EntityNotFoundException
1908
-     * @throws InvalidArgumentException
1909
-     * @throws InvalidDataTypeException
1910
-     * @throws InvalidInterfaceException
1911
-     * @throws ReflectionException
1912
-     * @throws RuntimeException
1913
-     * @throws DomainException
1914
-     */
1915
-    protected function cancel_registration($notify = false)
1916
-    {
1917
-        $this->_reg_status_change_return(EEM_Registration::status_id_cancelled, $notify);
1918
-    }
1919
-
1920
-
1921
-    /**
1922
-     * not_approve_registration
1923
-     *
1924
-     * @param bool $notify whether or not to notify the registrant about their status change.
1925
-     * @return void
1926
-     * @throws EE_Error
1927
-     * @throws EntityNotFoundException
1928
-     * @throws InvalidArgumentException
1929
-     * @throws InvalidDataTypeException
1930
-     * @throws InvalidInterfaceException
1931
-     * @throws ReflectionException
1932
-     * @throws RuntimeException
1933
-     * @throws DomainException
1934
-     */
1935
-    protected function not_approve_registration($notify = false)
1936
-    {
1937
-        $this->_reg_status_change_return(EEM_Registration::status_id_not_approved, $notify);
1938
-    }
1939
-
1940
-
1941
-    /**
1942
-     * decline_registration
1943
-     *
1944
-     * @param bool $notify whether or not to notify the registrant about their status change.
1945
-     * @return void
1946
-     * @throws EE_Error
1947
-     * @throws EntityNotFoundException
1948
-     * @throws InvalidArgumentException
1949
-     * @throws InvalidDataTypeException
1950
-     * @throws InvalidInterfaceException
1951
-     * @throws ReflectionException
1952
-     * @throws RuntimeException
1953
-     * @throws DomainException
1954
-     */
1955
-    protected function pending_registration($notify = false)
1956
-    {
1957
-        $this->_reg_status_change_return(EEM_Registration::status_id_pending_payment, $notify);
1958
-    }
1959
-
1960
-
1961
-    /**
1962
-     * waitlist_registration
1963
-     *
1964
-     * @param bool $notify whether or not to notify the registrant about their status change.
1965
-     * @return void
1966
-     * @throws EE_Error
1967
-     * @throws EntityNotFoundException
1968
-     * @throws InvalidArgumentException
1969
-     * @throws InvalidDataTypeException
1970
-     * @throws InvalidInterfaceException
1971
-     * @throws ReflectionException
1972
-     * @throws RuntimeException
1973
-     * @throws DomainException
1974
-     */
1975
-    protected function wait_list_registration($notify = false)
1976
-    {
1977
-        $this->_reg_status_change_return(EEM_Registration::status_id_wait_list, $notify);
1978
-    }
1979
-
1980
-
1981
-    /**
1982
-     * generates HTML for the Registration main meta box
1983
-     *
1984
-     * @return void
1985
-     * @throws DomainException
1986
-     * @throws EE_Error
1987
-     * @throws InvalidArgumentException
1988
-     * @throws InvalidDataTypeException
1989
-     * @throws InvalidInterfaceException
1990
-     * @throws ReflectionException
1991
-     * @throws EntityNotFoundException
1992
-     */
1993
-    public function _reg_details_meta_box()
1994
-    {
1995
-        EEH_Autoloader::register_line_item_display_autoloaders();
1996
-        EEH_Autoloader::register_line_item_filter_autoloaders();
1997
-        EE_Registry::instance()->load_helper('Line_Item');
1998
-        $transaction    = $this->_registration->transaction() ? $this->_registration->transaction()
1999
-            : EE_Transaction::new_instance();
2000
-        $this->_session = $transaction->session_data();
2001
-        $filters        = new EE_Line_Item_Filter_Collection();
2002
-        $filters->add(new EE_Single_Registration_Line_Item_Filter($this->_registration));
2003
-        $filters->add(new EE_Non_Zero_Line_Item_Filter());
2004
-        $line_item_filter_processor              = new EE_Line_Item_Filter_Processor(
2005
-            $filters,
2006
-            $transaction->total_line_item()
2007
-        );
2008
-        $filtered_line_item_tree                 = $line_item_filter_processor->process();
2009
-        $line_item_display                       = new EE_Line_Item_Display(
2010
-            'reg_admin_table',
2011
-            'EE_Admin_Table_Registration_Line_Item_Display_Strategy'
2012
-        );
2013
-        $this->_template_args['line_item_table'] = $line_item_display->display_line_item(
2014
-            $filtered_line_item_tree,
2015
-            ['EE_Registration' => $this->_registration]
2016
-        );
2017
-        $attendee                                = $this->_registration->attendee();
2018
-        if (
2019
-            EE_Registry::instance()->CAP->current_user_can(
2020
-                'ee_read_transaction',
2021
-                'espresso_transactions_view_transaction'
2022
-            )
2023
-        ) {
2024
-            $this->_template_args['view_transaction_button'] = EEH_Template::get_button_or_link(
2025
-                EE_Admin_Page::add_query_args_and_nonce(
2026
-                    [
2027
-                        'action' => 'view_transaction',
2028
-                        'TXN_ID' => $transaction->ID(),
2029
-                    ],
2030
-                    TXN_ADMIN_URL
2031
-                ),
2032
-                esc_html__(' View Transaction', 'event_espresso'),
2033
-                'button button--secondary right',
2034
-                'dashicons dashicons-cart'
2035
-            );
2036
-        } else {
2037
-            $this->_template_args['view_transaction_button'] = '';
2038
-        }
2039
-        if (
2040
-            $attendee instanceof EE_Attendee
2041
-            && EE_Registry::instance()->CAP->current_user_can(
2042
-                'ee_send_message',
2043
-                'espresso_registrations_resend_registration'
2044
-            )
2045
-        ) {
2046
-            $this->_template_args['resend_registration_button'] = EEH_Template::get_button_or_link(
2047
-                EE_Admin_Page::add_query_args_and_nonce(
2048
-                    [
2049
-                        'action'      => 'resend_registration',
2050
-                        '_REG_ID'     => $this->_registration->ID(),
2051
-                        'redirect_to' => 'view_registration',
2052
-                    ],
2053
-                    REG_ADMIN_URL
2054
-                ),
2055
-                esc_html__(' Resend Registration', 'event_espresso'),
2056
-                'button button--secondary right',
2057
-                'dashicons dashicons-email-alt'
2058
-            );
2059
-        } else {
2060
-            $this->_template_args['resend_registration_button'] = '';
2061
-        }
2062
-        $this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
2063
-        $payment                               = $transaction->get_first_related('Payment');
2064
-        $payment                               = ! $payment instanceof EE_Payment
2065
-            ? EE_Payment::new_instance()
2066
-            : $payment;
2067
-        $payment_method                        = $payment->get_first_related('Payment_Method');
2068
-        $payment_method                        = ! $payment_method instanceof EE_Payment_Method
2069
-            ? EE_Payment_Method::new_instance()
2070
-            : $payment_method;
2071
-        $reg_details                           = [
2072
-            'payment_method'       => $payment_method->name(),
2073
-            'response_msg'         => $payment->gateway_response(),
2074
-            'registration_id'      => $this->_registration->get('REG_code'),
2075
-            'registration_session' => $this->_registration->session_ID(),
2076
-            'ip_address'           => isset($this->_session['ip_address']) ? $this->_session['ip_address'] : '',
2077
-            'user_agent'           => isset($this->_session['user_agent']) ? $this->_session['user_agent'] : '',
2078
-        ];
2079
-        if (isset($reg_details['registration_id'])) {
2080
-            $this->_template_args['reg_details']['registration_id']['value'] = $reg_details['registration_id'];
2081
-            $this->_template_args['reg_details']['registration_id']['label'] = esc_html__(
2082
-                'Registration ID',
2083
-                'event_espresso'
2084
-            );
2085
-            $this->_template_args['reg_details']['registration_id']['class'] = 'regular-text';
2086
-        }
2087
-        if (isset($reg_details['payment_method'])) {
2088
-            $this->_template_args['reg_details']['payment_method']['value'] = $reg_details['payment_method'];
2089
-            $this->_template_args['reg_details']['payment_method']['label'] = esc_html__(
2090
-                'Most Recent Payment Method',
2091
-                'event_espresso'
2092
-            );
2093
-            $this->_template_args['reg_details']['payment_method']['class'] = 'regular-text';
2094
-            $this->_template_args['reg_details']['response_msg']['value']   = $reg_details['response_msg'];
2095
-            $this->_template_args['reg_details']['response_msg']['label']   = esc_html__(
2096
-                'Payment method response',
2097
-                'event_espresso'
2098
-            );
2099
-            $this->_template_args['reg_details']['response_msg']['class']   = 'regular-text';
2100
-        }
2101
-        $this->_template_args['reg_details']['registration_session']['value'] = $reg_details['registration_session'];
2102
-        $this->_template_args['reg_details']['registration_session']['label'] = esc_html__(
2103
-            'Registration Session',
2104
-            'event_espresso'
2105
-        );
2106
-        $this->_template_args['reg_details']['registration_session']['class'] = 'regular-text';
2107
-        $this->_template_args['reg_details']['ip_address']['value']           = $reg_details['ip_address'];
2108
-        $this->_template_args['reg_details']['ip_address']['label']           = esc_html__(
2109
-            'Registration placed from IP',
2110
-            'event_espresso'
2111
-        );
2112
-        $this->_template_args['reg_details']['ip_address']['class']           = 'regular-text';
2113
-        $this->_template_args['reg_details']['user_agent']['value']           = $reg_details['user_agent'];
2114
-        $this->_template_args['reg_details']['user_agent']['label']           = esc_html__(
2115
-            'Registrant User Agent',
2116
-            'event_espresso'
2117
-        );
2118
-        $this->_template_args['reg_details']['user_agent']['class']           = 'large-text';
2119
-        $this->_template_args['event_link']                                   = EE_Admin_Page::add_query_args_and_nonce(
2120
-            [
2121
-                'action'   => 'default',
2122
-                'event_id' => $this->_registration->event_ID(),
2123
-            ],
2124
-            REG_ADMIN_URL
2125
-        );
2126
-
2127
-        $this->_template_args['REG_ID'] = $this->_registration->ID();
2128
-        $this->_template_args['event_id'] = $this->_registration->event_ID();
2129
-
2130
-        $template_path = REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_reg_details.template.php';
2131
-        EEH_Template::display_template($template_path, $this->_template_args); // already escaped
2132
-    }
2133
-
2134
-
2135
-    /**
2136
-     * generates HTML for the Registration Questions meta box.
2137
-     * If pre-4.8.32.rc.000 hooks are used, uses old methods (with its filters),
2138
-     * otherwise uses new forms system
2139
-     *
2140
-     * @return void
2141
-     * @throws DomainException
2142
-     * @throws EE_Error
2143
-     * @throws InvalidArgumentException
2144
-     * @throws InvalidDataTypeException
2145
-     * @throws InvalidInterfaceException
2146
-     * @throws ReflectionException
2147
-     */
2148
-    public function _reg_questions_meta_box()
2149
-    {
2150
-        // allow someone to override this method entirely
2151
-        if (
2152
-            apply_filters(
2153
-                'FHEE__Registrations_Admin_Page___reg_questions_meta_box__do_default',
2154
-                true,
2155
-                $this,
2156
-                $this->_registration
2157
-            )
2158
-        ) {
2159
-            $form = $this->_get_reg_custom_questions_form(
2160
-                $this->_registration->ID()
2161
-            );
2162
-
2163
-            $this->_template_args['att_questions'] = count($form->subforms()) > 0
2164
-                ? $form->get_html_and_js()
2165
-                : '';
2166
-
2167
-            $this->_template_args['reg_questions_form_action'] = 'edit_registration';
2168
-            $this->_template_args['REG_ID'] = $this->_registration->ID();
2169
-            $template_path = REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_reg_questions.template.php';
2170
-            EEH_Template::display_template($template_path, $this->_template_args);
2171
-        }
2172
-    }
2173
-
2174
-
2175
-    /**
2176
-     * form_before_question_group
2177
-     *
2178
-     * @param string $output
2179
-     * @return        string
2180
-     * @deprecated    as of 4.8.32.rc.000
2181
-     */
2182
-    public function form_before_question_group($output)
2183
-    {
2184
-        EE_Error::doing_it_wrong(
2185
-            __CLASS__ . '::' . __FUNCTION__,
2186
-            esc_html__(
2187
-                '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.',
2188
-                'event_espresso'
2189
-            ),
2190
-            '4.8.32.rc.000'
2191
-        );
2192
-        return '
23
+	/**
24
+	 * @var EE_Registration
25
+	 */
26
+	private $_registration;
27
+
28
+	/**
29
+	 * @var EE_Event
30
+	 */
31
+	private $_reg_event;
32
+
33
+	/**
34
+	 * @var EE_Session
35
+	 */
36
+	private $_session;
37
+
38
+	/**
39
+	 * @var array
40
+	 */
41
+	private static $_reg_status;
42
+
43
+	/**
44
+	 * Form for displaying the custom questions for this registration.
45
+	 * This gets used a few times throughout the request so its best to cache it
46
+	 *
47
+	 * @var EE_Registration_Custom_Questions_Form
48
+	 */
49
+	protected $_reg_custom_questions_form;
50
+
51
+	/**
52
+	 * @var EEM_Registration $registration_model
53
+	 */
54
+	private $registration_model;
55
+
56
+	/**
57
+	 * @var EEM_Attendee $attendee_model
58
+	 */
59
+	private $attendee_model;
60
+
61
+	/**
62
+	 * @var EEM_Event $event_model
63
+	 */
64
+	private $event_model;
65
+
66
+	/**
67
+	 * @var EEM_Status $status_model
68
+	 */
69
+	private $status_model;
70
+
71
+
72
+	/**
73
+	 * @param bool $routing
74
+	 * @throws EE_Error
75
+	 * @throws InvalidArgumentException
76
+	 * @throws InvalidDataTypeException
77
+	 * @throws InvalidInterfaceException
78
+	 * @throws ReflectionException
79
+	 */
80
+	public function __construct($routing = true)
81
+	{
82
+		parent::__construct($routing);
83
+		add_action('wp_loaded', [$this, 'wp_loaded']);
84
+	}
85
+
86
+
87
+	/**
88
+	 * @return EEM_Registration
89
+	 * @throws InvalidArgumentException
90
+	 * @throws InvalidDataTypeException
91
+	 * @throws InvalidInterfaceException
92
+	 * @since 4.10.2.p
93
+	 */
94
+	protected function getRegistrationModel()
95
+	{
96
+		if (! $this->registration_model instanceof EEM_Registration) {
97
+			$this->registration_model = $this->loader->getShared('EEM_Registration');
98
+		}
99
+		return $this->registration_model;
100
+	}
101
+
102
+
103
+	/**
104
+	 * @return EEM_Attendee
105
+	 * @throws InvalidArgumentException
106
+	 * @throws InvalidDataTypeException
107
+	 * @throws InvalidInterfaceException
108
+	 * @since 4.10.2.p
109
+	 */
110
+	protected function getAttendeeModel()
111
+	{
112
+		if (! $this->attendee_model instanceof EEM_Attendee) {
113
+			$this->attendee_model = $this->loader->getShared('EEM_Attendee');
114
+		}
115
+		return $this->attendee_model;
116
+	}
117
+
118
+
119
+	/**
120
+	 * @return EEM_Event
121
+	 * @throws InvalidArgumentException
122
+	 * @throws InvalidDataTypeException
123
+	 * @throws InvalidInterfaceException
124
+	 * @since 4.10.2.p
125
+	 */
126
+	protected function getEventModel()
127
+	{
128
+		if (! $this->event_model instanceof EEM_Event) {
129
+			$this->event_model = $this->loader->getShared('EEM_Event');
130
+		}
131
+		return $this->event_model;
132
+	}
133
+
134
+
135
+	/**
136
+	 * @return EEM_Status
137
+	 * @throws InvalidArgumentException
138
+	 * @throws InvalidDataTypeException
139
+	 * @throws InvalidInterfaceException
140
+	 * @since 4.10.2.p
141
+	 */
142
+	protected function getStatusModel()
143
+	{
144
+		if (! $this->status_model instanceof EEM_Status) {
145
+			$this->status_model = $this->loader->getShared('EEM_Status');
146
+		}
147
+		return $this->status_model;
148
+	}
149
+
150
+
151
+	public function wp_loaded()
152
+	{
153
+		// when adding a new registration...
154
+		$action = $this->request->getRequestParam('action');
155
+		if ($action === 'new_registration') {
156
+			EE_System::do_not_cache();
157
+			if ($this->request->getRequestParam('processing_registration', 0, 'int') !== 1) {
158
+				// and it's NOT the attendee information reg step
159
+				// force cookie expiration by setting time to last week
160
+				setcookie('ee_registration_added', 0, time() - WEEK_IN_SECONDS, '/');
161
+				// and update the global
162
+				$_COOKIE['ee_registration_added'] = 0;
163
+			}
164
+		}
165
+	}
166
+
167
+
168
+	protected function _init_page_props()
169
+	{
170
+		$this->page_slug        = REG_PG_SLUG;
171
+		$this->_admin_base_url  = REG_ADMIN_URL;
172
+		$this->_admin_base_path = REG_ADMIN;
173
+		$this->page_label       = esc_html__('Registrations', 'event_espresso');
174
+		$this->_cpt_routes      = [
175
+			'add_new_attendee' => 'espresso_attendees',
176
+			'edit_attendee'    => 'espresso_attendees',
177
+			'insert_attendee'  => 'espresso_attendees',
178
+			'update_attendee'  => 'espresso_attendees',
179
+		];
180
+		$this->_cpt_model_names = [
181
+			'add_new_attendee' => 'EEM_Attendee',
182
+			'edit_attendee'    => 'EEM_Attendee',
183
+		];
184
+		$this->_cpt_edit_routes = [
185
+			'espresso_attendees' => 'edit_attendee',
186
+		];
187
+		$this->_pagenow_map     = [
188
+			'add_new_attendee' => 'post-new.php',
189
+			'edit_attendee'    => 'post.php',
190
+			'trash'            => 'post.php',
191
+		];
192
+		add_action('edit_form_after_title', [$this, 'after_title_form_fields'], 10);
193
+		// add filters so that the comment urls don't take users to a confusing 404 page
194
+		add_filter('get_comment_link', [$this, 'clear_comment_link'], 10, 2);
195
+	}
196
+
197
+
198
+	/**
199
+	 * @param string     $link    The comment permalink with '#comment-$id' appended.
200
+	 * @param WP_Comment $comment The current comment object.
201
+	 * @return string
202
+	 */
203
+	public function clear_comment_link($link, WP_Comment $comment)
204
+	{
205
+		// gotta make sure this only happens on this route
206
+		$post_type = get_post_type($comment->comment_post_ID);
207
+		if ($post_type === 'espresso_attendees') {
208
+			return '#commentsdiv';
209
+		}
210
+		return $link;
211
+	}
212
+
213
+
214
+	protected function _ajax_hooks()
215
+	{
216
+		// todo: all hooks for registrations ajax goes in here
217
+		add_action('wp_ajax_toggle_checkin_status', [$this, 'toggle_checkin_status']);
218
+	}
219
+
220
+
221
+	protected function _define_page_props()
222
+	{
223
+		$this->_admin_page_title = $this->page_label;
224
+		$this->_labels           = [
225
+			'buttons'                      => [
226
+				'add-registrant'      => esc_html__('Add New Registration', 'event_espresso'),
227
+				'add-attendee'        => esc_html__('Add Contact', 'event_espresso'),
228
+				'edit'                => esc_html__('Edit Contact', 'event_espresso'),
229
+				'report'              => esc_html__('Event Registrations CSV Report', 'event_espresso'),
230
+				'report_datetime'     => esc_html__('Datetime Registrations CSV Report', 'event_espresso'),
231
+				'report_all'          => esc_html__('All Registrations CSV Report', 'event_espresso'),
232
+				'report_filtered'     => esc_html__('Filtered CSV Report', 'event_espresso'),
233
+				'contact_list_report' => esc_html__('Contact List Report', 'event_espresso'),
234
+				'contact_list_export' => esc_html__('Export Data', 'event_espresso'),
235
+			],
236
+			'publishbox'                   => [
237
+				'add_new_attendee' => esc_html__('Add Contact Record', 'event_espresso'),
238
+				'edit_attendee'    => esc_html__('Update Contact Record', 'event_espresso'),
239
+			],
240
+			'hide_add_button_on_cpt_route' => [
241
+				'edit_attendee' => true,
242
+			],
243
+		];
244
+	}
245
+
246
+
247
+	/**
248
+	 * grab url requests and route them
249
+	 *
250
+	 * @return void
251
+	 * @throws EE_Error
252
+	 */
253
+	public function _set_page_routes()
254
+	{
255
+		$this->_get_registration_status_array();
256
+		$REG_ID             = $this->request->getRequestParam('_REG_ID', 0, 'int');
257
+		$REG_ID             = $this->request->getRequestParam('reg_status_change_form[REG_ID]', $REG_ID, 'int');
258
+		$ATT_ID             = $this->request->getRequestParam('ATT_ID', 0, 'int');
259
+		$ATT_ID             = $this->request->getRequestParam('post', $ATT_ID, 'int');
260
+		$this->_page_routes = [
261
+			'default'                             => [
262
+				'func'       => '_registrations_overview_list_table',
263
+				'capability' => 'ee_read_registrations',
264
+			],
265
+			'view_registration'                   => [
266
+				'func'       => '_registration_details',
267
+				'capability' => 'ee_read_registration',
268
+				'obj_id'     => $REG_ID,
269
+			],
270
+			'edit_registration'                   => [
271
+				'func'               => '_update_attendee_registration_form',
272
+				'noheader'           => true,
273
+				'headers_sent_route' => 'view_registration',
274
+				'capability'         => 'ee_edit_registration',
275
+				'obj_id'             => $REG_ID,
276
+				'_REG_ID'            => $REG_ID,
277
+			],
278
+			'trash_registrations'                 => [
279
+				'func'       => '_trash_or_restore_registrations',
280
+				'args'       => ['trash' => true],
281
+				'noheader'   => true,
282
+				'capability' => 'ee_delete_registrations',
283
+			],
284
+			'restore_registrations'               => [
285
+				'func'       => '_trash_or_restore_registrations',
286
+				'args'       => ['trash' => false],
287
+				'noheader'   => true,
288
+				'capability' => 'ee_delete_registrations',
289
+			],
290
+			'delete_registrations'                => [
291
+				'func'       => '_delete_registrations',
292
+				'noheader'   => true,
293
+				'capability' => 'ee_delete_registrations',
294
+			],
295
+			'new_registration'                    => [
296
+				'func'       => 'new_registration',
297
+				'capability' => 'ee_edit_registrations',
298
+			],
299
+			'process_reg_step'                    => [
300
+				'func'       => 'process_reg_step',
301
+				'noheader'   => true,
302
+				'capability' => 'ee_edit_registrations',
303
+			],
304
+			'redirect_to_txn'                     => [
305
+				'func'       => 'redirect_to_txn',
306
+				'noheader'   => true,
307
+				'capability' => 'ee_edit_registrations',
308
+			],
309
+			'change_reg_status'                   => [
310
+				'func'       => '_change_reg_status',
311
+				'noheader'   => true,
312
+				'capability' => 'ee_edit_registration',
313
+				'obj_id'     => $REG_ID,
314
+			],
315
+			'approve_registration'                => [
316
+				'func'       => 'approve_registration',
317
+				'noheader'   => true,
318
+				'capability' => 'ee_edit_registration',
319
+				'obj_id'     => $REG_ID,
320
+			],
321
+			'approve_and_notify_registration'     => [
322
+				'func'       => 'approve_registration',
323
+				'noheader'   => true,
324
+				'args'       => [true],
325
+				'capability' => 'ee_edit_registration',
326
+				'obj_id'     => $REG_ID,
327
+			],
328
+			'approve_registrations'               => [
329
+				'func'       => 'bulk_action_on_registrations',
330
+				'noheader'   => true,
331
+				'capability' => 'ee_edit_registrations',
332
+				'args'       => ['approve'],
333
+			],
334
+			'approve_and_notify_registrations'    => [
335
+				'func'       => 'bulk_action_on_registrations',
336
+				'noheader'   => true,
337
+				'capability' => 'ee_edit_registrations',
338
+				'args'       => ['approve', true],
339
+			],
340
+			'decline_registration'                => [
341
+				'func'       => 'decline_registration',
342
+				'noheader'   => true,
343
+				'capability' => 'ee_edit_registration',
344
+				'obj_id'     => $REG_ID,
345
+			],
346
+			'decline_and_notify_registration'     => [
347
+				'func'       => 'decline_registration',
348
+				'noheader'   => true,
349
+				'args'       => [true],
350
+				'capability' => 'ee_edit_registration',
351
+				'obj_id'     => $REG_ID,
352
+			],
353
+			'decline_registrations'               => [
354
+				'func'       => 'bulk_action_on_registrations',
355
+				'noheader'   => true,
356
+				'capability' => 'ee_edit_registrations',
357
+				'args'       => ['decline'],
358
+			],
359
+			'decline_and_notify_registrations'    => [
360
+				'func'       => 'bulk_action_on_registrations',
361
+				'noheader'   => true,
362
+				'capability' => 'ee_edit_registrations',
363
+				'args'       => ['decline', true],
364
+			],
365
+			'pending_registration'                => [
366
+				'func'       => 'pending_registration',
367
+				'noheader'   => true,
368
+				'capability' => 'ee_edit_registration',
369
+				'obj_id'     => $REG_ID,
370
+			],
371
+			'pending_and_notify_registration'     => [
372
+				'func'       => 'pending_registration',
373
+				'noheader'   => true,
374
+				'args'       => [true],
375
+				'capability' => 'ee_edit_registration',
376
+				'obj_id'     => $REG_ID,
377
+			],
378
+			'pending_registrations'               => [
379
+				'func'       => 'bulk_action_on_registrations',
380
+				'noheader'   => true,
381
+				'capability' => 'ee_edit_registrations',
382
+				'args'       => ['pending'],
383
+			],
384
+			'pending_and_notify_registrations'    => [
385
+				'func'       => 'bulk_action_on_registrations',
386
+				'noheader'   => true,
387
+				'capability' => 'ee_edit_registrations',
388
+				'args'       => ['pending', true],
389
+			],
390
+			'no_approve_registration'             => [
391
+				'func'       => 'not_approve_registration',
392
+				'noheader'   => true,
393
+				'capability' => 'ee_edit_registration',
394
+				'obj_id'     => $REG_ID,
395
+			],
396
+			'no_approve_and_notify_registration'  => [
397
+				'func'       => 'not_approve_registration',
398
+				'noheader'   => true,
399
+				'args'       => [true],
400
+				'capability' => 'ee_edit_registration',
401
+				'obj_id'     => $REG_ID,
402
+			],
403
+			'no_approve_registrations'            => [
404
+				'func'       => 'bulk_action_on_registrations',
405
+				'noheader'   => true,
406
+				'capability' => 'ee_edit_registrations',
407
+				'args'       => ['not_approve'],
408
+			],
409
+			'no_approve_and_notify_registrations' => [
410
+				'func'       => 'bulk_action_on_registrations',
411
+				'noheader'   => true,
412
+				'capability' => 'ee_edit_registrations',
413
+				'args'       => ['not_approve', true],
414
+			],
415
+			'cancel_registration'                 => [
416
+				'func'       => 'cancel_registration',
417
+				'noheader'   => true,
418
+				'capability' => 'ee_edit_registration',
419
+				'obj_id'     => $REG_ID,
420
+			],
421
+			'cancel_and_notify_registration'      => [
422
+				'func'       => 'cancel_registration',
423
+				'noheader'   => true,
424
+				'args'       => [true],
425
+				'capability' => 'ee_edit_registration',
426
+				'obj_id'     => $REG_ID,
427
+			],
428
+			'cancel_registrations'                => [
429
+				'func'       => 'bulk_action_on_registrations',
430
+				'noheader'   => true,
431
+				'capability' => 'ee_edit_registrations',
432
+				'args'       => ['cancel'],
433
+			],
434
+			'cancel_and_notify_registrations'     => [
435
+				'func'       => 'bulk_action_on_registrations',
436
+				'noheader'   => true,
437
+				'capability' => 'ee_edit_registrations',
438
+				'args'       => ['cancel', true],
439
+			],
440
+			'wait_list_registration'              => [
441
+				'func'       => 'wait_list_registration',
442
+				'noheader'   => true,
443
+				'capability' => 'ee_edit_registration',
444
+				'obj_id'     => $REG_ID,
445
+			],
446
+			'wait_list_and_notify_registration'   => [
447
+				'func'       => 'wait_list_registration',
448
+				'noheader'   => true,
449
+				'args'       => [true],
450
+				'capability' => 'ee_edit_registration',
451
+				'obj_id'     => $REG_ID,
452
+			],
453
+			'contact_list'                        => [
454
+				'func'       => '_attendee_contact_list_table',
455
+				'capability' => 'ee_read_contacts',
456
+			],
457
+			'add_new_attendee'                    => [
458
+				'func' => '_create_new_cpt_item',
459
+				'args' => [
460
+					'new_attendee' => true,
461
+					'capability'   => 'ee_edit_contacts',
462
+				],
463
+			],
464
+			'edit_attendee'                       => [
465
+				'func'       => '_edit_cpt_item',
466
+				'capability' => 'ee_edit_contacts',
467
+				'obj_id'     => $ATT_ID,
468
+			],
469
+			'duplicate_attendee'                  => [
470
+				'func'       => '_duplicate_attendee',
471
+				'noheader'   => true,
472
+				'capability' => 'ee_edit_contacts',
473
+				'obj_id'     => $ATT_ID,
474
+			],
475
+			'insert_attendee'                     => [
476
+				'func'       => '_insert_or_update_attendee',
477
+				'args'       => [
478
+					'new_attendee' => true,
479
+				],
480
+				'noheader'   => true,
481
+				'capability' => 'ee_edit_contacts',
482
+			],
483
+			'update_attendee'                     => [
484
+				'func'       => '_insert_or_update_attendee',
485
+				'args'       => [
486
+					'new_attendee' => false,
487
+				],
488
+				'noheader'   => true,
489
+				'capability' => 'ee_edit_contacts',
490
+				'obj_id'     => $ATT_ID,
491
+			],
492
+			'trash_attendees'                     => [
493
+				'func'       => '_trash_or_restore_attendees',
494
+				'args'       => [
495
+					'trash' => 'true',
496
+				],
497
+				'noheader'   => true,
498
+				'capability' => 'ee_delete_contacts',
499
+			],
500
+			'trash_attendee'                      => [
501
+				'func'       => '_trash_or_restore_attendees',
502
+				'args'       => [
503
+					'trash' => true,
504
+				],
505
+				'noheader'   => true,
506
+				'capability' => 'ee_delete_contacts',
507
+				'obj_id'     => $ATT_ID,
508
+			],
509
+			'restore_attendees'                   => [
510
+				'func'       => '_trash_or_restore_attendees',
511
+				'args'       => [
512
+					'trash' => false,
513
+				],
514
+				'noheader'   => true,
515
+				'capability' => 'ee_delete_contacts',
516
+				'obj_id'     => $ATT_ID,
517
+			],
518
+			'resend_registration'                 => [
519
+				'func'       => '_resend_registration',
520
+				'noheader'   => true,
521
+				'capability' => 'ee_send_message',
522
+			],
523
+			'registrations_report'                => [
524
+				'func'       => '_registrations_report',
525
+				'noheader'   => true,
526
+				'capability' => 'ee_read_registrations',
527
+			],
528
+			'contact_list_export'                 => [
529
+				'func'       => '_contact_list_export',
530
+				'noheader'   => true,
531
+				'capability' => 'export',
532
+			],
533
+			'contact_list_report'                 => [
534
+				'func'       => '_contact_list_report',
535
+				'noheader'   => true,
536
+				'capability' => 'ee_read_contacts',
537
+			],
538
+		];
539
+	}
540
+
541
+
542
+	protected function _set_page_config()
543
+	{
544
+		$REG_ID             = $this->request->getRequestParam('_REG_ID', 0, 'int');
545
+		$ATT_ID             = $this->request->getRequestParam('ATT_ID', 0, 'int');
546
+		$this->_page_config = [
547
+			'default'           => [
548
+				'nav'           => [
549
+					'label' => esc_html__('Overview', 'event_espresso'),
550
+					'icon' => 'dashicons-list-view',
551
+					'order' => 5,
552
+				],
553
+				'help_tabs'     => [
554
+					'registrations_overview_help_tab'                       => [
555
+						'title'    => esc_html__('Registrations Overview', 'event_espresso'),
556
+						'filename' => 'registrations_overview',
557
+					],
558
+					'registrations_overview_table_column_headings_help_tab' => [
559
+						'title'    => esc_html__('Registrations Table Column Headings', 'event_espresso'),
560
+						'filename' => 'registrations_overview_table_column_headings',
561
+					],
562
+					'registrations_overview_filters_help_tab'               => [
563
+						'title'    => esc_html__('Registration Filters', 'event_espresso'),
564
+						'filename' => 'registrations_overview_filters',
565
+					],
566
+					'registrations_overview_views_help_tab'                 => [
567
+						'title'    => esc_html__('Registration Views', 'event_espresso'),
568
+						'filename' => 'registrations_overview_views',
569
+					],
570
+					'registrations_regoverview_other_help_tab'              => [
571
+						'title'    => esc_html__('Registrations Other', 'event_espresso'),
572
+						'filename' => 'registrations_overview_other',
573
+					],
574
+				],
575
+				'list_table'    => 'EE_Registrations_List_Table',
576
+				'require_nonce' => false,
577
+			],
578
+			'view_registration' => [
579
+				'nav'           => [
580
+					'label'      => esc_html__('REG Details', 'event_espresso'),
581
+					'icon' => 'dashicons-clipboard',
582
+					'order'      => 15,
583
+					'url'        => $REG_ID
584
+						? add_query_arg(['_REG_ID' => $REG_ID], $this->_current_page_view_url)
585
+						: $this->_admin_base_url,
586
+					'persistent' => false,
587
+				],
588
+				'help_tabs'     => [
589
+					'registrations_details_help_tab'                    => [
590
+						'title'    => esc_html__('Registration Details', 'event_espresso'),
591
+						'filename' => 'registrations_details',
592
+					],
593
+					'registrations_details_table_help_tab'              => [
594
+						'title'    => esc_html__('Registration Details Table', 'event_espresso'),
595
+						'filename' => 'registrations_details_table',
596
+					],
597
+					'registrations_details_form_answers_help_tab'       => [
598
+						'title'    => esc_html__('Registration Form Answers', 'event_espresso'),
599
+						'filename' => 'registrations_details_form_answers',
600
+					],
601
+					'registrations_details_registrant_details_help_tab' => [
602
+						'title'    => esc_html__('Contact Details', 'event_espresso'),
603
+						'filename' => 'registrations_details_registrant_details',
604
+					],
605
+				],
606
+				'metaboxes'     => array_merge(
607
+					$this->_default_espresso_metaboxes,
608
+					['_registration_details_metaboxes']
609
+				),
610
+				'require_nonce' => false,
611
+			],
612
+			'new_registration'  => [
613
+				'nav'           => [
614
+					'label'      => esc_html__('Add New Registration', 'event_espresso'),
615
+					'icon' => 'dashicons-plus-alt',
616
+					'url'        => '#',
617
+					'order'      => 15,
618
+					'persistent' => false,
619
+				],
620
+				'metaboxes'     => $this->_default_espresso_metaboxes,
621
+				'labels'        => [
622
+					'publishbox' => esc_html__('Save Registration', 'event_espresso'),
623
+				],
624
+				'require_nonce' => false,
625
+			],
626
+			'add_new_attendee'  => [
627
+				'nav'           => [
628
+					'label'      => esc_html__('Add Contact', 'event_espresso'),
629
+					'icon' => 'dashicons-plus-alt',
630
+					'order'      => 15,
631
+					'persistent' => false,
632
+				],
633
+				'metaboxes'     => array_merge(
634
+					$this->_default_espresso_metaboxes,
635
+					['_publish_post_box', 'attendee_editor_metaboxes']
636
+				),
637
+				'require_nonce' => false,
638
+			],
639
+			'edit_attendee'     => [
640
+				'nav'           => [
641
+					'label'      => esc_html__('Edit Contact', 'event_espresso'),
642
+					'icon' => 'dashicons-edit-large',
643
+					'order'      => 15,
644
+					'persistent' => false,
645
+					'url'        => $ATT_ID
646
+						? add_query_arg(['ATT_ID' => $ATT_ID], $this->_current_page_view_url)
647
+						: $this->_admin_base_url,
648
+				],
649
+				'metaboxes'     => array_merge(
650
+					$this->_default_espresso_metaboxes,
651
+					['attendee_editor_metaboxes']
652
+				),
653
+				'require_nonce' => false,
654
+			],
655
+			'contact_list'      => [
656
+				'nav'           => [
657
+					'label' => esc_html__('Contact List', 'event_espresso'),
658
+					'icon' => 'dashicons-id-alt',
659
+					'order' => 20,
660
+				],
661
+				'list_table'    => 'EE_Attendee_Contact_List_Table',
662
+				'help_tabs'     => [
663
+					'registrations_contact_list_help_tab'                       => [
664
+						'title'    => esc_html__('Registrations Contact List', 'event_espresso'),
665
+						'filename' => 'registrations_contact_list',
666
+					],
667
+					'registrations_contact-list_table_column_headings_help_tab' => [
668
+						'title'    => esc_html__('Contact List Table Column Headings', 'event_espresso'),
669
+						'filename' => 'registrations_contact_list_table_column_headings',
670
+					],
671
+					'registrations_contact_list_views_help_tab'                 => [
672
+						'title'    => esc_html__('Contact List Views', 'event_espresso'),
673
+						'filename' => 'registrations_contact_list_views',
674
+					],
675
+					'registrations_contact_list_other_help_tab'                 => [
676
+						'title'    => esc_html__('Contact List Other', 'event_espresso'),
677
+						'filename' => 'registrations_contact_list_other',
678
+					],
679
+				],
680
+				'metaboxes'     => [],
681
+				'require_nonce' => false,
682
+			],
683
+			// override default cpt routes
684
+			'create_new'        => '',
685
+			'edit'              => '',
686
+		];
687
+	}
688
+
689
+
690
+	/**
691
+	 * The below methods aren't used by this class currently
692
+	 */
693
+	protected function _add_screen_options()
694
+	{
695
+	}
696
+
697
+
698
+	protected function _add_feature_pointers()
699
+	{
700
+	}
701
+
702
+
703
+	public function admin_init()
704
+	{
705
+		EE_Registry::$i18n_js_strings['update_att_qstns'] = esc_html__(
706
+			'click "Update Registration Questions" to save your changes',
707
+			'event_espresso'
708
+		);
709
+	}
710
+
711
+
712
+	public function admin_notices()
713
+	{
714
+	}
715
+
716
+
717
+	public function admin_footer_scripts()
718
+	{
719
+	}
720
+
721
+
722
+	/**
723
+	 * get list of registration statuses
724
+	 *
725
+	 * @return void
726
+	 * @throws EE_Error
727
+	 */
728
+	private function _get_registration_status_array()
729
+	{
730
+		self::$_reg_status = EEM_Registration::reg_status_array([], true);
731
+	}
732
+
733
+
734
+	/**
735
+	 * @throws InvalidArgumentException
736
+	 * @throws InvalidDataTypeException
737
+	 * @throws InvalidInterfaceException
738
+	 * @since 4.10.2.p
739
+	 */
740
+	protected function _add_screen_options_default()
741
+	{
742
+		$this->_per_page_screen_option();
743
+	}
744
+
745
+
746
+	/**
747
+	 * @throws InvalidArgumentException
748
+	 * @throws InvalidDataTypeException
749
+	 * @throws InvalidInterfaceException
750
+	 * @since 4.10.2.p
751
+	 */
752
+	protected function _add_screen_options_contact_list()
753
+	{
754
+		$page_title              = $this->_admin_page_title;
755
+		$this->_admin_page_title = esc_html__('Contacts', 'event_espresso');
756
+		$this->_per_page_screen_option();
757
+		$this->_admin_page_title = $page_title;
758
+	}
759
+
760
+
761
+	public function load_scripts_styles()
762
+	{
763
+		// style
764
+		wp_register_style(
765
+			'espresso_reg',
766
+			REG_ASSETS_URL . 'espresso_registrations_admin.css',
767
+			['ee-admin-css'],
768
+			EVENT_ESPRESSO_VERSION
769
+		);
770
+		wp_enqueue_style('espresso_reg');
771
+		// script
772
+		wp_register_script(
773
+			'espresso_reg',
774
+			REG_ASSETS_URL . 'espresso_registrations_admin.js',
775
+			['jquery-ui-datepicker', 'jquery-ui-draggable', 'ee_admin_js'],
776
+			EVENT_ESPRESSO_VERSION,
777
+			true
778
+		);
779
+		wp_enqueue_script('espresso_reg');
780
+	}
781
+
782
+
783
+	/**
784
+	 * @throws EE_Error
785
+	 * @throws InvalidArgumentException
786
+	 * @throws InvalidDataTypeException
787
+	 * @throws InvalidInterfaceException
788
+	 * @throws ReflectionException
789
+	 * @since 4.10.2.p
790
+	 */
791
+	public function load_scripts_styles_edit_attendee()
792
+	{
793
+		// stuff to only show up on our attendee edit details page.
794
+		$attendee_details_translations = [
795
+			'att_publish_text' => sprintf(
796
+			/* translators: The date and time */
797
+				wp_strip_all_tags(__('Created on: %s', 'event_espresso')),
798
+				'<b>' . $this->_cpt_model_obj->get_datetime('ATT_created') . '</b>'
799
+			),
800
+		];
801
+		wp_localize_script('espresso_reg', 'ATTENDEE_DETAILS', $attendee_details_translations);
802
+		wp_enqueue_script('jquery-validate');
803
+	}
804
+
805
+
806
+	/**
807
+	 * @throws EE_Error
808
+	 * @throws InvalidArgumentException
809
+	 * @throws InvalidDataTypeException
810
+	 * @throws InvalidInterfaceException
811
+	 * @throws ReflectionException
812
+	 * @since 4.10.2.p
813
+	 */
814
+	public function load_scripts_styles_view_registration()
815
+	{
816
+		// styles
817
+		wp_enqueue_style('espresso-ui-theme');
818
+		// scripts
819
+		$this->_get_reg_custom_questions_form($this->_registration->ID());
820
+		$this->_reg_custom_questions_form->wp_enqueue_scripts();
821
+	}
822
+
823
+
824
+	public function load_scripts_styles_contact_list()
825
+	{
826
+		wp_dequeue_style('espresso_reg');
827
+		wp_register_style(
828
+			'espresso_att',
829
+			REG_ASSETS_URL . 'espresso_attendees_admin.css',
830
+			['ee-admin-css'],
831
+			EVENT_ESPRESSO_VERSION
832
+		);
833
+		wp_enqueue_style('espresso_att');
834
+	}
835
+
836
+
837
+	public function load_scripts_styles_new_registration()
838
+	{
839
+		wp_register_script(
840
+			'ee-spco-for-admin',
841
+			REG_ASSETS_URL . 'spco_for_admin.js',
842
+			['underscore', 'jquery'],
843
+			EVENT_ESPRESSO_VERSION,
844
+			true
845
+		);
846
+		wp_enqueue_script('ee-spco-for-admin');
847
+		add_filter('FHEE__EED_Ticket_Selector__load_tckt_slctr_assets', '__return_true');
848
+		EE_Form_Section_Proper::wp_enqueue_scripts();
849
+		EED_Ticket_Selector::load_tckt_slctr_assets();
850
+		EE_Datepicker_Input::enqueue_styles_and_scripts();
851
+	}
852
+
853
+
854
+	public function AHEE__EE_Admin_Page__route_admin_request_resend_registration()
855
+	{
856
+		add_filter('FHEE_load_EE_messages', '__return_true');
857
+	}
858
+
859
+
860
+	public function AHEE__EE_Admin_Page__route_admin_request_approve_registration()
861
+	{
862
+		add_filter('FHEE_load_EE_messages', '__return_true');
863
+	}
864
+
865
+
866
+	/**
867
+	 * @throws EE_Error
868
+	 * @throws InvalidArgumentException
869
+	 * @throws InvalidDataTypeException
870
+	 * @throws InvalidInterfaceException
871
+	 * @throws ReflectionException
872
+	 * @since 4.10.2.p
873
+	 */
874
+	protected function _set_list_table_views_default()
875
+	{
876
+		// for notification related bulk actions we need to make sure only active messengers have an option.
877
+		EED_Messages::set_autoloaders();
878
+		/** @type EE_Message_Resource_Manager $message_resource_manager */
879
+		$message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
880
+		$active_mts               = $message_resource_manager->list_of_active_message_types();
881
+		// key= bulk_action_slug, value= message type.
882
+		$match_array = [
883
+			'approve_registrations'    => 'registration',
884
+			'decline_registrations'    => 'declined_registration',
885
+			'pending_registrations'    => 'pending_approval',
886
+			'no_approve_registrations' => 'not_approved_registration',
887
+			'cancel_registrations'     => 'cancelled_registration',
888
+		];
889
+		$can_send    = EE_Registry::instance()->CAP->current_user_can(
890
+			'ee_send_message',
891
+			'batch_send_messages'
892
+		);
893
+		/** setup reg status bulk actions **/
894
+		$def_reg_status_actions['approve_registrations'] = esc_html__('Approve Registrations', 'event_espresso');
895
+		if ($can_send && in_array($match_array['approve_registrations'], $active_mts, true)) {
896
+			$def_reg_status_actions['approve_and_notify_registrations'] = esc_html__(
897
+				'Approve and Notify Registrations',
898
+				'event_espresso'
899
+			);
900
+		}
901
+		$def_reg_status_actions['decline_registrations'] = esc_html__('Decline Registrations', 'event_espresso');
902
+		if ($can_send && in_array($match_array['decline_registrations'], $active_mts, true)) {
903
+			$def_reg_status_actions['decline_and_notify_registrations'] = esc_html__(
904
+				'Decline and Notify Registrations',
905
+				'event_espresso'
906
+			);
907
+		}
908
+		$def_reg_status_actions['pending_registrations'] = esc_html__(
909
+			'Set Registrations to Pending Payment',
910
+			'event_espresso'
911
+		);
912
+		if ($can_send && in_array($match_array['pending_registrations'], $active_mts, true)) {
913
+			$def_reg_status_actions['pending_and_notify_registrations'] = esc_html__(
914
+				'Set Registrations to Pending Payment and Notify',
915
+				'event_espresso'
916
+			);
917
+		}
918
+		$def_reg_status_actions['no_approve_registrations'] = esc_html__(
919
+			'Set Registrations to Not Approved',
920
+			'event_espresso'
921
+		);
922
+		if ($can_send && in_array($match_array['no_approve_registrations'], $active_mts, true)) {
923
+			$def_reg_status_actions['no_approve_and_notify_registrations'] = esc_html__(
924
+				'Set Registrations to Not Approved and Notify',
925
+				'event_espresso'
926
+			);
927
+		}
928
+		$def_reg_status_actions['cancel_registrations'] = esc_html__('Cancel Registrations', 'event_espresso');
929
+		if ($can_send && in_array($match_array['cancel_registrations'], $active_mts, true)) {
930
+			$def_reg_status_actions['cancel_and_notify_registrations'] = esc_html__(
931
+				'Cancel Registrations and Notify',
932
+				'event_espresso'
933
+			);
934
+		}
935
+		$def_reg_status_actions = apply_filters(
936
+			'FHEE__Registrations_Admin_Page___set_list_table_views_default__def_reg_status_actions_array',
937
+			$def_reg_status_actions,
938
+			$active_mts,
939
+			$can_send
940
+		);
941
+
942
+		$this->_views = [
943
+			'all'   => [
944
+				'slug'        => 'all',
945
+				'label'       => esc_html__('View All Registrations', 'event_espresso'),
946
+				'count'       => 0,
947
+				'bulk_action' => array_merge(
948
+					$def_reg_status_actions,
949
+					[
950
+						'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
951
+					]
952
+				),
953
+			],
954
+			'month' => [
955
+				'slug'        => 'month',
956
+				'label'       => esc_html__('This Month', 'event_espresso'),
957
+				'count'       => 0,
958
+				'bulk_action' => array_merge(
959
+					$def_reg_status_actions,
960
+					[
961
+						'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
962
+					]
963
+				),
964
+			],
965
+			'today' => [
966
+				'slug'        => 'today',
967
+				'label'       => sprintf(
968
+					esc_html__('Today - %s', 'event_espresso'),
969
+					date('M d, Y', current_time('timestamp'))
970
+				),
971
+				'count'       => 0,
972
+				'bulk_action' => array_merge(
973
+					$def_reg_status_actions,
974
+					[
975
+						'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
976
+					]
977
+				),
978
+			],
979
+		];
980
+		if (
981
+			EE_Registry::instance()->CAP->current_user_can(
982
+				'ee_delete_registrations',
983
+				'espresso_registrations_delete_registration'
984
+			)
985
+		) {
986
+			$this->_views['incomplete'] = [
987
+				'slug'        => 'incomplete',
988
+				'label'       => esc_html__('Incomplete', 'event_espresso'),
989
+				'count'       => 0,
990
+				'bulk_action' => [
991
+					'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
992
+				],
993
+			];
994
+			$this->_views['trash']      = [
995
+				'slug'        => 'trash',
996
+				'label'       => esc_html__('Trash', 'event_espresso'),
997
+				'count'       => 0,
998
+				'bulk_action' => [
999
+					'restore_registrations' => esc_html__('Restore Registrations', 'event_espresso'),
1000
+					'delete_registrations'  => esc_html__('Delete Registrations Permanently', 'event_espresso'),
1001
+				],
1002
+			];
1003
+		}
1004
+	}
1005
+
1006
+
1007
+	protected function _set_list_table_views_contact_list()
1008
+	{
1009
+		$this->_views = [
1010
+			'in_use' => [
1011
+				'slug'        => 'in_use',
1012
+				'label'       => esc_html__('In Use', 'event_espresso'),
1013
+				'count'       => 0,
1014
+				'bulk_action' => [
1015
+					'trash_attendees' => esc_html__('Move to Trash', 'event_espresso'),
1016
+				],
1017
+			],
1018
+		];
1019
+		if (
1020
+			EE_Registry::instance()->CAP->current_user_can(
1021
+				'ee_delete_contacts',
1022
+				'espresso_registrations_trash_attendees'
1023
+			)
1024
+		) {
1025
+			$this->_views['trash'] = [
1026
+				'slug'        => 'trash',
1027
+				'label'       => esc_html__('Trash', 'event_espresso'),
1028
+				'count'       => 0,
1029
+				'bulk_action' => [
1030
+					'restore_attendees' => esc_html__('Restore from Trash', 'event_espresso'),
1031
+				],
1032
+			];
1033
+		}
1034
+	}
1035
+
1036
+
1037
+	/**
1038
+	 * @return array
1039
+	 * @throws EE_Error
1040
+	 */
1041
+	protected function _registration_legend_items()
1042
+	{
1043
+		$fc_items = [
1044
+			'star-icon'        => [
1045
+				'class' => 'dashicons dashicons-star-filled gold-icon',
1046
+				'desc'  => esc_html__('This is the Primary Registrant', 'event_espresso'),
1047
+			],
1048
+			'view_details'     => [
1049
+				'class' => 'dashicons dashicons-clipboard',
1050
+				'desc'  => esc_html__('View Registration Details', 'event_espresso'),
1051
+			],
1052
+			'edit_attendee'    => [
1053
+				'class' => 'dashicons dashicons-admin-users',
1054
+				'desc'  => esc_html__('Edit Contact Details', 'event_espresso'),
1055
+			],
1056
+			'view_transaction' => [
1057
+				'class' => 'dashicons dashicons-cart',
1058
+				'desc'  => esc_html__('View Transaction Details', 'event_espresso'),
1059
+			],
1060
+			'view_invoice'     => [
1061
+				'class' => 'dashicons dashicons-media-spreadsheet',
1062
+				'desc'  => esc_html__('View Transaction Invoice', 'event_espresso'),
1063
+			],
1064
+		];
1065
+		if (
1066
+			EE_Registry::instance()->CAP->current_user_can(
1067
+				'ee_send_message',
1068
+				'espresso_registrations_resend_registration'
1069
+			)
1070
+		) {
1071
+			$fc_items['resend_registration'] = [
1072
+				'class' => 'dashicons dashicons-email-alt',
1073
+				'desc'  => esc_html__('Resend Registration Details', 'event_espresso'),
1074
+			];
1075
+		} else {
1076
+			$fc_items['blank'] = ['class' => 'blank', 'desc' => ''];
1077
+		}
1078
+		if (
1079
+			EE_Registry::instance()->CAP->current_user_can(
1080
+				'ee_read_global_messages',
1081
+				'view_filtered_messages'
1082
+			)
1083
+		) {
1084
+			$related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
1085
+			if (is_array($related_for_icon) && isset($related_for_icon['css_class'], $related_for_icon['label'])) {
1086
+				$fc_items['view_related_messages'] = [
1087
+					'class' => $related_for_icon['css_class'],
1088
+					'desc'  => $related_for_icon['label'],
1089
+				];
1090
+			}
1091
+		}
1092
+		$sc_items = [
1093
+			'approved_status'   => [
1094
+				'class' => 'ee-status-legend ee-status-bg--' . EEM_Registration::status_id_approved,
1095
+				'desc'  => EEH_Template::pretty_status(
1096
+					EEM_Registration::status_id_approved,
1097
+					false,
1098
+					'sentence'
1099
+				),
1100
+			],
1101
+			'pending_status'    => [
1102
+				'class' => 'ee-status-legend ee-status-bg--' . EEM_Registration::status_id_pending_payment,
1103
+				'desc'  => EEH_Template::pretty_status(
1104
+					EEM_Registration::status_id_pending_payment,
1105
+					false,
1106
+					'sentence'
1107
+				),
1108
+			],
1109
+			'wait_list'         => [
1110
+				'class' => 'ee-status-legend ee-status-bg--' . EEM_Registration::status_id_wait_list,
1111
+				'desc'  => EEH_Template::pretty_status(
1112
+					EEM_Registration::status_id_wait_list,
1113
+					false,
1114
+					'sentence'
1115
+				),
1116
+			],
1117
+			'incomplete_status' => [
1118
+				'class' => 'ee-status-legend ee-status-bg--' . EEM_Registration::status_id_incomplete,
1119
+				'desc'  => EEH_Template::pretty_status(
1120
+					EEM_Registration::status_id_incomplete,
1121
+					false,
1122
+					'sentence'
1123
+				),
1124
+			],
1125
+			'not_approved'      => [
1126
+				'class' => 'ee-status-legend ee-status-bg--' . EEM_Registration::status_id_not_approved,
1127
+				'desc'  => EEH_Template::pretty_status(
1128
+					EEM_Registration::status_id_not_approved,
1129
+					false,
1130
+					'sentence'
1131
+				),
1132
+			],
1133
+			'declined_status'   => [
1134
+				'class' => 'ee-status-legend ee-status-bg--' . EEM_Registration::status_id_declined,
1135
+				'desc'  => EEH_Template::pretty_status(
1136
+					EEM_Registration::status_id_declined,
1137
+					false,
1138
+					'sentence'
1139
+				),
1140
+			],
1141
+			'cancelled_status'  => [
1142
+				'class' => 'ee-status-legend ee-status-bg--' . EEM_Registration::status_id_cancelled,
1143
+				'desc'  => EEH_Template::pretty_status(
1144
+					EEM_Registration::status_id_cancelled,
1145
+					false,
1146
+					'sentence'
1147
+				),
1148
+			],
1149
+		];
1150
+		return array_merge($fc_items, $sc_items);
1151
+	}
1152
+
1153
+
1154
+
1155
+	/***************************************        REGISTRATION OVERVIEW        **************************************/
1156
+
1157
+
1158
+	/**
1159
+	 * @throws DomainException
1160
+	 * @throws EE_Error
1161
+	 * @throws InvalidArgumentException
1162
+	 * @throws InvalidDataTypeException
1163
+	 * @throws InvalidInterfaceException
1164
+	 */
1165
+	protected function _registrations_overview_list_table()
1166
+	{
1167
+		$this->appendAddNewRegistrationButtonToPageTitle();
1168
+		$header_text                  = '';
1169
+		$admin_page_header_decorators = [
1170
+			'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\AttendeeFilterHeader',
1171
+			'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\EventFilterHeader',
1172
+			'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\DateFilterHeader',
1173
+			'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\TicketFilterHeader',
1174
+		];
1175
+		foreach ($admin_page_header_decorators as $admin_page_header_decorator) {
1176
+			$filter_header_decorator = $this->loader->getNew($admin_page_header_decorator);
1177
+			$header_text = $filter_header_decorator->getHeaderText($header_text);
1178
+		}
1179
+		$this->_template_args['before_list_table']  = $header_text;
1180
+		$this->_template_args['after_list_table']  = $this->_display_legend($this->_registration_legend_items());
1181
+		$this->display_admin_list_table_page_with_no_sidebar();
1182
+	}
1183
+
1184
+
1185
+	/**
1186
+	 * @throws EE_Error
1187
+	 * @throws InvalidArgumentException
1188
+	 * @throws InvalidDataTypeException
1189
+	 * @throws InvalidInterfaceException
1190
+	 */
1191
+	private function appendAddNewRegistrationButtonToPageTitle()
1192
+	{
1193
+		$EVT_ID = $this->request->getRequestParam('event_id', 0, 'int');
1194
+		if (
1195
+			$EVT_ID
1196
+			&& EE_Registry::instance()->CAP->current_user_can(
1197
+				'ee_edit_registrations',
1198
+				'espresso_registrations_new_registration',
1199
+				$EVT_ID
1200
+			)
1201
+		) {
1202
+			$this->_admin_page_title .= ' ' . $this->get_action_link_or_button(
1203
+				'new_registration',
1204
+				'add-registrant',
1205
+				['event_id' => $EVT_ID],
1206
+				'add-new-h2'
1207
+			);
1208
+		}
1209
+	}
1210
+
1211
+
1212
+	/**
1213
+	 * This sets the _registration property for the registration details screen
1214
+	 *
1215
+	 * @return void
1216
+	 * @throws EE_Error
1217
+	 * @throws InvalidArgumentException
1218
+	 * @throws InvalidDataTypeException
1219
+	 * @throws InvalidInterfaceException
1220
+	 */
1221
+	private function _set_registration_object()
1222
+	{
1223
+		// get out if we've already set the object
1224
+		if ($this->_registration instanceof EE_Registration) {
1225
+			return;
1226
+		}
1227
+		$REG_ID = $this->request->getRequestParam('_REG_ID', 0, 'int');
1228
+		if ($this->_registration = $this->getRegistrationModel()->get_one_by_ID($REG_ID)) {
1229
+			return;
1230
+		}
1231
+		$error_msg = sprintf(
1232
+			esc_html__(
1233
+				'An error occurred and the details for Registration ID #%s could not be retrieved.',
1234
+				'event_espresso'
1235
+			),
1236
+			$REG_ID
1237
+		);
1238
+		EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
1239
+		$this->_registration = null;
1240
+	}
1241
+
1242
+
1243
+	/**
1244
+	 * Used to retrieve registrations for the list table.
1245
+	 *
1246
+	 * @param int  $per_page
1247
+	 * @param bool $count
1248
+	 * @param bool $this_month
1249
+	 * @param bool $today
1250
+	 * @return EE_Registration[]|int
1251
+	 * @throws EE_Error
1252
+	 * @throws InvalidArgumentException
1253
+	 * @throws InvalidDataTypeException
1254
+	 * @throws InvalidInterfaceException
1255
+	 */
1256
+	public function get_registrations(
1257
+		$per_page = 10,
1258
+		$count = false,
1259
+		$this_month = false,
1260
+		$today = false
1261
+	) {
1262
+		if ($this_month) {
1263
+			$this->request->setRequestParam('status', 'month');
1264
+		}
1265
+		if ($today) {
1266
+			$this->request->setRequestParam('status', 'today');
1267
+		}
1268
+		$query_params = $this->_get_registration_query_parameters($this->request->requestParams(), $per_page, $count);
1269
+		/**
1270
+		 * Override the default groupby added by EEM_Base so that sorts with multiple order bys work as expected
1271
+		 *
1272
+		 * @link https://events.codebasehq.com/projects/event-espresso/tickets/10093
1273
+		 * @see  https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1274
+		 *                      or if you have the development copy of EE you can view this at the path:
1275
+		 *                      /docs/G--Model-System/model-query-params.md
1276
+		 */
1277
+		$query_params['group_by'] = '';
1278
+
1279
+		return $count
1280
+			? $this->getRegistrationModel()->count($query_params)
1281
+			/** @type EE_Registration[] */
1282
+			: $this->getRegistrationModel()->get_all($query_params);
1283
+	}
1284
+
1285
+
1286
+	/**
1287
+	 * Retrieves the query parameters to be used by the Registration model for getting registrations.
1288
+	 * Note: this listens to values on the request for some of the query parameters.
1289
+	 *
1290
+	 * @param array $request
1291
+	 * @param int   $per_page
1292
+	 * @param bool  $count
1293
+	 * @return array
1294
+	 * @throws EE_Error
1295
+	 * @throws InvalidArgumentException
1296
+	 * @throws InvalidDataTypeException
1297
+	 * @throws InvalidInterfaceException
1298
+	 */
1299
+	protected function _get_registration_query_parameters(
1300
+		$request = [],
1301
+		$per_page = 10,
1302
+		$count = false
1303
+	) {
1304
+		/** @var EventEspresso\core\domain\services\admin\registrations\list_table\QueryBuilder $list_table_query_builder */
1305
+		$list_table_query_builder = $this->loader->getNew(
1306
+			'EventEspresso\core\domain\services\admin\registrations\list_table\QueryBuilder',
1307
+			[null, null, $request]
1308
+		);
1309
+		return $list_table_query_builder->getQueryParams($per_page, $count);
1310
+	}
1311
+
1312
+
1313
+	public function get_registration_status_array()
1314
+	{
1315
+		return self::$_reg_status;
1316
+	}
1317
+
1318
+
1319
+
1320
+
1321
+	/***************************************        REGISTRATION DETAILS        ***************************************/
1322
+	/**
1323
+	 * generates HTML for the View Registration Details Admin page
1324
+	 *
1325
+	 * @return void
1326
+	 * @throws DomainException
1327
+	 * @throws EE_Error
1328
+	 * @throws InvalidArgumentException
1329
+	 * @throws InvalidDataTypeException
1330
+	 * @throws InvalidInterfaceException
1331
+	 * @throws EntityNotFoundException
1332
+	 * @throws ReflectionException
1333
+	 */
1334
+	protected function _registration_details()
1335
+	{
1336
+		$this->_template_args = [];
1337
+		$this->_set_registration_object();
1338
+		if (is_object($this->_registration)) {
1339
+			$transaction                                   = $this->_registration->transaction()
1340
+				? $this->_registration->transaction()
1341
+				: EE_Transaction::new_instance();
1342
+			$this->_session                                = $transaction->session_data();
1343
+			$event_id                                      = $this->_registration->event_ID();
1344
+			$this->_template_args['reg_nmbr']['value']     = $this->_registration->ID();
1345
+			$this->_template_args['reg_nmbr']['label']     = esc_html__('Registration Number', 'event_espresso');
1346
+			$this->_template_args['reg_datetime']['value'] = $this->_registration->get_i18n_datetime('REG_date');
1347
+			$this->_template_args['reg_datetime']['label'] = esc_html__('Date', 'event_espresso');
1348
+			$this->_template_args['grand_total']           = $transaction->total();
1349
+			$this->_template_args['currency_sign']         = EE_Registry::instance()->CFG->currency->sign;
1350
+			// link back to overview
1351
+			$this->_template_args['reg_overview_url']            = REG_ADMIN_URL;
1352
+			$this->_template_args['registration']                = $this->_registration;
1353
+			$this->_template_args['filtered_registrations_link'] = EE_Admin_Page::add_query_args_and_nonce(
1354
+				[
1355
+					'action'   => 'default',
1356
+					'event_id' => $event_id,
1357
+				],
1358
+				REG_ADMIN_URL
1359
+			);
1360
+			$this->_template_args['filtered_transactions_link']  = EE_Admin_Page::add_query_args_and_nonce(
1361
+				[
1362
+					'action' => 'default',
1363
+					'EVT_ID' => $event_id,
1364
+					'page'   => 'espresso_transactions',
1365
+				],
1366
+				admin_url('admin.php')
1367
+			);
1368
+			$this->_template_args['event_link']                  = EE_Admin_Page::add_query_args_and_nonce(
1369
+				[
1370
+					'page'   => 'espresso_events',
1371
+					'action' => 'edit',
1372
+					'post'   => $event_id,
1373
+				],
1374
+				admin_url('admin.php')
1375
+			);
1376
+			// next and previous links
1377
+			$next_reg                                      = $this->_registration->next(
1378
+				null,
1379
+				[],
1380
+				'REG_ID'
1381
+			);
1382
+			$this->_template_args['next_registration']     = $next_reg
1383
+				? $this->_next_link(
1384
+					EE_Admin_Page::add_query_args_and_nonce(
1385
+						[
1386
+							'action'  => 'view_registration',
1387
+							'_REG_ID' => $next_reg['REG_ID'],
1388
+						],
1389
+						REG_ADMIN_URL
1390
+					),
1391
+					'dashicons dashicons-arrow-right ee-icon-size-22'
1392
+				)
1393
+				: '';
1394
+			$previous_reg                                  = $this->_registration->previous(
1395
+				null,
1396
+				[],
1397
+				'REG_ID'
1398
+			);
1399
+			$this->_template_args['previous_registration'] = $previous_reg
1400
+				? $this->_previous_link(
1401
+					EE_Admin_Page::add_query_args_and_nonce(
1402
+						[
1403
+							'action'  => 'view_registration',
1404
+							'_REG_ID' => $previous_reg['REG_ID'],
1405
+						],
1406
+						REG_ADMIN_URL
1407
+					),
1408
+					'dashicons dashicons-arrow-left ee-icon-size-22'
1409
+				)
1410
+				: '';
1411
+			// grab header
1412
+			$template_path                             = REG_TEMPLATE_PATH . 'reg_admin_details_header.template.php';
1413
+			$this->_template_args['REG_ID']            = $this->_registration->ID();
1414
+			$this->_template_args['admin_page_header'] = EEH_Template::display_template(
1415
+				$template_path,
1416
+				$this->_template_args,
1417
+				true
1418
+			);
1419
+		} else {
1420
+			$this->_template_args['admin_page_header'] = '';
1421
+			$this->_display_espresso_notices();
1422
+		}
1423
+		// the details template wrapper
1424
+		$this->display_admin_page_with_sidebar();
1425
+	}
1426
+
1427
+
1428
+	/**
1429
+	 * @throws EE_Error
1430
+	 * @throws InvalidArgumentException
1431
+	 * @throws InvalidDataTypeException
1432
+	 * @throws InvalidInterfaceException
1433
+	 * @throws ReflectionException
1434
+	 * @since 4.10.2.p
1435
+	 */
1436
+	protected function _registration_details_metaboxes()
1437
+	{
1438
+		do_action('AHEE__Registrations_Admin_Page___registration_details_metabox__start', $this);
1439
+		$this->_set_registration_object();
1440
+		$attendee = $this->_registration instanceof EE_Registration ? $this->_registration->attendee() : null;
1441
+		$this->addMetaBox(
1442
+			'edit-reg-status-mbox',
1443
+			esc_html__('Registration Status', 'event_espresso'),
1444
+			[$this, 'set_reg_status_buttons_metabox'],
1445
+			$this->_wp_page_slug
1446
+		);
1447
+		$this->addMetaBox(
1448
+			'edit-reg-details-mbox',
1449
+			'<span>' . esc_html__('Registration Details', 'event_espresso')
1450
+			. '&nbsp;<span class="dashicons dashicons-clipboard"></span></span>',
1451
+			[$this, '_reg_details_meta_box'],
1452
+			$this->_wp_page_slug
1453
+		);
1454
+		if (
1455
+			$attendee instanceof EE_Attendee
1456
+			&& EE_Registry::instance()->CAP->current_user_can(
1457
+				'ee_read_registration',
1458
+				'edit-reg-questions-mbox',
1459
+				$this->_registration->ID()
1460
+			)
1461
+		) {
1462
+			$this->addMetaBox(
1463
+				'edit-reg-questions-mbox',
1464
+				esc_html__('Registration Form Answers', 'event_espresso'),
1465
+				[$this, '_reg_questions_meta_box'],
1466
+				$this->_wp_page_slug
1467
+			);
1468
+		}
1469
+		$this->addMetaBox(
1470
+			'edit-reg-registrant-mbox',
1471
+			esc_html__('Contact Details', 'event_espresso'),
1472
+			[$this, '_reg_registrant_side_meta_box'],
1473
+			$this->_wp_page_slug,
1474
+			'side'
1475
+		);
1476
+		if ($this->_registration->group_size() > 1) {
1477
+			$this->addMetaBox(
1478
+				'edit-reg-attendees-mbox',
1479
+				esc_html__('Other Registrations in this Transaction', 'event_espresso'),
1480
+				[$this, '_reg_attendees_meta_box'],
1481
+				$this->_wp_page_slug
1482
+			);
1483
+		}
1484
+	}
1485
+
1486
+
1487
+	/**
1488
+	 * set_reg_status_buttons_metabox
1489
+	 *
1490
+	 * @return void
1491
+	 * @throws EE_Error
1492
+	 * @throws EntityNotFoundException
1493
+	 * @throws InvalidArgumentException
1494
+	 * @throws InvalidDataTypeException
1495
+	 * @throws InvalidInterfaceException
1496
+	 * @throws ReflectionException
1497
+	 */
1498
+	public function set_reg_status_buttons_metabox()
1499
+	{
1500
+		$this->_set_registration_object();
1501
+		$change_reg_status_form = $this->_generate_reg_status_change_form();
1502
+		$output                 = $change_reg_status_form->form_open(
1503
+			self::add_query_args_and_nonce(
1504
+				[
1505
+					'action' => 'change_reg_status',
1506
+				],
1507
+				REG_ADMIN_URL
1508
+			)
1509
+		);
1510
+		$output                 .= $change_reg_status_form->get_html();
1511
+		$output                 .= $change_reg_status_form->form_close();
1512
+		echo wp_kses($output, AllowedTags::getWithFormTags());
1513
+	}
1514
+
1515
+
1516
+	/**
1517
+	 * @return EE_Form_Section_Proper
1518
+	 * @throws EE_Error
1519
+	 * @throws InvalidArgumentException
1520
+	 * @throws InvalidDataTypeException
1521
+	 * @throws InvalidInterfaceException
1522
+	 * @throws EntityNotFoundException
1523
+	 * @throws ReflectionException
1524
+	 */
1525
+	protected function _generate_reg_status_change_form()
1526
+	{
1527
+		$reg_status_change_form_array = [
1528
+			'name'            => 'reg_status_change_form',
1529
+			'html_id'         => 'reg-status-change-form',
1530
+			'layout_strategy' => new EE_Admin_Two_Column_Layout(),
1531
+			'subsections'     => [
1532
+				'return'         => new EE_Hidden_Input(
1533
+					[
1534
+						'name'    => 'return',
1535
+						'default' => 'view_registration',
1536
+					]
1537
+				),
1538
+				'REG_ID'         => new EE_Hidden_Input(
1539
+					[
1540
+						'name'    => 'REG_ID',
1541
+						'default' => $this->_registration->ID(),
1542
+					]
1543
+				),
1544
+			],
1545
+		];
1546
+		if (
1547
+			EE_Registry::instance()->CAP->current_user_can(
1548
+				'ee_edit_registration',
1549
+				'toggle_registration_status',
1550
+				$this->_registration->ID()
1551
+			)
1552
+		) {
1553
+			$reg_status_change_form_array['subsections']['reg_status']         = new EE_Select_Input(
1554
+				$this->_get_reg_statuses(),
1555
+				[
1556
+					'html_label_text' => esc_html__('Change Registration Status to', 'event_espresso'),
1557
+					'default'         => $this->_registration->status_ID(),
1558
+				]
1559
+			);
1560
+			$reg_status_change_form_array['subsections']['send_notifications'] = new EE_Yes_No_Input(
1561
+				[
1562
+					'html_label_text' => esc_html__('Send Related Messages', 'event_espresso'),
1563
+					'default'         => false,
1564
+					'html_help_text'  => esc_html__(
1565
+						'If set to "Yes", then the related messages will be sent to the registrant.',
1566
+						'event_espresso'
1567
+					),
1568
+				]
1569
+			);
1570
+			$reg_status_change_form_array['subsections']['submit']             = new EE_Submit_Input(
1571
+				[
1572
+					'html_class'      => 'button--primary',
1573
+					'html_label_text' => '&nbsp;',
1574
+					'default'         => esc_html__('Update Registration Status', 'event_espresso'),
1575
+				]
1576
+			);
1577
+		}
1578
+		return new EE_Form_Section_Proper($reg_status_change_form_array);
1579
+	}
1580
+
1581
+
1582
+	/**
1583
+	 * Returns an array of all the buttons for the various statuses and switch status actions
1584
+	 *
1585
+	 * @return array
1586
+	 * @throws EE_Error
1587
+	 * @throws InvalidArgumentException
1588
+	 * @throws InvalidDataTypeException
1589
+	 * @throws InvalidInterfaceException
1590
+	 * @throws EntityNotFoundException
1591
+	 */
1592
+	protected function _get_reg_statuses()
1593
+	{
1594
+		$reg_status_array = $this->getRegistrationModel()->reg_status_array();
1595
+		unset($reg_status_array[ EEM_Registration::status_id_incomplete ]);
1596
+		// get current reg status
1597
+		$current_status = $this->_registration->status_ID();
1598
+		// is registration for free event? This will determine whether to display the pending payment option
1599
+		if (
1600
+			$current_status !== EEM_Registration::status_id_pending_payment
1601
+			&& EEH_Money::compare_floats($this->_registration->ticket()->price(), 0.00)
1602
+		) {
1603
+			unset($reg_status_array[ EEM_Registration::status_id_pending_payment ]);
1604
+		}
1605
+		return $this->getStatusModel()->localized_status($reg_status_array, false, 'sentence');
1606
+	}
1607
+
1608
+
1609
+	/**
1610
+	 * This method is used when using _REG_ID from request which may or may not be an array of reg_ids.
1611
+	 *
1612
+	 * @param bool $status REG status given for changing registrations to.
1613
+	 * @param bool $notify Whether to send messages notifications or not.
1614
+	 * @return array (array with reg_id(s) updated and whether update was successful.
1615
+	 * @throws DomainException
1616
+	 * @throws EE_Error
1617
+	 * @throws EntityNotFoundException
1618
+	 * @throws InvalidArgumentException
1619
+	 * @throws InvalidDataTypeException
1620
+	 * @throws InvalidInterfaceException
1621
+	 * @throws ReflectionException
1622
+	 * @throws RuntimeException
1623
+	 */
1624
+	protected function _set_registration_status_from_request($status = false, $notify = false)
1625
+	{
1626
+		$REG_IDs = $this->request->requestParamIsSet('reg_status_change_form')
1627
+			? $this->request->getRequestParam('reg_status_change_form[REG_ID]', [], 'int', true)
1628
+			: $this->request->getRequestParam('_REG_ID', [], 'int', true);
1629
+
1630
+		// sanitize $REG_IDs
1631
+		$REG_IDs = array_map('absint', $REG_IDs);
1632
+		// and remove empty entries
1633
+		$REG_IDs = array_filter($REG_IDs);
1634
+
1635
+		$result = $this->_set_registration_status($REG_IDs, $status, $notify);
1636
+
1637
+		/**
1638
+		 * Set and filter $_req_data['_REG_ID'] for any potential future messages notifications.
1639
+		 * Currently this value is used downstream by the _process_resend_registration method.
1640
+		 *
1641
+		 * @param int|array                $registration_ids The registration ids that have had their status changed successfully.
1642
+		 * @param bool                     $status           The status registrations were changed to.
1643
+		 * @param bool                     $success          If the status was changed successfully for all registrations.
1644
+		 * @param Registrations_Admin_Page $admin_page_object
1645
+		 */
1646
+		$REG_ID = apply_filters(
1647
+			'FHEE__Registrations_Admin_Page___set_registration_status_from_request__REG_IDs',
1648
+			$result['REG_ID'],
1649
+			$status,
1650
+			$result['success'],
1651
+			$this
1652
+		);
1653
+		$this->request->setRequestParam('_REG_ID', $REG_ID);
1654
+
1655
+		// notify?
1656
+		if (
1657
+			$notify
1658
+			&& $result['success']
1659
+			&& ! empty($REG_ID)
1660
+			&& EE_Registry::instance()->CAP->current_user_can(
1661
+				'ee_send_message',
1662
+				'espresso_registrations_resend_registration'
1663
+			)
1664
+		) {
1665
+			$this->_process_resend_registration();
1666
+		}
1667
+		return $result;
1668
+	}
1669
+
1670
+
1671
+	/**
1672
+	 * Set the registration status for the given reg_id (which may or may not be an array, it gets typecast to an
1673
+	 * array). Note, this method does NOT take care of possible notifications.  That is required by calling code.
1674
+	 *
1675
+	 * @param array  $REG_IDs
1676
+	 * @param string $status
1677
+	 * @param bool   $notify Used to indicate whether notification was requested or not.  This determines the context
1678
+	 *                       slug sent with setting the registration status.
1679
+	 * @return array (an array with 'success' key representing whether status change was successful, and 'REG_ID' as
1680
+	 * @throws EE_Error
1681
+	 * @throws InvalidArgumentException
1682
+	 * @throws InvalidDataTypeException
1683
+	 * @throws InvalidInterfaceException
1684
+	 * @throws ReflectionException
1685
+	 * @throws RuntimeException
1686
+	 * @throws EntityNotFoundException
1687
+	 * @throws DomainException
1688
+	 */
1689
+	protected function _set_registration_status($REG_IDs = [], $status = '', $notify = false)
1690
+	{
1691
+		$success = false;
1692
+		// typecast $REG_IDs
1693
+		$REG_IDs = (array) $REG_IDs;
1694
+		if (! empty($REG_IDs)) {
1695
+			$success = true;
1696
+			// set default status if none is passed
1697
+			$status         = $status ?: EEM_Registration::status_id_pending_payment;
1698
+			$status_context = $notify
1699
+				? Domain::CONTEXT_REGISTRATION_STATUS_CHANGE_REGISTRATION_ADMIN_NOTIFY
1700
+				: Domain::CONTEXT_REGISTRATION_STATUS_CHANGE_REGISTRATION_ADMIN;
1701
+			// loop through REG_ID's and change status
1702
+			foreach ($REG_IDs as $REG_ID) {
1703
+				$registration = $this->getRegistrationModel()->get_one_by_ID($REG_ID);
1704
+				if ($registration instanceof EE_Registration) {
1705
+					$registration->set_status(
1706
+						$status,
1707
+						false,
1708
+						new Context(
1709
+							$status_context,
1710
+							esc_html__(
1711
+								'Manually triggered status change on a Registration Admin Page route.',
1712
+								'event_espresso'
1713
+							)
1714
+						)
1715
+					);
1716
+					$result = $registration->save();
1717
+					// verifying explicit fails because update *may* just return 0 for 0 rows affected
1718
+					$success = $result !== false ? $success : false;
1719
+				}
1720
+			}
1721
+		}
1722
+
1723
+		// return $success and processed registrations
1724
+		return ['REG_ID' => $REG_IDs, 'success' => $success];
1725
+	}
1726
+
1727
+
1728
+	/**
1729
+	 * Common logic for setting up success message and redirecting to appropriate route
1730
+	 *
1731
+	 * @param string $STS_ID status id for the registration changed to
1732
+	 * @param bool   $notify indicates whether the _set_registration_status_from_request does notifications or not.
1733
+	 * @return void
1734
+	 * @throws DomainException
1735
+	 * @throws EE_Error
1736
+	 * @throws EntityNotFoundException
1737
+	 * @throws InvalidArgumentException
1738
+	 * @throws InvalidDataTypeException
1739
+	 * @throws InvalidInterfaceException
1740
+	 * @throws ReflectionException
1741
+	 * @throws RuntimeException
1742
+	 */
1743
+	protected function _reg_status_change_return($STS_ID, $notify = false)
1744
+	{
1745
+		$result  = ! empty($STS_ID) ? $this->_set_registration_status_from_request($STS_ID, $notify)
1746
+			: ['success' => false];
1747
+		$success = isset($result['success']) && $result['success'];
1748
+		// setup success message
1749
+		if ($success) {
1750
+			if (is_array($result['REG_ID']) && count($result['REG_ID']) === 1) {
1751
+				$msg = sprintf(
1752
+					esc_html__('Registration status has been set to %s', 'event_espresso'),
1753
+					EEH_Template::pretty_status($STS_ID, false, 'lower')
1754
+				);
1755
+			} else {
1756
+				$msg = sprintf(
1757
+					esc_html__('Registrations have been set to %s.', 'event_espresso'),
1758
+					EEH_Template::pretty_status($STS_ID, false, 'lower')
1759
+				);
1760
+			}
1761
+			EE_Error::add_success($msg);
1762
+		} else {
1763
+			EE_Error::add_error(
1764
+				esc_html__(
1765
+					'Something went wrong, and the status was not changed',
1766
+					'event_espresso'
1767
+				),
1768
+				__FILE__,
1769
+				__LINE__,
1770
+				__FUNCTION__
1771
+			);
1772
+		}
1773
+		$return = $this->request->getRequestParam('return');
1774
+		$route  = $return === 'view_registration'
1775
+			? ['action' => 'view_registration', '_REG_ID' => reset($result['REG_ID'])]
1776
+			: ['action' => 'default'];
1777
+		$route  = $this->mergeExistingRequestParamsWithRedirectArgs($route);
1778
+		$this->_redirect_after_action($success, '', '', $route, true);
1779
+	}
1780
+
1781
+
1782
+	/**
1783
+	 * incoming reg status change from reg details page.
1784
+	 *
1785
+	 * @return void
1786
+	 * @throws EE_Error
1787
+	 * @throws EntityNotFoundException
1788
+	 * @throws InvalidArgumentException
1789
+	 * @throws InvalidDataTypeException
1790
+	 * @throws InvalidInterfaceException
1791
+	 * @throws ReflectionException
1792
+	 * @throws RuntimeException
1793
+	 * @throws DomainException
1794
+	 */
1795
+	protected function _change_reg_status()
1796
+	{
1797
+		$this->request->setRequestParam('return', 'view_registration');
1798
+		// set notify based on whether the send notifications toggle is set or not
1799
+		$notify     = $this->request->getRequestParam('reg_status_change_form[send_notifications]', false, 'bool');
1800
+		$reg_status = $this->request->getRequestParam('reg_status_change_form[reg_status]', '');
1801
+		$this->request->setRequestParam('reg_status_change_form[reg_status]', $reg_status);
1802
+		switch ($reg_status) {
1803
+			case EEM_Registration::status_id_approved:
1804
+			case EEH_Template::pretty_status(EEM_Registration::status_id_approved, false, 'sentence'):
1805
+				$this->approve_registration($notify);
1806
+				break;
1807
+			case EEM_Registration::status_id_pending_payment:
1808
+			case EEH_Template::pretty_status(EEM_Registration::status_id_pending_payment, false, 'sentence'):
1809
+				$this->pending_registration($notify);
1810
+				break;
1811
+			case EEM_Registration::status_id_not_approved:
1812
+			case EEH_Template::pretty_status(EEM_Registration::status_id_not_approved, false, 'sentence'):
1813
+				$this->not_approve_registration($notify);
1814
+				break;
1815
+			case EEM_Registration::status_id_declined:
1816
+			case EEH_Template::pretty_status(EEM_Registration::status_id_declined, false, 'sentence'):
1817
+				$this->decline_registration($notify);
1818
+				break;
1819
+			case EEM_Registration::status_id_cancelled:
1820
+			case EEH_Template::pretty_status(EEM_Registration::status_id_cancelled, false, 'sentence'):
1821
+				$this->cancel_registration($notify);
1822
+				break;
1823
+			case EEM_Registration::status_id_wait_list:
1824
+			case EEH_Template::pretty_status(EEM_Registration::status_id_wait_list, false, 'sentence'):
1825
+				$this->wait_list_registration($notify);
1826
+				break;
1827
+			case EEM_Registration::status_id_incomplete:
1828
+			default:
1829
+				$this->request->unSetRequestParam('return');
1830
+				$this->_reg_status_change_return('');
1831
+				break;
1832
+		}
1833
+	}
1834
+
1835
+
1836
+	/**
1837
+	 * Callback for bulk action routes.
1838
+	 * Note: although we could just register the singular route callbacks for each bulk action route as well, this
1839
+	 * method was chosen so there is one central place all the registration status bulk actions are going through.
1840
+	 * Potentially, this provides an easier place to locate logic that is specific to these bulk actions (as opposed to
1841
+	 * when an action is happening on just a single registration).
1842
+	 *
1843
+	 * @param      $action
1844
+	 * @param bool $notify
1845
+	 */
1846
+	protected function bulk_action_on_registrations($action, $notify = false)
1847
+	{
1848
+		do_action(
1849
+			'AHEE__Registrations_Admin_Page__bulk_action_on_registrations__before_execution',
1850
+			$this,
1851
+			$action,
1852
+			$notify
1853
+		);
1854
+		$method = $action . '_registration';
1855
+		if (method_exists($this, $method)) {
1856
+			$this->$method($notify);
1857
+		}
1858
+	}
1859
+
1860
+
1861
+	/**
1862
+	 * approve_registration
1863
+	 *
1864
+	 * @param bool $notify whether or not to notify the registrant about their approval.
1865
+	 * @return void
1866
+	 * @throws EE_Error
1867
+	 * @throws EntityNotFoundException
1868
+	 * @throws InvalidArgumentException
1869
+	 * @throws InvalidDataTypeException
1870
+	 * @throws InvalidInterfaceException
1871
+	 * @throws ReflectionException
1872
+	 * @throws RuntimeException
1873
+	 * @throws DomainException
1874
+	 */
1875
+	protected function approve_registration($notify = false)
1876
+	{
1877
+		$this->_reg_status_change_return(EEM_Registration::status_id_approved, $notify);
1878
+	}
1879
+
1880
+
1881
+	/**
1882
+	 * decline_registration
1883
+	 *
1884
+	 * @param bool $notify whether or not to notify the registrant about their status change.
1885
+	 * @return void
1886
+	 * @throws EE_Error
1887
+	 * @throws EntityNotFoundException
1888
+	 * @throws InvalidArgumentException
1889
+	 * @throws InvalidDataTypeException
1890
+	 * @throws InvalidInterfaceException
1891
+	 * @throws ReflectionException
1892
+	 * @throws RuntimeException
1893
+	 * @throws DomainException
1894
+	 */
1895
+	protected function decline_registration($notify = false)
1896
+	{
1897
+		$this->_reg_status_change_return(EEM_Registration::status_id_declined, $notify);
1898
+	}
1899
+
1900
+
1901
+	/**
1902
+	 * cancel_registration
1903
+	 *
1904
+	 * @param bool $notify whether or not to notify the registrant about their status change.
1905
+	 * @return void
1906
+	 * @throws EE_Error
1907
+	 * @throws EntityNotFoundException
1908
+	 * @throws InvalidArgumentException
1909
+	 * @throws InvalidDataTypeException
1910
+	 * @throws InvalidInterfaceException
1911
+	 * @throws ReflectionException
1912
+	 * @throws RuntimeException
1913
+	 * @throws DomainException
1914
+	 */
1915
+	protected function cancel_registration($notify = false)
1916
+	{
1917
+		$this->_reg_status_change_return(EEM_Registration::status_id_cancelled, $notify);
1918
+	}
1919
+
1920
+
1921
+	/**
1922
+	 * not_approve_registration
1923
+	 *
1924
+	 * @param bool $notify whether or not to notify the registrant about their status change.
1925
+	 * @return void
1926
+	 * @throws EE_Error
1927
+	 * @throws EntityNotFoundException
1928
+	 * @throws InvalidArgumentException
1929
+	 * @throws InvalidDataTypeException
1930
+	 * @throws InvalidInterfaceException
1931
+	 * @throws ReflectionException
1932
+	 * @throws RuntimeException
1933
+	 * @throws DomainException
1934
+	 */
1935
+	protected function not_approve_registration($notify = false)
1936
+	{
1937
+		$this->_reg_status_change_return(EEM_Registration::status_id_not_approved, $notify);
1938
+	}
1939
+
1940
+
1941
+	/**
1942
+	 * decline_registration
1943
+	 *
1944
+	 * @param bool $notify whether or not to notify the registrant about their status change.
1945
+	 * @return void
1946
+	 * @throws EE_Error
1947
+	 * @throws EntityNotFoundException
1948
+	 * @throws InvalidArgumentException
1949
+	 * @throws InvalidDataTypeException
1950
+	 * @throws InvalidInterfaceException
1951
+	 * @throws ReflectionException
1952
+	 * @throws RuntimeException
1953
+	 * @throws DomainException
1954
+	 */
1955
+	protected function pending_registration($notify = false)
1956
+	{
1957
+		$this->_reg_status_change_return(EEM_Registration::status_id_pending_payment, $notify);
1958
+	}
1959
+
1960
+
1961
+	/**
1962
+	 * waitlist_registration
1963
+	 *
1964
+	 * @param bool $notify whether or not to notify the registrant about their status change.
1965
+	 * @return void
1966
+	 * @throws EE_Error
1967
+	 * @throws EntityNotFoundException
1968
+	 * @throws InvalidArgumentException
1969
+	 * @throws InvalidDataTypeException
1970
+	 * @throws InvalidInterfaceException
1971
+	 * @throws ReflectionException
1972
+	 * @throws RuntimeException
1973
+	 * @throws DomainException
1974
+	 */
1975
+	protected function wait_list_registration($notify = false)
1976
+	{
1977
+		$this->_reg_status_change_return(EEM_Registration::status_id_wait_list, $notify);
1978
+	}
1979
+
1980
+
1981
+	/**
1982
+	 * generates HTML for the Registration main meta box
1983
+	 *
1984
+	 * @return void
1985
+	 * @throws DomainException
1986
+	 * @throws EE_Error
1987
+	 * @throws InvalidArgumentException
1988
+	 * @throws InvalidDataTypeException
1989
+	 * @throws InvalidInterfaceException
1990
+	 * @throws ReflectionException
1991
+	 * @throws EntityNotFoundException
1992
+	 */
1993
+	public function _reg_details_meta_box()
1994
+	{
1995
+		EEH_Autoloader::register_line_item_display_autoloaders();
1996
+		EEH_Autoloader::register_line_item_filter_autoloaders();
1997
+		EE_Registry::instance()->load_helper('Line_Item');
1998
+		$transaction    = $this->_registration->transaction() ? $this->_registration->transaction()
1999
+			: EE_Transaction::new_instance();
2000
+		$this->_session = $transaction->session_data();
2001
+		$filters        = new EE_Line_Item_Filter_Collection();
2002
+		$filters->add(new EE_Single_Registration_Line_Item_Filter($this->_registration));
2003
+		$filters->add(new EE_Non_Zero_Line_Item_Filter());
2004
+		$line_item_filter_processor              = new EE_Line_Item_Filter_Processor(
2005
+			$filters,
2006
+			$transaction->total_line_item()
2007
+		);
2008
+		$filtered_line_item_tree                 = $line_item_filter_processor->process();
2009
+		$line_item_display                       = new EE_Line_Item_Display(
2010
+			'reg_admin_table',
2011
+			'EE_Admin_Table_Registration_Line_Item_Display_Strategy'
2012
+		);
2013
+		$this->_template_args['line_item_table'] = $line_item_display->display_line_item(
2014
+			$filtered_line_item_tree,
2015
+			['EE_Registration' => $this->_registration]
2016
+		);
2017
+		$attendee                                = $this->_registration->attendee();
2018
+		if (
2019
+			EE_Registry::instance()->CAP->current_user_can(
2020
+				'ee_read_transaction',
2021
+				'espresso_transactions_view_transaction'
2022
+			)
2023
+		) {
2024
+			$this->_template_args['view_transaction_button'] = EEH_Template::get_button_or_link(
2025
+				EE_Admin_Page::add_query_args_and_nonce(
2026
+					[
2027
+						'action' => 'view_transaction',
2028
+						'TXN_ID' => $transaction->ID(),
2029
+					],
2030
+					TXN_ADMIN_URL
2031
+				),
2032
+				esc_html__(' View Transaction', 'event_espresso'),
2033
+				'button button--secondary right',
2034
+				'dashicons dashicons-cart'
2035
+			);
2036
+		} else {
2037
+			$this->_template_args['view_transaction_button'] = '';
2038
+		}
2039
+		if (
2040
+			$attendee instanceof EE_Attendee
2041
+			&& EE_Registry::instance()->CAP->current_user_can(
2042
+				'ee_send_message',
2043
+				'espresso_registrations_resend_registration'
2044
+			)
2045
+		) {
2046
+			$this->_template_args['resend_registration_button'] = EEH_Template::get_button_or_link(
2047
+				EE_Admin_Page::add_query_args_and_nonce(
2048
+					[
2049
+						'action'      => 'resend_registration',
2050
+						'_REG_ID'     => $this->_registration->ID(),
2051
+						'redirect_to' => 'view_registration',
2052
+					],
2053
+					REG_ADMIN_URL
2054
+				),
2055
+				esc_html__(' Resend Registration', 'event_espresso'),
2056
+				'button button--secondary right',
2057
+				'dashicons dashicons-email-alt'
2058
+			);
2059
+		} else {
2060
+			$this->_template_args['resend_registration_button'] = '';
2061
+		}
2062
+		$this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
2063
+		$payment                               = $transaction->get_first_related('Payment');
2064
+		$payment                               = ! $payment instanceof EE_Payment
2065
+			? EE_Payment::new_instance()
2066
+			: $payment;
2067
+		$payment_method                        = $payment->get_first_related('Payment_Method');
2068
+		$payment_method                        = ! $payment_method instanceof EE_Payment_Method
2069
+			? EE_Payment_Method::new_instance()
2070
+			: $payment_method;
2071
+		$reg_details                           = [
2072
+			'payment_method'       => $payment_method->name(),
2073
+			'response_msg'         => $payment->gateway_response(),
2074
+			'registration_id'      => $this->_registration->get('REG_code'),
2075
+			'registration_session' => $this->_registration->session_ID(),
2076
+			'ip_address'           => isset($this->_session['ip_address']) ? $this->_session['ip_address'] : '',
2077
+			'user_agent'           => isset($this->_session['user_agent']) ? $this->_session['user_agent'] : '',
2078
+		];
2079
+		if (isset($reg_details['registration_id'])) {
2080
+			$this->_template_args['reg_details']['registration_id']['value'] = $reg_details['registration_id'];
2081
+			$this->_template_args['reg_details']['registration_id']['label'] = esc_html__(
2082
+				'Registration ID',
2083
+				'event_espresso'
2084
+			);
2085
+			$this->_template_args['reg_details']['registration_id']['class'] = 'regular-text';
2086
+		}
2087
+		if (isset($reg_details['payment_method'])) {
2088
+			$this->_template_args['reg_details']['payment_method']['value'] = $reg_details['payment_method'];
2089
+			$this->_template_args['reg_details']['payment_method']['label'] = esc_html__(
2090
+				'Most Recent Payment Method',
2091
+				'event_espresso'
2092
+			);
2093
+			$this->_template_args['reg_details']['payment_method']['class'] = 'regular-text';
2094
+			$this->_template_args['reg_details']['response_msg']['value']   = $reg_details['response_msg'];
2095
+			$this->_template_args['reg_details']['response_msg']['label']   = esc_html__(
2096
+				'Payment method response',
2097
+				'event_espresso'
2098
+			);
2099
+			$this->_template_args['reg_details']['response_msg']['class']   = 'regular-text';
2100
+		}
2101
+		$this->_template_args['reg_details']['registration_session']['value'] = $reg_details['registration_session'];
2102
+		$this->_template_args['reg_details']['registration_session']['label'] = esc_html__(
2103
+			'Registration Session',
2104
+			'event_espresso'
2105
+		);
2106
+		$this->_template_args['reg_details']['registration_session']['class'] = 'regular-text';
2107
+		$this->_template_args['reg_details']['ip_address']['value']           = $reg_details['ip_address'];
2108
+		$this->_template_args['reg_details']['ip_address']['label']           = esc_html__(
2109
+			'Registration placed from IP',
2110
+			'event_espresso'
2111
+		);
2112
+		$this->_template_args['reg_details']['ip_address']['class']           = 'regular-text';
2113
+		$this->_template_args['reg_details']['user_agent']['value']           = $reg_details['user_agent'];
2114
+		$this->_template_args['reg_details']['user_agent']['label']           = esc_html__(
2115
+			'Registrant User Agent',
2116
+			'event_espresso'
2117
+		);
2118
+		$this->_template_args['reg_details']['user_agent']['class']           = 'large-text';
2119
+		$this->_template_args['event_link']                                   = EE_Admin_Page::add_query_args_and_nonce(
2120
+			[
2121
+				'action'   => 'default',
2122
+				'event_id' => $this->_registration->event_ID(),
2123
+			],
2124
+			REG_ADMIN_URL
2125
+		);
2126
+
2127
+		$this->_template_args['REG_ID'] = $this->_registration->ID();
2128
+		$this->_template_args['event_id'] = $this->_registration->event_ID();
2129
+
2130
+		$template_path = REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_reg_details.template.php';
2131
+		EEH_Template::display_template($template_path, $this->_template_args); // already escaped
2132
+	}
2133
+
2134
+
2135
+	/**
2136
+	 * generates HTML for the Registration Questions meta box.
2137
+	 * If pre-4.8.32.rc.000 hooks are used, uses old methods (with its filters),
2138
+	 * otherwise uses new forms system
2139
+	 *
2140
+	 * @return void
2141
+	 * @throws DomainException
2142
+	 * @throws EE_Error
2143
+	 * @throws InvalidArgumentException
2144
+	 * @throws InvalidDataTypeException
2145
+	 * @throws InvalidInterfaceException
2146
+	 * @throws ReflectionException
2147
+	 */
2148
+	public function _reg_questions_meta_box()
2149
+	{
2150
+		// allow someone to override this method entirely
2151
+		if (
2152
+			apply_filters(
2153
+				'FHEE__Registrations_Admin_Page___reg_questions_meta_box__do_default',
2154
+				true,
2155
+				$this,
2156
+				$this->_registration
2157
+			)
2158
+		) {
2159
+			$form = $this->_get_reg_custom_questions_form(
2160
+				$this->_registration->ID()
2161
+			);
2162
+
2163
+			$this->_template_args['att_questions'] = count($form->subforms()) > 0
2164
+				? $form->get_html_and_js()
2165
+				: '';
2166
+
2167
+			$this->_template_args['reg_questions_form_action'] = 'edit_registration';
2168
+			$this->_template_args['REG_ID'] = $this->_registration->ID();
2169
+			$template_path = REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_reg_questions.template.php';
2170
+			EEH_Template::display_template($template_path, $this->_template_args);
2171
+		}
2172
+	}
2173
+
2174
+
2175
+	/**
2176
+	 * form_before_question_group
2177
+	 *
2178
+	 * @param string $output
2179
+	 * @return        string
2180
+	 * @deprecated    as of 4.8.32.rc.000
2181
+	 */
2182
+	public function form_before_question_group($output)
2183
+	{
2184
+		EE_Error::doing_it_wrong(
2185
+			__CLASS__ . '::' . __FUNCTION__,
2186
+			esc_html__(
2187
+				'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.',
2188
+				'event_espresso'
2189
+			),
2190
+			'4.8.32.rc.000'
2191
+		);
2192
+		return '
2193 2193
 	<table class="form-table ee-width-100">
2194 2194
 		<tbody>
2195 2195
 			';
2196
-    }
2197
-
2198
-
2199
-    /**
2200
-     * form_after_question_group
2201
-     *
2202
-     * @param string $output
2203
-     * @return        string
2204
-     * @deprecated    as of 4.8.32.rc.000
2205
-     */
2206
-    public function form_after_question_group($output)
2207
-    {
2208
-        EE_Error::doing_it_wrong(
2209
-            __CLASS__ . '::' . __FUNCTION__,
2210
-            esc_html__(
2211
-                '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.',
2212
-                'event_espresso'
2213
-            ),
2214
-            '4.8.32.rc.000'
2215
-        );
2216
-        return '
2196
+	}
2197
+
2198
+
2199
+	/**
2200
+	 * form_after_question_group
2201
+	 *
2202
+	 * @param string $output
2203
+	 * @return        string
2204
+	 * @deprecated    as of 4.8.32.rc.000
2205
+	 */
2206
+	public function form_after_question_group($output)
2207
+	{
2208
+		EE_Error::doing_it_wrong(
2209
+			__CLASS__ . '::' . __FUNCTION__,
2210
+			esc_html__(
2211
+				'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.',
2212
+				'event_espresso'
2213
+			),
2214
+			'4.8.32.rc.000'
2215
+		);
2216
+		return '
2217 2217
 			<tr class="hide-if-no-js">
2218 2218
 				<th> </th>
2219 2219
 				<td class="reg-admin-edit-attendee-question-td">
2220 2220
 					<a class="reg-admin-edit-attendee-question-lnk" href="#" title="'
2221
-               . esc_attr__('click to edit question', 'event_espresso')
2222
-               . '">
2221
+			   . esc_attr__('click to edit question', 'event_espresso')
2222
+			   . '">
2223 2223
 						<span class="reg-admin-edit-question-group-spn lt-grey-txt">'
2224
-               . esc_html__('edit the above question group', 'event_espresso')
2225
-               . '</span>
2224
+			   . esc_html__('edit the above question group', 'event_espresso')
2225
+			   . '</span>
2226 2226
 						<div class="dashicons dashicons-edit"></div>
2227 2227
 					</a>
2228 2228
 				</td>
@@ -2230,636 +2230,636 @@  discard block
 block discarded – undo
2230 2230
 		</tbody>
2231 2231
 	</table>
2232 2232
 ';
2233
-    }
2234
-
2235
-
2236
-    /**
2237
-     * form_form_field_label_wrap
2238
-     *
2239
-     * @param string $label
2240
-     * @return        string
2241
-     * @deprecated    as of 4.8.32.rc.000
2242
-     */
2243
-    public function form_form_field_label_wrap($label)
2244
-    {
2245
-        EE_Error::doing_it_wrong(
2246
-            __CLASS__ . '::' . __FUNCTION__,
2247
-            esc_html__(
2248
-                '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.',
2249
-                'event_espresso'
2250
-            ),
2251
-            '4.8.32.rc.000'
2252
-        );
2253
-        return '
2233
+	}
2234
+
2235
+
2236
+	/**
2237
+	 * form_form_field_label_wrap
2238
+	 *
2239
+	 * @param string $label
2240
+	 * @return        string
2241
+	 * @deprecated    as of 4.8.32.rc.000
2242
+	 */
2243
+	public function form_form_field_label_wrap($label)
2244
+	{
2245
+		EE_Error::doing_it_wrong(
2246
+			__CLASS__ . '::' . __FUNCTION__,
2247
+			esc_html__(
2248
+				'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.',
2249
+				'event_espresso'
2250
+			),
2251
+			'4.8.32.rc.000'
2252
+		);
2253
+		return '
2254 2254
 			<tr>
2255 2255
 				<th>
2256 2256
 					' . $label . '
2257 2257
 				</th>';
2258
-    }
2259
-
2260
-
2261
-    /**
2262
-     * form_form_field_input__wrap
2263
-     *
2264
-     * @param string $input
2265
-     * @return        string
2266
-     * @deprecated    as of 4.8.32.rc.000
2267
-     */
2268
-    public function form_form_field_input__wrap($input)
2269
-    {
2270
-        EE_Error::doing_it_wrong(
2271
-            __CLASS__ . '::' . __FUNCTION__,
2272
-            esc_html__(
2273
-                '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.',
2274
-                'event_espresso'
2275
-            ),
2276
-            '4.8.32.rc.000'
2277
-        );
2278
-        return '
2258
+	}
2259
+
2260
+
2261
+	/**
2262
+	 * form_form_field_input__wrap
2263
+	 *
2264
+	 * @param string $input
2265
+	 * @return        string
2266
+	 * @deprecated    as of 4.8.32.rc.000
2267
+	 */
2268
+	public function form_form_field_input__wrap($input)
2269
+	{
2270
+		EE_Error::doing_it_wrong(
2271
+			__CLASS__ . '::' . __FUNCTION__,
2272
+			esc_html__(
2273
+				'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.',
2274
+				'event_espresso'
2275
+			),
2276
+			'4.8.32.rc.000'
2277
+		);
2278
+		return '
2279 2279
 				<td class="reg-admin-attendee-questions-input-td disabled-input">
2280 2280
 					' . $input . '
2281 2281
 				</td>
2282 2282
 			</tr>';
2283
-    }
2284
-
2285
-
2286
-    /**
2287
-     * Updates the registration's custom questions according to the form info, if the form is submitted.
2288
-     * If it's not a post, the "view_registrations" route will be called next on the SAME request
2289
-     * to display the page
2290
-     *
2291
-     * @return void
2292
-     * @throws EE_Error
2293
-     * @throws InvalidArgumentException
2294
-     * @throws InvalidDataTypeException
2295
-     * @throws InvalidInterfaceException
2296
-     * @throws ReflectionException
2297
-     */
2298
-    protected function _update_attendee_registration_form()
2299
-    {
2300
-        do_action('AHEE__Registrations_Admin_Page___update_attendee_registration_form__start', $this);
2301
-        if ($_SERVER['REQUEST_METHOD'] === 'POST') {
2302
-            $REG_ID  = $this->request->getRequestParam('_REG_ID', 0, 'int');
2303
-            $success = $this->_save_reg_custom_questions_form($REG_ID);
2304
-            if ($success) {
2305
-                $what  = esc_html__('Registration Form', 'event_espresso');
2306
-                $route = $REG_ID
2307
-                    ? ['action' => 'view_registration', '_REG_ID' => $REG_ID]
2308
-                    : ['action' => 'default'];
2309
-                $this->_redirect_after_action(true, $what, esc_html__('updated', 'event_espresso'), $route);
2310
-            }
2311
-        }
2312
-    }
2313
-
2314
-
2315
-    /**
2316
-     * Gets the form for saving registrations custom questions (if done
2317
-     * previously retrieves the cached form object, which may have validation errors in it)
2318
-     *
2319
-     * @param int $REG_ID
2320
-     * @return EE_Registration_Custom_Questions_Form
2321
-     * @throws EE_Error
2322
-     * @throws InvalidArgumentException
2323
-     * @throws InvalidDataTypeException
2324
-     * @throws InvalidInterfaceException
2325
-     * @throws ReflectionException
2326
-     */
2327
-    protected function _get_reg_custom_questions_form($REG_ID)
2328
-    {
2329
-        if (! $this->_reg_custom_questions_form) {
2330
-            require_once(REG_ADMIN . 'form_sections/EE_Registration_Custom_Questions_Form.form.php');
2331
-            $this->_reg_custom_questions_form = new EE_Registration_Custom_Questions_Form(
2332
-                $this->getRegistrationModel()->get_one_by_ID($REG_ID)
2333
-            );
2334
-            $this->_reg_custom_questions_form->_construct_finalize(null, null);
2335
-        }
2336
-        return $this->_reg_custom_questions_form;
2337
-    }
2338
-
2339
-
2340
-    /**
2341
-     * Saves
2342
-     *
2343
-     * @param bool $REG_ID
2344
-     * @return bool
2345
-     * @throws EE_Error
2346
-     * @throws InvalidArgumentException
2347
-     * @throws InvalidDataTypeException
2348
-     * @throws InvalidInterfaceException
2349
-     * @throws ReflectionException
2350
-     */
2351
-    private function _save_reg_custom_questions_form($REG_ID = 0)
2352
-    {
2353
-        if (! $REG_ID) {
2354
-            EE_Error::add_error(
2355
-                esc_html__(
2356
-                    'An error occurred. No registration ID was received.',
2357
-                    'event_espresso'
2358
-                ),
2359
-                __FILE__,
2360
-                __FUNCTION__,
2361
-                __LINE__
2362
-            );
2363
-        }
2364
-        $form = $this->_get_reg_custom_questions_form($REG_ID);
2365
-        $form->receive_form_submission($this->request->requestParams());
2366
-        $success = false;
2367
-        if ($form->is_valid()) {
2368
-            foreach ($form->subforms() as $question_group_form) {
2369
-                foreach ($question_group_form->inputs() as $question_id => $input) {
2370
-                    $where_conditions    = [
2371
-                        'QST_ID' => $question_id,
2372
-                        'REG_ID' => $REG_ID,
2373
-                    ];
2374
-                    $possibly_new_values = [
2375
-                        'ANS_value' => $input->normalized_value(),
2376
-                    ];
2377
-                    $answer              = EEM_Answer::instance()->get_one([$where_conditions]);
2378
-                    if ($answer instanceof EE_Answer) {
2379
-                        $success = $answer->save($possibly_new_values);
2380
-                    } else {
2381
-                        // insert it then
2382
-                        $cols_n_vals = array_merge($where_conditions, $possibly_new_values);
2383
-                        $answer      = EE_Answer::new_instance($cols_n_vals);
2384
-                        $success     = $answer->save();
2385
-                    }
2386
-                }
2387
-            }
2388
-        } else {
2389
-            EE_Error::add_error($form->get_validation_error_string(), __FILE__, __FUNCTION__, __LINE__);
2390
-        }
2391
-        return $success;
2392
-    }
2393
-
2394
-
2395
-    /**
2396
-     * generates HTML for the Registration main meta box
2397
-     *
2398
-     * @return void
2399
-     * @throws DomainException
2400
-     * @throws EE_Error
2401
-     * @throws InvalidArgumentException
2402
-     * @throws InvalidDataTypeException
2403
-     * @throws InvalidInterfaceException
2404
-     * @throws ReflectionException
2405
-     */
2406
-    public function _reg_attendees_meta_box()
2407
-    {
2408
-        $REG = $this->getRegistrationModel();
2409
-        // get all other registrations on this transaction, and cache
2410
-        // the attendees for them so we don't have to run another query using force_join
2411
-        $registrations                           = $REG->get_all(
2412
-            [
2413
-                [
2414
-                    'TXN_ID' => $this->_registration->transaction_ID(),
2415
-                    'REG_ID' => ['!=', $this->_registration->ID()],
2416
-                ],
2417
-                'force_join'               => ['Attendee'],
2418
-                'default_where_conditions' => 'other_models_only',
2419
-            ]
2420
-        );
2421
-        $this->_template_args['attendees']       = [];
2422
-        $this->_template_args['attendee_notice'] = '';
2423
-        if (
2424
-            empty($registrations)
2425
-            || (is_array($registrations)
2426
-                && ! EEH_Array::get_one_item_from_array($registrations))
2427
-        ) {
2428
-            EE_Error::add_error(
2429
-                esc_html__(
2430
-                    'There are no records attached to this registration. Something may have gone wrong with the registration',
2431
-                    'event_espresso'
2432
-                ),
2433
-                __FILE__,
2434
-                __FUNCTION__,
2435
-                __LINE__
2436
-            );
2437
-            $this->_template_args['attendee_notice'] = EE_Error::get_notices();
2438
-        } else {
2439
-            $att_nmbr = 1;
2440
-            foreach ($registrations as $registration) {
2441
-                /* @var $registration EE_Registration */
2442
-                $attendee                                                      = $registration->attendee()
2443
-                    ? $registration->attendee()
2444
-                    : $this->getAttendeeModel()->create_default_object();
2445
-                $this->_template_args['attendees'][ $att_nmbr ]['STS_ID']      = $registration->status_ID();
2446
-                $this->_template_args['attendees'][ $att_nmbr ]['fname']       = $attendee->fname();
2447
-                $this->_template_args['attendees'][ $att_nmbr ]['lname']       = $attendee->lname();
2448
-                $this->_template_args['attendees'][ $att_nmbr ]['email']       = $attendee->email();
2449
-                $this->_template_args['attendees'][ $att_nmbr ]['final_price'] = $registration->final_price();
2450
-                $this->_template_args['attendees'][ $att_nmbr ]['address']     = implode(
2451
-                    ', ',
2452
-                    $attendee->full_address_as_array()
2453
-                );
2454
-                $this->_template_args['attendees'][ $att_nmbr ]['att_link']    = self::add_query_args_and_nonce(
2455
-                    [
2456
-                        'action' => 'edit_attendee',
2457
-                        'post'   => $attendee->ID(),
2458
-                    ],
2459
-                    REG_ADMIN_URL
2460
-                );
2461
-                $this->_template_args['attendees'][ $att_nmbr ]['event_name']  =
2462
-                    $registration->event_obj() instanceof EE_Event
2463
-                        ? $registration->event_obj()->name()
2464
-                        : '';
2465
-                $att_nmbr++;
2466
-            }
2467
-            $this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
2468
-        }
2469
-        $template_path = REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_attendees.template.php';
2470
-        EEH_Template::display_template($template_path, $this->_template_args);
2471
-    }
2472
-
2473
-
2474
-    /**
2475
-     * generates HTML for the Edit Registration side meta box
2476
-     *
2477
-     * @return void
2478
-     * @throws DomainException
2479
-     * @throws EE_Error
2480
-     * @throws InvalidArgumentException
2481
-     * @throws InvalidDataTypeException
2482
-     * @throws InvalidInterfaceException
2483
-     * @throws ReflectionException
2484
-     */
2485
-    public function _reg_registrant_side_meta_box()
2486
-    {
2487
-        /*@var $attendee EE_Attendee */
2488
-        $att_check = $this->_registration->attendee();
2489
-        $attendee  = $att_check instanceof EE_Attendee
2490
-            ? $att_check
2491
-            : $this->getAttendeeModel()->create_default_object();
2492
-        // now let's determine if this is not the primary registration.  If it isn't then we set the
2493
-        // primary_registration object for reference BUT ONLY if the Attendee object loaded is not the same as the
2494
-        // primary registration object (that way we know if we need to show create button or not)
2495
-        if (! $this->_registration->is_primary_registrant()) {
2496
-            $primary_registration = $this->_registration->get_primary_registration();
2497
-            $primary_attendee     = $primary_registration instanceof EE_Registration ? $primary_registration->attendee()
2498
-                : null;
2499
-            if (! $primary_attendee instanceof EE_Attendee || $attendee->ID() !== $primary_attendee->ID()) {
2500
-                // in here?  This means the displayed registration is not the primary registrant but ALREADY HAS its own
2501
-                // custom attendee object so let's not worry about the primary reg.
2502
-                $primary_registration = null;
2503
-            }
2504
-        } else {
2505
-            $primary_registration = null;
2506
-        }
2507
-        $this->_template_args['ATT_ID']            = $attendee->ID();
2508
-        $this->_template_args['fname']             = $attendee->fname();
2509
-        $this->_template_args['lname']             = $attendee->lname();
2510
-        $this->_template_args['email']             = $attendee->email();
2511
-        $this->_template_args['phone']             = $attendee->phone();
2512
-        $this->_template_args['formatted_address'] = EEH_Address::format($attendee);
2513
-        // edit link
2514
-        $this->_template_args['att_edit_link']  = EE_Admin_Page::add_query_args_and_nonce(
2515
-            [
2516
-                'action' => 'edit_attendee',
2517
-                'post'   => $attendee->ID(),
2518
-            ],
2519
-            REG_ADMIN_URL
2520
-        );
2521
-        $this->_template_args['att_edit_title'] = esc_html__('View details for this contact.', 'event_espresso');
2522
-        $this->_template_args['att_edit_label'] = esc_html__('View/Edit Contact', 'event_espresso');
2523
-        // create link
2524
-        $this->_template_args['create_link']  = $primary_registration instanceof EE_Registration
2525
-            ? EE_Admin_Page::add_query_args_and_nonce(
2526
-                [
2527
-                    'action'  => 'duplicate_attendee',
2528
-                    '_REG_ID' => $this->_registration->ID(),
2529
-                ],
2530
-                REG_ADMIN_URL
2531
-            ) : '';
2532
-        $this->_template_args['create_label'] = esc_html__('Create Contact', 'event_espresso');
2533
-        $this->_template_args['att_check'] = $att_check;
2534
-        $template_path = REG_TEMPLATE_PATH . 'reg_admin_details_side_meta_box_registrant.template.php';
2535
-        EEH_Template::display_template($template_path, $this->_template_args);
2536
-    }
2537
-
2538
-
2539
-    /**
2540
-     * trash or restore registrations
2541
-     *
2542
-     * @param boolean $trash whether to archive or restore
2543
-     * @return void
2544
-     * @throws EE_Error
2545
-     * @throws InvalidArgumentException
2546
-     * @throws InvalidDataTypeException
2547
-     * @throws InvalidInterfaceException
2548
-     * @throws RuntimeException
2549
-     */
2550
-    protected function _trash_or_restore_registrations($trash = true)
2551
-    {
2552
-        // if empty _REG_ID then get out because there's nothing to do
2553
-        $REG_IDs = $this->request->getRequestParam('_REG_ID', [], 'int', true);
2554
-        if (empty($REG_IDs)) {
2555
-            EE_Error::add_error(
2556
-                sprintf(
2557
-                    esc_html__(
2558
-                        'In order to %1$s registrations you must select which ones you wish to %1$s by clicking the checkboxes.',
2559
-                        'event_espresso'
2560
-                    ),
2561
-                    $trash ? 'trash' : 'restore'
2562
-                ),
2563
-                __FILE__,
2564
-                __LINE__,
2565
-                __FUNCTION__
2566
-            );
2567
-            $this->_redirect_after_action(false, '', '', [], true);
2568
-        }
2569
-        $success        = 0;
2570
-        $overwrite_msgs = false;
2571
-        // Checkboxes
2572
-        $reg_count = count($REG_IDs);
2573
-        // cycle thru checkboxes
2574
-        foreach ($REG_IDs as $REG_ID) {
2575
-            /** @var EE_Registration $REG */
2576
-            $REG      = $this->getRegistrationModel()->get_one_by_ID($REG_ID);
2577
-            $payments = $REG->registration_payments();
2578
-            if (! empty($payments)) {
2579
-                $name           = $REG->attendee() instanceof EE_Attendee
2580
-                    ? $REG->attendee()->full_name()
2581
-                    : esc_html__('Unknown Attendee', 'event_espresso');
2582
-                $overwrite_msgs = true;
2583
-                EE_Error::add_error(
2584
-                    sprintf(
2585
-                        esc_html__(
2586
-                            '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.',
2587
-                            'event_espresso'
2588
-                        ),
2589
-                        $name
2590
-                    ),
2591
-                    __FILE__,
2592
-                    __FUNCTION__,
2593
-                    __LINE__
2594
-                );
2595
-                // can't trash this registration because it has payments.
2596
-                continue;
2597
-            }
2598
-            $updated = $trash ? $REG->delete() : $REG->restore();
2599
-            if ($updated) {
2600
-                $success++;
2601
-            }
2602
-        }
2603
-        $this->_redirect_after_action(
2604
-            $success === $reg_count, // were ALL registrations affected?
2605
-            $success > 1
2606
-                ? esc_html__('Registrations', 'event_espresso')
2607
-                : esc_html__('Registration', 'event_espresso'),
2608
-            $trash
2609
-                ? esc_html__('moved to the trash', 'event_espresso')
2610
-                : esc_html__('restored', 'event_espresso'),
2611
-            $this->mergeExistingRequestParamsWithRedirectArgs(['action' => 'default']),
2612
-            $overwrite_msgs
2613
-        );
2614
-    }
2615
-
2616
-
2617
-    /**
2618
-     * This is used to permanently delete registrations.  Note, this will handle not only deleting permanently the
2619
-     * registration but also.
2620
-     * 1. Removing relations to EE_Attendee
2621
-     * 2. Deleting permanently the related transaction, but ONLY if all related registrations to the transaction are
2622
-     * ALSO trashed.
2623
-     * 3. Deleting permanently any related Line items but only if the above conditions are met.
2624
-     * 4. Removing relationships between all tickets and the related registrations
2625
-     * 5. Deleting permanently any related Answers (and the answers for other related registrations that were deleted.)
2626
-     * 6. Deleting permanently any related Checkins.
2627
-     *
2628
-     * @return void
2629
-     * @throws EE_Error
2630
-     * @throws InvalidArgumentException
2631
-     * @throws InvalidDataTypeException
2632
-     * @throws InvalidInterfaceException
2633
-     * @throws ReflectionException
2634
-     */
2635
-    protected function _delete_registrations()
2636
-    {
2637
-        $REG_MDL = $this->getRegistrationModel();
2638
-        $success = 0;
2639
-        // Checkboxes
2640
-        $REG_IDs = $this->request->getRequestParam('_REG_ID', [], 'int', true);
2641
-
2642
-        if (! empty($REG_IDs)) {
2643
-            // if array has more than one element than success message should be plural
2644
-            $success = count($REG_IDs) > 1 ? 2 : 1;
2645
-            // cycle thru checkboxes
2646
-            foreach ($REG_IDs as $REG_ID) {
2647
-                $REG = $REG_MDL->get_one_by_ID($REG_ID);
2648
-                if (! $REG instanceof EE_Registration) {
2649
-                    continue;
2650
-                }
2651
-                $deleted = $this->_delete_registration($REG);
2652
-                if (! $deleted) {
2653
-                    $success = 0;
2654
-                }
2655
-            }
2656
-        }
2657
-
2658
-        $what        = $success > 1
2659
-            ? esc_html__('Registrations', 'event_espresso')
2660
-            : esc_html__('Registration', 'event_espresso');
2661
-        $action_desc = esc_html__('permanently deleted.', 'event_espresso');
2662
-        $this->_redirect_after_action(
2663
-            $success,
2664
-            $what,
2665
-            $action_desc,
2666
-            $this->mergeExistingRequestParamsWithRedirectArgs(['action' => 'default']),
2667
-            true
2668
-        );
2669
-    }
2670
-
2671
-
2672
-    /**
2673
-     * handles the permanent deletion of a registration.  See comments with _delete_registrations() for details on what
2674
-     * models get affected.
2675
-     *
2676
-     * @param EE_Registration $REG registration to be deleted permanently
2677
-     * @return bool true = successful deletion, false = fail.
2678
-     * @throws EE_Error
2679
-     * @throws InvalidArgumentException
2680
-     * @throws InvalidDataTypeException
2681
-     * @throws InvalidInterfaceException
2682
-     * @throws ReflectionException
2683
-     */
2684
-    protected function _delete_registration(EE_Registration $REG)
2685
-    {
2686
-        // first we start with the transaction... ultimately, we WILL not delete permanently if there are any related
2687
-        // registrations on the transaction that are NOT trashed.
2688
-        $TXN = $REG->get_first_related('Transaction');
2689
-        if (! $TXN instanceof EE_Transaction) {
2690
-            EE_Error::add_error(
2691
-                sprintf(
2692
-                    esc_html__(
2693
-                        'Unable to permanently delete registration %d because its related transaction has already been deleted. If you can restore the related transaction to the database then this registration can be deleted.',
2694
-                        'event_espresso'
2695
-                    ),
2696
-                    $REG->id()
2697
-                ),
2698
-                __FILE__,
2699
-                __FUNCTION__,
2700
-                __LINE__
2701
-            );
2702
-            return false;
2703
-        }
2704
-        $REGS        = $TXN->get_many_related('Registration');
2705
-        $all_trashed = true;
2706
-        foreach ($REGS as $registration) {
2707
-            if (! $registration->get('REG_deleted')) {
2708
-                $all_trashed = false;
2709
-            }
2710
-        }
2711
-        if (! $all_trashed) {
2712
-            EE_Error::add_error(
2713
-                esc_html__(
2714
-                    '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.',
2715
-                    'event_espresso'
2716
-                ),
2717
-                __FILE__,
2718
-                __FUNCTION__,
2719
-                __LINE__
2720
-            );
2721
-            return false;
2722
-        }
2723
-        // k made it here so that means we can delete all the related transactions and their answers (but let's do them
2724
-        // separately from THIS one).
2725
-        foreach ($REGS as $registration) {
2726
-            // delete related answers
2727
-            $registration->delete_related_permanently('Answer');
2728
-            // remove relationship to EE_Attendee (but we ALWAYS leave the contact record intact)
2729
-            $attendee = $registration->get_first_related('Attendee');
2730
-            if ($attendee instanceof EE_Attendee) {
2731
-                $registration->_remove_relation_to($attendee, 'Attendee');
2732
-            }
2733
-            // now remove relationships to tickets on this registration.
2734
-            $registration->_remove_relations('Ticket');
2735
-            // now delete permanently the checkins related to this registration.
2736
-            $registration->delete_related_permanently('Checkin');
2737
-            if ($registration->ID() === $REG->ID()) {
2738
-                continue;
2739
-            } //we don't want to delete permanently the existing registration just yet.
2740
-            // remove relation to transaction for these registrations if NOT the existing registrations
2741
-            $registration->_remove_relations('Transaction');
2742
-            // delete permanently any related messages.
2743
-            $registration->delete_related_permanently('Message');
2744
-            // now delete this registration permanently
2745
-            $registration->delete_permanently();
2746
-        }
2747
-        // now all related registrations on the transaction are handled.  So let's just handle this registration itself
2748
-        // (the transaction and line items should be all that's left).
2749
-        // delete the line items related to the transaction for this registration.
2750
-        $TXN->delete_related_permanently('Line_Item');
2751
-        // we need to remove all the relationships on the transaction
2752
-        $TXN->delete_related_permanently('Payment');
2753
-        $TXN->delete_related_permanently('Extra_Meta');
2754
-        $TXN->delete_related_permanently('Message');
2755
-        // now we can delete this REG permanently (and the transaction of course)
2756
-        $REG->delete_related_permanently('Transaction');
2757
-        return $REG->delete_permanently();
2758
-    }
2759
-
2760
-
2761
-    /**
2762
-     *    generates HTML for the Register New Attendee Admin page
2763
-     *
2764
-     * @throws DomainException
2765
-     * @throws EE_Error
2766
-     * @throws InvalidArgumentException
2767
-     * @throws InvalidDataTypeException
2768
-     * @throws InvalidInterfaceException
2769
-     * @throws ReflectionException
2770
-     */
2771
-    public function new_registration()
2772
-    {
2773
-        if (! $this->_set_reg_event()) {
2774
-            throw new EE_Error(
2775
-                esc_html__(
2776
-                    'Unable to continue with registering because there is no Event ID in the request',
2777
-                    'event_espresso'
2778
-                )
2779
-            );
2780
-        }
2781
-        /** @var CurrentPage $current_page */
2782
-        $current_page = $this->loader->getShared(CurrentPage::class);
2783
-        $current_page->setEspressoPage(true);
2784
-        // gotta start with a clean slate if we're not coming here via ajax
2785
-        if (
2786
-            ! $this->request->isAjax()
2787
-            && (
2788
-                ! $this->request->requestParamIsSet('processing_registration')
2789
-                || $this->request->requestParamIsSet('step_error')
2790
-            )
2791
-        ) {
2792
-            EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
2793
-        }
2794
-        $this->_template_args['event_name'] = '';
2795
-        // event name
2796
-        if ($this->_reg_event) {
2797
-            $this->_template_args['event_name'] = $this->_reg_event->name();
2798
-            $edit_event_url                     = self::add_query_args_and_nonce(
2799
-                [
2800
-                    'action' => 'edit',
2801
-                    'post'   => $this->_reg_event->ID(),
2802
-                ],
2803
-                EVENTS_ADMIN_URL
2804
-            );
2805
-            $edit_event_lnk                     = '<a href="'
2806
-                                                  . $edit_event_url
2807
-                                                  . '" title="'
2808
-                                                  . esc_attr__('Edit ', 'event_espresso')
2809
-                                                  . $this->_reg_event->name()
2810
-                                                  . '">'
2811
-                                                  . esc_html__('Edit Event', 'event_espresso')
2812
-                                                  . '</a>';
2813
-            $this->_template_args['event_name'] .= ' <span class="admin-page-header-edit-lnk not-bold">'
2814
-                                                   . $edit_event_lnk
2815
-                                                   . '</span>';
2816
-        }
2817
-        $this->_template_args['step_content'] = $this->_get_registration_step_content();
2818
-        if ($this->request->isAjax()) {
2819
-            $this->_return_json();
2820
-        }
2821
-        // grab header
2822
-        $template_path = REG_TEMPLATE_PATH . 'reg_admin_register_new_attendee.template.php';
2823
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
2824
-            $template_path,
2825
-            $this->_template_args,
2826
-            true
2827
-        );
2828
-        // $this->_set_publish_post_box_vars( NULL, FALSE, FALSE, NULL, FALSE );
2829
-        // the details template wrapper
2830
-        $this->display_admin_page_with_sidebar();
2831
-    }
2832
-
2833
-
2834
-    /**
2835
-     * This returns the content for a registration step
2836
-     *
2837
-     * @return string html
2838
-     * @throws DomainException
2839
-     * @throws EE_Error
2840
-     * @throws InvalidArgumentException
2841
-     * @throws InvalidDataTypeException
2842
-     * @throws InvalidInterfaceException
2843
-     * @throws ReflectionException
2844
-     */
2845
-    protected function _get_registration_step_content()
2846
-    {
2847
-        if (isset($_COOKIE['ee_registration_added']) && $_COOKIE['ee_registration_added']) {
2848
-            $warning_msg = sprintf(
2849
-                esc_html__(
2850
-                    '%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',
2851
-                    'event_espresso'
2852
-                ),
2853
-                '<br />',
2854
-                '<h3 class="important-notice">',
2855
-                '</h3>',
2856
-                '<div class="float-right">',
2857
-                '<span id="redirect_timer" class="important-notice">30</span>',
2858
-                '</div>',
2859
-                '<b>',
2860
-                '</b>'
2861
-            );
2862
-            return '
2283
+	}
2284
+
2285
+
2286
+	/**
2287
+	 * Updates the registration's custom questions according to the form info, if the form is submitted.
2288
+	 * If it's not a post, the "view_registrations" route will be called next on the SAME request
2289
+	 * to display the page
2290
+	 *
2291
+	 * @return void
2292
+	 * @throws EE_Error
2293
+	 * @throws InvalidArgumentException
2294
+	 * @throws InvalidDataTypeException
2295
+	 * @throws InvalidInterfaceException
2296
+	 * @throws ReflectionException
2297
+	 */
2298
+	protected function _update_attendee_registration_form()
2299
+	{
2300
+		do_action('AHEE__Registrations_Admin_Page___update_attendee_registration_form__start', $this);
2301
+		if ($_SERVER['REQUEST_METHOD'] === 'POST') {
2302
+			$REG_ID  = $this->request->getRequestParam('_REG_ID', 0, 'int');
2303
+			$success = $this->_save_reg_custom_questions_form($REG_ID);
2304
+			if ($success) {
2305
+				$what  = esc_html__('Registration Form', 'event_espresso');
2306
+				$route = $REG_ID
2307
+					? ['action' => 'view_registration', '_REG_ID' => $REG_ID]
2308
+					: ['action' => 'default'];
2309
+				$this->_redirect_after_action(true, $what, esc_html__('updated', 'event_espresso'), $route);
2310
+			}
2311
+		}
2312
+	}
2313
+
2314
+
2315
+	/**
2316
+	 * Gets the form for saving registrations custom questions (if done
2317
+	 * previously retrieves the cached form object, which may have validation errors in it)
2318
+	 *
2319
+	 * @param int $REG_ID
2320
+	 * @return EE_Registration_Custom_Questions_Form
2321
+	 * @throws EE_Error
2322
+	 * @throws InvalidArgumentException
2323
+	 * @throws InvalidDataTypeException
2324
+	 * @throws InvalidInterfaceException
2325
+	 * @throws ReflectionException
2326
+	 */
2327
+	protected function _get_reg_custom_questions_form($REG_ID)
2328
+	{
2329
+		if (! $this->_reg_custom_questions_form) {
2330
+			require_once(REG_ADMIN . 'form_sections/EE_Registration_Custom_Questions_Form.form.php');
2331
+			$this->_reg_custom_questions_form = new EE_Registration_Custom_Questions_Form(
2332
+				$this->getRegistrationModel()->get_one_by_ID($REG_ID)
2333
+			);
2334
+			$this->_reg_custom_questions_form->_construct_finalize(null, null);
2335
+		}
2336
+		return $this->_reg_custom_questions_form;
2337
+	}
2338
+
2339
+
2340
+	/**
2341
+	 * Saves
2342
+	 *
2343
+	 * @param bool $REG_ID
2344
+	 * @return bool
2345
+	 * @throws EE_Error
2346
+	 * @throws InvalidArgumentException
2347
+	 * @throws InvalidDataTypeException
2348
+	 * @throws InvalidInterfaceException
2349
+	 * @throws ReflectionException
2350
+	 */
2351
+	private function _save_reg_custom_questions_form($REG_ID = 0)
2352
+	{
2353
+		if (! $REG_ID) {
2354
+			EE_Error::add_error(
2355
+				esc_html__(
2356
+					'An error occurred. No registration ID was received.',
2357
+					'event_espresso'
2358
+				),
2359
+				__FILE__,
2360
+				__FUNCTION__,
2361
+				__LINE__
2362
+			);
2363
+		}
2364
+		$form = $this->_get_reg_custom_questions_form($REG_ID);
2365
+		$form->receive_form_submission($this->request->requestParams());
2366
+		$success = false;
2367
+		if ($form->is_valid()) {
2368
+			foreach ($form->subforms() as $question_group_form) {
2369
+				foreach ($question_group_form->inputs() as $question_id => $input) {
2370
+					$where_conditions    = [
2371
+						'QST_ID' => $question_id,
2372
+						'REG_ID' => $REG_ID,
2373
+					];
2374
+					$possibly_new_values = [
2375
+						'ANS_value' => $input->normalized_value(),
2376
+					];
2377
+					$answer              = EEM_Answer::instance()->get_one([$where_conditions]);
2378
+					if ($answer instanceof EE_Answer) {
2379
+						$success = $answer->save($possibly_new_values);
2380
+					} else {
2381
+						// insert it then
2382
+						$cols_n_vals = array_merge($where_conditions, $possibly_new_values);
2383
+						$answer      = EE_Answer::new_instance($cols_n_vals);
2384
+						$success     = $answer->save();
2385
+					}
2386
+				}
2387
+			}
2388
+		} else {
2389
+			EE_Error::add_error($form->get_validation_error_string(), __FILE__, __FUNCTION__, __LINE__);
2390
+		}
2391
+		return $success;
2392
+	}
2393
+
2394
+
2395
+	/**
2396
+	 * generates HTML for the Registration main meta box
2397
+	 *
2398
+	 * @return void
2399
+	 * @throws DomainException
2400
+	 * @throws EE_Error
2401
+	 * @throws InvalidArgumentException
2402
+	 * @throws InvalidDataTypeException
2403
+	 * @throws InvalidInterfaceException
2404
+	 * @throws ReflectionException
2405
+	 */
2406
+	public function _reg_attendees_meta_box()
2407
+	{
2408
+		$REG = $this->getRegistrationModel();
2409
+		// get all other registrations on this transaction, and cache
2410
+		// the attendees for them so we don't have to run another query using force_join
2411
+		$registrations                           = $REG->get_all(
2412
+			[
2413
+				[
2414
+					'TXN_ID' => $this->_registration->transaction_ID(),
2415
+					'REG_ID' => ['!=', $this->_registration->ID()],
2416
+				],
2417
+				'force_join'               => ['Attendee'],
2418
+				'default_where_conditions' => 'other_models_only',
2419
+			]
2420
+		);
2421
+		$this->_template_args['attendees']       = [];
2422
+		$this->_template_args['attendee_notice'] = '';
2423
+		if (
2424
+			empty($registrations)
2425
+			|| (is_array($registrations)
2426
+				&& ! EEH_Array::get_one_item_from_array($registrations))
2427
+		) {
2428
+			EE_Error::add_error(
2429
+				esc_html__(
2430
+					'There are no records attached to this registration. Something may have gone wrong with the registration',
2431
+					'event_espresso'
2432
+				),
2433
+				__FILE__,
2434
+				__FUNCTION__,
2435
+				__LINE__
2436
+			);
2437
+			$this->_template_args['attendee_notice'] = EE_Error::get_notices();
2438
+		} else {
2439
+			$att_nmbr = 1;
2440
+			foreach ($registrations as $registration) {
2441
+				/* @var $registration EE_Registration */
2442
+				$attendee                                                      = $registration->attendee()
2443
+					? $registration->attendee()
2444
+					: $this->getAttendeeModel()->create_default_object();
2445
+				$this->_template_args['attendees'][ $att_nmbr ]['STS_ID']      = $registration->status_ID();
2446
+				$this->_template_args['attendees'][ $att_nmbr ]['fname']       = $attendee->fname();
2447
+				$this->_template_args['attendees'][ $att_nmbr ]['lname']       = $attendee->lname();
2448
+				$this->_template_args['attendees'][ $att_nmbr ]['email']       = $attendee->email();
2449
+				$this->_template_args['attendees'][ $att_nmbr ]['final_price'] = $registration->final_price();
2450
+				$this->_template_args['attendees'][ $att_nmbr ]['address']     = implode(
2451
+					', ',
2452
+					$attendee->full_address_as_array()
2453
+				);
2454
+				$this->_template_args['attendees'][ $att_nmbr ]['att_link']    = self::add_query_args_and_nonce(
2455
+					[
2456
+						'action' => 'edit_attendee',
2457
+						'post'   => $attendee->ID(),
2458
+					],
2459
+					REG_ADMIN_URL
2460
+				);
2461
+				$this->_template_args['attendees'][ $att_nmbr ]['event_name']  =
2462
+					$registration->event_obj() instanceof EE_Event
2463
+						? $registration->event_obj()->name()
2464
+						: '';
2465
+				$att_nmbr++;
2466
+			}
2467
+			$this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
2468
+		}
2469
+		$template_path = REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_attendees.template.php';
2470
+		EEH_Template::display_template($template_path, $this->_template_args);
2471
+	}
2472
+
2473
+
2474
+	/**
2475
+	 * generates HTML for the Edit Registration side meta box
2476
+	 *
2477
+	 * @return void
2478
+	 * @throws DomainException
2479
+	 * @throws EE_Error
2480
+	 * @throws InvalidArgumentException
2481
+	 * @throws InvalidDataTypeException
2482
+	 * @throws InvalidInterfaceException
2483
+	 * @throws ReflectionException
2484
+	 */
2485
+	public function _reg_registrant_side_meta_box()
2486
+	{
2487
+		/*@var $attendee EE_Attendee */
2488
+		$att_check = $this->_registration->attendee();
2489
+		$attendee  = $att_check instanceof EE_Attendee
2490
+			? $att_check
2491
+			: $this->getAttendeeModel()->create_default_object();
2492
+		// now let's determine if this is not the primary registration.  If it isn't then we set the
2493
+		// primary_registration object for reference BUT ONLY if the Attendee object loaded is not the same as the
2494
+		// primary registration object (that way we know if we need to show create button or not)
2495
+		if (! $this->_registration->is_primary_registrant()) {
2496
+			$primary_registration = $this->_registration->get_primary_registration();
2497
+			$primary_attendee     = $primary_registration instanceof EE_Registration ? $primary_registration->attendee()
2498
+				: null;
2499
+			if (! $primary_attendee instanceof EE_Attendee || $attendee->ID() !== $primary_attendee->ID()) {
2500
+				// in here?  This means the displayed registration is not the primary registrant but ALREADY HAS its own
2501
+				// custom attendee object so let's not worry about the primary reg.
2502
+				$primary_registration = null;
2503
+			}
2504
+		} else {
2505
+			$primary_registration = null;
2506
+		}
2507
+		$this->_template_args['ATT_ID']            = $attendee->ID();
2508
+		$this->_template_args['fname']             = $attendee->fname();
2509
+		$this->_template_args['lname']             = $attendee->lname();
2510
+		$this->_template_args['email']             = $attendee->email();
2511
+		$this->_template_args['phone']             = $attendee->phone();
2512
+		$this->_template_args['formatted_address'] = EEH_Address::format($attendee);
2513
+		// edit link
2514
+		$this->_template_args['att_edit_link']  = EE_Admin_Page::add_query_args_and_nonce(
2515
+			[
2516
+				'action' => 'edit_attendee',
2517
+				'post'   => $attendee->ID(),
2518
+			],
2519
+			REG_ADMIN_URL
2520
+		);
2521
+		$this->_template_args['att_edit_title'] = esc_html__('View details for this contact.', 'event_espresso');
2522
+		$this->_template_args['att_edit_label'] = esc_html__('View/Edit Contact', 'event_espresso');
2523
+		// create link
2524
+		$this->_template_args['create_link']  = $primary_registration instanceof EE_Registration
2525
+			? EE_Admin_Page::add_query_args_and_nonce(
2526
+				[
2527
+					'action'  => 'duplicate_attendee',
2528
+					'_REG_ID' => $this->_registration->ID(),
2529
+				],
2530
+				REG_ADMIN_URL
2531
+			) : '';
2532
+		$this->_template_args['create_label'] = esc_html__('Create Contact', 'event_espresso');
2533
+		$this->_template_args['att_check'] = $att_check;
2534
+		$template_path = REG_TEMPLATE_PATH . 'reg_admin_details_side_meta_box_registrant.template.php';
2535
+		EEH_Template::display_template($template_path, $this->_template_args);
2536
+	}
2537
+
2538
+
2539
+	/**
2540
+	 * trash or restore registrations
2541
+	 *
2542
+	 * @param boolean $trash whether to archive or restore
2543
+	 * @return void
2544
+	 * @throws EE_Error
2545
+	 * @throws InvalidArgumentException
2546
+	 * @throws InvalidDataTypeException
2547
+	 * @throws InvalidInterfaceException
2548
+	 * @throws RuntimeException
2549
+	 */
2550
+	protected function _trash_or_restore_registrations($trash = true)
2551
+	{
2552
+		// if empty _REG_ID then get out because there's nothing to do
2553
+		$REG_IDs = $this->request->getRequestParam('_REG_ID', [], 'int', true);
2554
+		if (empty($REG_IDs)) {
2555
+			EE_Error::add_error(
2556
+				sprintf(
2557
+					esc_html__(
2558
+						'In order to %1$s registrations you must select which ones you wish to %1$s by clicking the checkboxes.',
2559
+						'event_espresso'
2560
+					),
2561
+					$trash ? 'trash' : 'restore'
2562
+				),
2563
+				__FILE__,
2564
+				__LINE__,
2565
+				__FUNCTION__
2566
+			);
2567
+			$this->_redirect_after_action(false, '', '', [], true);
2568
+		}
2569
+		$success        = 0;
2570
+		$overwrite_msgs = false;
2571
+		// Checkboxes
2572
+		$reg_count = count($REG_IDs);
2573
+		// cycle thru checkboxes
2574
+		foreach ($REG_IDs as $REG_ID) {
2575
+			/** @var EE_Registration $REG */
2576
+			$REG      = $this->getRegistrationModel()->get_one_by_ID($REG_ID);
2577
+			$payments = $REG->registration_payments();
2578
+			if (! empty($payments)) {
2579
+				$name           = $REG->attendee() instanceof EE_Attendee
2580
+					? $REG->attendee()->full_name()
2581
+					: esc_html__('Unknown Attendee', 'event_espresso');
2582
+				$overwrite_msgs = true;
2583
+				EE_Error::add_error(
2584
+					sprintf(
2585
+						esc_html__(
2586
+							'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.',
2587
+							'event_espresso'
2588
+						),
2589
+						$name
2590
+					),
2591
+					__FILE__,
2592
+					__FUNCTION__,
2593
+					__LINE__
2594
+				);
2595
+				// can't trash this registration because it has payments.
2596
+				continue;
2597
+			}
2598
+			$updated = $trash ? $REG->delete() : $REG->restore();
2599
+			if ($updated) {
2600
+				$success++;
2601
+			}
2602
+		}
2603
+		$this->_redirect_after_action(
2604
+			$success === $reg_count, // were ALL registrations affected?
2605
+			$success > 1
2606
+				? esc_html__('Registrations', 'event_espresso')
2607
+				: esc_html__('Registration', 'event_espresso'),
2608
+			$trash
2609
+				? esc_html__('moved to the trash', 'event_espresso')
2610
+				: esc_html__('restored', 'event_espresso'),
2611
+			$this->mergeExistingRequestParamsWithRedirectArgs(['action' => 'default']),
2612
+			$overwrite_msgs
2613
+		);
2614
+	}
2615
+
2616
+
2617
+	/**
2618
+	 * This is used to permanently delete registrations.  Note, this will handle not only deleting permanently the
2619
+	 * registration but also.
2620
+	 * 1. Removing relations to EE_Attendee
2621
+	 * 2. Deleting permanently the related transaction, but ONLY if all related registrations to the transaction are
2622
+	 * ALSO trashed.
2623
+	 * 3. Deleting permanently any related Line items but only if the above conditions are met.
2624
+	 * 4. Removing relationships between all tickets and the related registrations
2625
+	 * 5. Deleting permanently any related Answers (and the answers for other related registrations that were deleted.)
2626
+	 * 6. Deleting permanently any related Checkins.
2627
+	 *
2628
+	 * @return void
2629
+	 * @throws EE_Error
2630
+	 * @throws InvalidArgumentException
2631
+	 * @throws InvalidDataTypeException
2632
+	 * @throws InvalidInterfaceException
2633
+	 * @throws ReflectionException
2634
+	 */
2635
+	protected function _delete_registrations()
2636
+	{
2637
+		$REG_MDL = $this->getRegistrationModel();
2638
+		$success = 0;
2639
+		// Checkboxes
2640
+		$REG_IDs = $this->request->getRequestParam('_REG_ID', [], 'int', true);
2641
+
2642
+		if (! empty($REG_IDs)) {
2643
+			// if array has more than one element than success message should be plural
2644
+			$success = count($REG_IDs) > 1 ? 2 : 1;
2645
+			// cycle thru checkboxes
2646
+			foreach ($REG_IDs as $REG_ID) {
2647
+				$REG = $REG_MDL->get_one_by_ID($REG_ID);
2648
+				if (! $REG instanceof EE_Registration) {
2649
+					continue;
2650
+				}
2651
+				$deleted = $this->_delete_registration($REG);
2652
+				if (! $deleted) {
2653
+					$success = 0;
2654
+				}
2655
+			}
2656
+		}
2657
+
2658
+		$what        = $success > 1
2659
+			? esc_html__('Registrations', 'event_espresso')
2660
+			: esc_html__('Registration', 'event_espresso');
2661
+		$action_desc = esc_html__('permanently deleted.', 'event_espresso');
2662
+		$this->_redirect_after_action(
2663
+			$success,
2664
+			$what,
2665
+			$action_desc,
2666
+			$this->mergeExistingRequestParamsWithRedirectArgs(['action' => 'default']),
2667
+			true
2668
+		);
2669
+	}
2670
+
2671
+
2672
+	/**
2673
+	 * handles the permanent deletion of a registration.  See comments with _delete_registrations() for details on what
2674
+	 * models get affected.
2675
+	 *
2676
+	 * @param EE_Registration $REG registration to be deleted permanently
2677
+	 * @return bool true = successful deletion, false = fail.
2678
+	 * @throws EE_Error
2679
+	 * @throws InvalidArgumentException
2680
+	 * @throws InvalidDataTypeException
2681
+	 * @throws InvalidInterfaceException
2682
+	 * @throws ReflectionException
2683
+	 */
2684
+	protected function _delete_registration(EE_Registration $REG)
2685
+	{
2686
+		// first we start with the transaction... ultimately, we WILL not delete permanently if there are any related
2687
+		// registrations on the transaction that are NOT trashed.
2688
+		$TXN = $REG->get_first_related('Transaction');
2689
+		if (! $TXN instanceof EE_Transaction) {
2690
+			EE_Error::add_error(
2691
+				sprintf(
2692
+					esc_html__(
2693
+						'Unable to permanently delete registration %d because its related transaction has already been deleted. If you can restore the related transaction to the database then this registration can be deleted.',
2694
+						'event_espresso'
2695
+					),
2696
+					$REG->id()
2697
+				),
2698
+				__FILE__,
2699
+				__FUNCTION__,
2700
+				__LINE__
2701
+			);
2702
+			return false;
2703
+		}
2704
+		$REGS        = $TXN->get_many_related('Registration');
2705
+		$all_trashed = true;
2706
+		foreach ($REGS as $registration) {
2707
+			if (! $registration->get('REG_deleted')) {
2708
+				$all_trashed = false;
2709
+			}
2710
+		}
2711
+		if (! $all_trashed) {
2712
+			EE_Error::add_error(
2713
+				esc_html__(
2714
+					'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.',
2715
+					'event_espresso'
2716
+				),
2717
+				__FILE__,
2718
+				__FUNCTION__,
2719
+				__LINE__
2720
+			);
2721
+			return false;
2722
+		}
2723
+		// k made it here so that means we can delete all the related transactions and their answers (but let's do them
2724
+		// separately from THIS one).
2725
+		foreach ($REGS as $registration) {
2726
+			// delete related answers
2727
+			$registration->delete_related_permanently('Answer');
2728
+			// remove relationship to EE_Attendee (but we ALWAYS leave the contact record intact)
2729
+			$attendee = $registration->get_first_related('Attendee');
2730
+			if ($attendee instanceof EE_Attendee) {
2731
+				$registration->_remove_relation_to($attendee, 'Attendee');
2732
+			}
2733
+			// now remove relationships to tickets on this registration.
2734
+			$registration->_remove_relations('Ticket');
2735
+			// now delete permanently the checkins related to this registration.
2736
+			$registration->delete_related_permanently('Checkin');
2737
+			if ($registration->ID() === $REG->ID()) {
2738
+				continue;
2739
+			} //we don't want to delete permanently the existing registration just yet.
2740
+			// remove relation to transaction for these registrations if NOT the existing registrations
2741
+			$registration->_remove_relations('Transaction');
2742
+			// delete permanently any related messages.
2743
+			$registration->delete_related_permanently('Message');
2744
+			// now delete this registration permanently
2745
+			$registration->delete_permanently();
2746
+		}
2747
+		// now all related registrations on the transaction are handled.  So let's just handle this registration itself
2748
+		// (the transaction and line items should be all that's left).
2749
+		// delete the line items related to the transaction for this registration.
2750
+		$TXN->delete_related_permanently('Line_Item');
2751
+		// we need to remove all the relationships on the transaction
2752
+		$TXN->delete_related_permanently('Payment');
2753
+		$TXN->delete_related_permanently('Extra_Meta');
2754
+		$TXN->delete_related_permanently('Message');
2755
+		// now we can delete this REG permanently (and the transaction of course)
2756
+		$REG->delete_related_permanently('Transaction');
2757
+		return $REG->delete_permanently();
2758
+	}
2759
+
2760
+
2761
+	/**
2762
+	 *    generates HTML for the Register New Attendee Admin page
2763
+	 *
2764
+	 * @throws DomainException
2765
+	 * @throws EE_Error
2766
+	 * @throws InvalidArgumentException
2767
+	 * @throws InvalidDataTypeException
2768
+	 * @throws InvalidInterfaceException
2769
+	 * @throws ReflectionException
2770
+	 */
2771
+	public function new_registration()
2772
+	{
2773
+		if (! $this->_set_reg_event()) {
2774
+			throw new EE_Error(
2775
+				esc_html__(
2776
+					'Unable to continue with registering because there is no Event ID in the request',
2777
+					'event_espresso'
2778
+				)
2779
+			);
2780
+		}
2781
+		/** @var CurrentPage $current_page */
2782
+		$current_page = $this->loader->getShared(CurrentPage::class);
2783
+		$current_page->setEspressoPage(true);
2784
+		// gotta start with a clean slate if we're not coming here via ajax
2785
+		if (
2786
+			! $this->request->isAjax()
2787
+			&& (
2788
+				! $this->request->requestParamIsSet('processing_registration')
2789
+				|| $this->request->requestParamIsSet('step_error')
2790
+			)
2791
+		) {
2792
+			EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
2793
+		}
2794
+		$this->_template_args['event_name'] = '';
2795
+		// event name
2796
+		if ($this->_reg_event) {
2797
+			$this->_template_args['event_name'] = $this->_reg_event->name();
2798
+			$edit_event_url                     = self::add_query_args_and_nonce(
2799
+				[
2800
+					'action' => 'edit',
2801
+					'post'   => $this->_reg_event->ID(),
2802
+				],
2803
+				EVENTS_ADMIN_URL
2804
+			);
2805
+			$edit_event_lnk                     = '<a href="'
2806
+												  . $edit_event_url
2807
+												  . '" title="'
2808
+												  . esc_attr__('Edit ', 'event_espresso')
2809
+												  . $this->_reg_event->name()
2810
+												  . '">'
2811
+												  . esc_html__('Edit Event', 'event_espresso')
2812
+												  . '</a>';
2813
+			$this->_template_args['event_name'] .= ' <span class="admin-page-header-edit-lnk not-bold">'
2814
+												   . $edit_event_lnk
2815
+												   . '</span>';
2816
+		}
2817
+		$this->_template_args['step_content'] = $this->_get_registration_step_content();
2818
+		if ($this->request->isAjax()) {
2819
+			$this->_return_json();
2820
+		}
2821
+		// grab header
2822
+		$template_path = REG_TEMPLATE_PATH . 'reg_admin_register_new_attendee.template.php';
2823
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
2824
+			$template_path,
2825
+			$this->_template_args,
2826
+			true
2827
+		);
2828
+		// $this->_set_publish_post_box_vars( NULL, FALSE, FALSE, NULL, FALSE );
2829
+		// the details template wrapper
2830
+		$this->display_admin_page_with_sidebar();
2831
+	}
2832
+
2833
+
2834
+	/**
2835
+	 * This returns the content for a registration step
2836
+	 *
2837
+	 * @return string html
2838
+	 * @throws DomainException
2839
+	 * @throws EE_Error
2840
+	 * @throws InvalidArgumentException
2841
+	 * @throws InvalidDataTypeException
2842
+	 * @throws InvalidInterfaceException
2843
+	 * @throws ReflectionException
2844
+	 */
2845
+	protected function _get_registration_step_content()
2846
+	{
2847
+		if (isset($_COOKIE['ee_registration_added']) && $_COOKIE['ee_registration_added']) {
2848
+			$warning_msg = sprintf(
2849
+				esc_html__(
2850
+					'%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',
2851
+					'event_espresso'
2852
+				),
2853
+				'<br />',
2854
+				'<h3 class="important-notice">',
2855
+				'</h3>',
2856
+				'<div class="float-right">',
2857
+				'<span id="redirect_timer" class="important-notice">30</span>',
2858
+				'</div>',
2859
+				'<b>',
2860
+				'</b>'
2861
+			);
2862
+			return '
2863 2863
 	<div id="ee-add-reg-back-button-dv"><p>' . $warning_msg . '</p></div>
2864 2864
 	<script >
2865 2865
 		// WHOAH !!! it appears that someone is using the back button from the Transaction admin page
@@ -2872,840 +2872,840 @@  discard block
 block discarded – undo
2872 2872
 	        }
2873 2873
 	    }, 800 );
2874 2874
 	</script >';
2875
-        }
2876
-        $template_args = [
2877
-            'title'                    => '',
2878
-            'content'                  => '',
2879
-            'step_button_text'         => '',
2880
-            'show_notification_toggle' => false,
2881
-        ];
2882
-        // to indicate we're processing a new registration
2883
-        $hidden_fields = [
2884
-            'processing_registration' => [
2885
-                'type'  => 'hidden',
2886
-                'value' => 0,
2887
-            ],
2888
-            'event_id'                => [
2889
-                'type'  => 'hidden',
2890
-                'value' => $this->_reg_event->ID(),
2891
-            ],
2892
-        ];
2893
-        // if the cart is empty then we know we're at step one, so we'll display the ticket selector
2894
-        $cart = EE_Registry::instance()->SSN->cart();
2895
-        $step = ! $cart instanceof EE_Cart ? 'ticket' : 'questions';
2896
-        switch ($step) {
2897
-            case 'ticket':
2898
-                $hidden_fields['processing_registration']['value'] = 1;
2899
-                $template_args['title']                            = esc_html__(
2900
-                    'Step One: Select the Ticket for this registration',
2901
-                    'event_espresso'
2902
-                );
2903
-                $template_args['content'] = EED_Ticket_Selector::instance()->display_ticket_selector($this->_reg_event);
2904
-                $template_args['content'] .= '</div>';
2905
-                $template_args['step_button_text'] = esc_html__(
2906
-                    'Add Tickets and Continue to Registrant Details',
2907
-                    'event_espresso'
2908
-                );
2909
-                $template_args['show_notification_toggle']         = false;
2910
-                break;
2911
-            case 'questions':
2912
-                $hidden_fields['processing_registration']['value'] = 2;
2913
-                $template_args['title']                            = esc_html__(
2914
-                    'Step Two: Add Registrant Details for this Registration',
2915
-                    'event_espresso'
2916
-                );
2917
-                // in theory, we should be able to run EED_SPCO at this point
2918
-                // because the cart should have been set up properly by the first process_reg_step run.
2919
-                $template_args['content'] = EED_Single_Page_Checkout::registration_checkout_for_admin();
2920
-                $template_args['step_button_text'] = esc_html__(
2921
-                    'Save Registration and Continue to Details',
2922
-                    'event_espresso'
2923
-                );
2924
-                $template_args['show_notification_toggle'] = true;
2925
-                break;
2926
-        }
2927
-        // we come back to the process_registration_step route.
2928
-        $this->_set_add_edit_form_tags('process_reg_step', $hidden_fields);
2929
-        return EEH_Template::display_template(
2930
-            REG_TEMPLATE_PATH . 'reg_admin_register_new_attendee_step_content.template.php',
2931
-            $template_args,
2932
-            true
2933
-        );
2934
-    }
2935
-
2936
-
2937
-    /**
2938
-     * set_reg_event
2939
-     *
2940
-     * @return bool
2941
-     * @throws EE_Error
2942
-     * @throws InvalidArgumentException
2943
-     * @throws InvalidDataTypeException
2944
-     * @throws InvalidInterfaceException
2945
-     */
2946
-    private function _set_reg_event()
2947
-    {
2948
-        if (is_object($this->_reg_event)) {
2949
-            return true;
2950
-        }
2951
-
2952
-        $EVT_ID = $this->request->getRequestParam('event_id', 0, 'int');
2953
-        if (! $EVT_ID) {
2954
-            return false;
2955
-        }
2956
-        $this->_reg_event = $this->getEventModel()->get_one_by_ID($EVT_ID);
2957
-        return true;
2958
-    }
2959
-
2960
-
2961
-    /**
2962
-     * process_reg_step
2963
-     *
2964
-     * @return void
2965
-     * @throws DomainException
2966
-     * @throws EE_Error
2967
-     * @throws InvalidArgumentException
2968
-     * @throws InvalidDataTypeException
2969
-     * @throws InvalidInterfaceException
2970
-     * @throws ReflectionException
2971
-     * @throws RuntimeException
2972
-     */
2973
-    public function process_reg_step()
2974
-    {
2975
-        EE_System::do_not_cache();
2976
-        $this->_set_reg_event();
2977
-        /** @var CurrentPage $current_page */
2978
-        $current_page = $this->loader->getShared(CurrentPage::class);
2979
-        $current_page->setEspressoPage(true);
2980
-        $this->request->setRequestParam('uts', time());
2981
-        // what step are we on?
2982
-        $cart = EE_Registry::instance()->SSN->cart();
2983
-        $step = ! $cart instanceof EE_Cart ? 'ticket' : 'questions';
2984
-        // if doing ajax then we need to verify the nonce
2985
-        if ($this->request->isAjax()) {
2986
-            $nonce = $this->request->getRequestParam($this->_req_nonce, '');
2987
-            $this->_verify_nonce($nonce, $this->_req_nonce);
2988
-        }
2989
-        switch ($step) {
2990
-            case 'ticket':
2991
-                // process ticket selection
2992
-                $success = EED_Ticket_Selector::instance()->process_ticket_selections();
2993
-                if ($success) {
2994
-                    EE_Error::add_success(
2995
-                        esc_html__(
2996
-                            'Tickets Selected. Now complete the registration.',
2997
-                            'event_espresso'
2998
-                        )
2999
-                    );
3000
-                } else {
3001
-                    $this->request->setRequestParam('step_error', true);
3002
-                    $query_args['step_error'] = $this->request->getRequestParam('step_error', true, 'bool');
3003
-                }
3004
-                if ($this->request->isAjax()) {
3005
-                    $this->new_registration(); // display next step
3006
-                } else {
3007
-                    $query_args = [
3008
-                        'action'                  => 'new_registration',
3009
-                        'processing_registration' => 1,
3010
-                        'event_id'                => $this->_reg_event->ID(),
3011
-                        'uts'                     => time(),
3012
-                    ];
3013
-                    $this->_redirect_after_action(
3014
-                        false,
3015
-                        '',
3016
-                        '',
3017
-                        $query_args,
3018
-                        true
3019
-                    );
3020
-                }
3021
-                break;
3022
-            case 'questions':
3023
-                if (! $this->request->requestParamIsSet('txn_reg_status_change[send_notifications]')) {
3024
-                    add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_false', 15);
3025
-                }
3026
-                // process registration
3027
-                $transaction = EED_Single_Page_Checkout::instance()->process_registration_from_admin();
3028
-                if ($cart instanceof EE_Cart) {
3029
-                    $grand_total = $cart->get_grand_total();
3030
-                    if ($grand_total instanceof EE_Line_Item) {
3031
-                        $grand_total->save_this_and_descendants_to_txn();
3032
-                    }
3033
-                }
3034
-                if (! $transaction instanceof EE_Transaction) {
3035
-                    $query_args = [
3036
-                        'action'                  => 'new_registration',
3037
-                        'processing_registration' => 2,
3038
-                        'event_id'                => $this->_reg_event->ID(),
3039
-                        'uts'                     => time(),
3040
-                    ];
3041
-                    if ($this->request->isAjax()) {
3042
-                        // display registration form again because there are errors (maybe validation?)
3043
-                        $this->new_registration();
3044
-                        return;
3045
-                    }
3046
-                    $this->_redirect_after_action(
3047
-                        false,
3048
-                        '',
3049
-                        '',
3050
-                        $query_args,
3051
-                        true
3052
-                    );
3053
-                    return;
3054
-                }
3055
-                // maybe update status, and make sure to save transaction if not done already
3056
-                if (! $transaction->update_status_based_on_total_paid()) {
3057
-                    $transaction->save();
3058
-                }
3059
-                EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
3060
-                $query_args = [
3061
-                    'action'        => 'redirect_to_txn',
3062
-                    'TXN_ID'        => $transaction->ID(),
3063
-                    'EVT_ID'        => $this->_reg_event->ID(),
3064
-                    'event_name'    => urlencode($this->_reg_event->name()),
3065
-                    'redirect_from' => 'new_registration',
3066
-                ];
3067
-                $this->_redirect_after_action(false, '', '', $query_args, true);
3068
-                break;
3069
-        }
3070
-        // what are you looking here for?  Should be nothing to do at this point.
3071
-    }
3072
-
3073
-
3074
-    /**
3075
-     * redirect_to_txn
3076
-     *
3077
-     * @return void
3078
-     * @throws EE_Error
3079
-     * @throws InvalidArgumentException
3080
-     * @throws InvalidDataTypeException
3081
-     * @throws InvalidInterfaceException
3082
-     * @throws ReflectionException
3083
-     */
3084
-    public function redirect_to_txn()
3085
-    {
3086
-        EE_System::do_not_cache();
3087
-        EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
3088
-        $query_args = [
3089
-            'action' => 'view_transaction',
3090
-            'TXN_ID' => $this->request->getRequestParam('TXN_ID', 0, 'int'),
3091
-            'page'   => 'espresso_transactions',
3092
-        ];
3093
-        if ($this->request->requestParamIsSet('EVT_ID') && $this->request->requestParamIsSet('redirect_from')) {
3094
-            $query_args['EVT_ID']        = $this->request->getRequestParam('EVT_ID', 0, 'int');
3095
-            $query_args['event_name']    = urlencode($this->request->getRequestParam('event_name'));
3096
-            $query_args['redirect_from'] = $this->request->getRequestParam('redirect_from');
3097
-        }
3098
-        EE_Error::add_success(
3099
-            esc_html__(
3100
-                'Registration Created.  Please review the transaction and add any payments as necessary',
3101
-                'event_espresso'
3102
-            )
3103
-        );
3104
-        $this->_redirect_after_action(false, '', '', $query_args, true);
3105
-    }
3106
-
3107
-
3108
-    /**
3109
-     * generates HTML for the Attendee Contact List
3110
-     *
3111
-     * @return void
3112
-     * @throws DomainException
3113
-     * @throws EE_Error
3114
-     */
3115
-    protected function _attendee_contact_list_table()
3116
-    {
3117
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3118
-        $this->_search_btn_label = esc_html__('Contacts', 'event_espresso');
3119
-        $this->display_admin_list_table_page_with_no_sidebar();
3120
-    }
3121
-
3122
-
3123
-    /**
3124
-     * get_attendees
3125
-     *
3126
-     * @param      $per_page
3127
-     * @param bool $count whether to return count or data.
3128
-     * @param bool $trash
3129
-     * @return array|int
3130
-     * @throws EE_Error
3131
-     * @throws InvalidArgumentException
3132
-     * @throws InvalidDataTypeException
3133
-     * @throws InvalidInterfaceException
3134
-     */
3135
-    public function get_attendees($per_page, $count = false, $trash = false)
3136
-    {
3137
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3138
-        require_once(REG_ADMIN . 'EE_Attendee_Contact_List_Table.class.php');
3139
-        $orderby = $this->request->getRequestParam('orderby');
3140
-        switch ($orderby) {
3141
-            case 'ATT_ID':
3142
-            case 'ATT_fname':
3143
-            case 'ATT_email':
3144
-            case 'ATT_city':
3145
-            case 'STA_ID':
3146
-            case 'CNT_ID':
3147
-                break;
3148
-            case 'Registration_Count':
3149
-                $orderby = 'Registration_Count';
3150
-                break;
3151
-            default:
3152
-                $orderby = 'ATT_lname';
3153
-        }
3154
-        $sort         = $this->request->getRequestParam('order', 'ASC');
3155
-        $current_page = $this->request->getRequestParam('paged', 1, 'int');
3156
-        $per_page     = absint($per_page) ? $per_page : 10;
3157
-        $per_page     = $this->request->getRequestParam('perpage', $per_page, 'int');
3158
-        $_where       = [];
3159
-        $search_term  = $this->request->getRequestParam('s');
3160
-        if ($search_term) {
3161
-            $search_term  = '%' . $search_term . '%';
3162
-            $_where['OR'] = [
3163
-                'Registration.Event.EVT_name'       => ['LIKE', $search_term],
3164
-                'Registration.Event.EVT_desc'       => ['LIKE', $search_term],
3165
-                'Registration.Event.EVT_short_desc' => ['LIKE', $search_term],
3166
-                'ATT_fname'                         => ['LIKE', $search_term],
3167
-                'ATT_lname'                         => ['LIKE', $search_term],
3168
-                'ATT_short_bio'                     => ['LIKE', $search_term],
3169
-                'ATT_email'                         => ['LIKE', $search_term],
3170
-                'ATT_address'                       => ['LIKE', $search_term],
3171
-                'ATT_address2'                      => ['LIKE', $search_term],
3172
-                'ATT_city'                          => ['LIKE', $search_term],
3173
-                'Country.CNT_name'                  => ['LIKE', $search_term],
3174
-                'State.STA_name'                    => ['LIKE', $search_term],
3175
-                'ATT_phone'                         => ['LIKE', $search_term],
3176
-                'Registration.REG_final_price'      => ['LIKE', $search_term],
3177
-                'Registration.REG_code'             => ['LIKE', $search_term],
3178
-                'Registration.REG_group_size'       => ['LIKE', $search_term],
3179
-            ];
3180
-        }
3181
-        $offset     = ($current_page - 1) * $per_page;
3182
-        $limit      = $count ? null : [$offset, $per_page];
3183
-        $query_args = [
3184
-            $_where,
3185
-            'extra_selects' => ['Registration_Count' => ['Registration.REG_ID', 'count', '%d']],
3186
-            'limit'         => $limit,
3187
-        ];
3188
-        if (! $count) {
3189
-            $query_args['order_by'] = [$orderby => $sort];
3190
-        }
3191
-        $query_args[0]['status'] = $trash ? ['!=', 'publish'] : ['IN', ['publish']];
3192
-        return $count
3193
-            ? $this->getAttendeeModel()->count($query_args, 'ATT_ID', true)
3194
-            : $this->getAttendeeModel()->get_all($query_args);
3195
-    }
3196
-
3197
-
3198
-    /**
3199
-     * This is just taking care of resending the registration confirmation
3200
-     *
3201
-     * @return void
3202
-     * @throws EE_Error
3203
-     * @throws InvalidArgumentException
3204
-     * @throws InvalidDataTypeException
3205
-     * @throws InvalidInterfaceException
3206
-     * @throws ReflectionException
3207
-     */
3208
-    protected function _resend_registration()
3209
-    {
3210
-        $this->_process_resend_registration();
3211
-        $REG_ID      = $this->request->getRequestParam('_REG_ID', 0, 'int');
3212
-        $redirect_to = $this->request->getRequestParam('redirect_to');
3213
-        $query_args  = $redirect_to
3214
-            ? ['action' => $redirect_to, '_REG_ID' => $REG_ID]
3215
-            : ['action' => 'default'];
3216
-        $this->_redirect_after_action(false, '', '', $query_args, true);
3217
-    }
3218
-
3219
-
3220
-    /**
3221
-     * Creates a registration report, but accepts the name of a method to use for preparing the query parameters
3222
-     * to use when selecting registrations
3223
-     *
3224
-     * @param string $method_name_for_getting_query_params the name of the method (on this class) to use for preparing
3225
-     *                                                     the query parameters from the request
3226
-     * @return void ends the request with a redirect or download
3227
-     */
3228
-    public function _registrations_report_base($method_name_for_getting_query_params)
3229
-    {
3230
-        $EVT_ID = $this->request->requestParamIsSet('EVT_ID')
3231
-            ? $this->request->getRequestParam('EVT_ID', 0, DataType::INT)
3232
-            : null;
3233
-        if (! defined('EE_USE_OLD_CSV_REPORT_CLASS')) {
3234
-            $return_url = $this->request->getRequestParam('return_url', '', DataType::URL);
3235
-            $filters = $this->request->getRequestParam('filters', [], DataType::STRING, true);
3236
-            $use_filters = $this->request->getRequestParam('use_filters', false, DataType::BOOL);
3237
-            wp_redirect(
3238
-                EE_Admin_Page::add_query_args_and_nonce(
3239
-                    [
3240
-                        'page'        => EED_Batch::PAGE_SLUG,
3241
-                        'batch'       => EED_Batch::batch_file_job,
3242
-                        'EVT_ID'      => $EVT_ID,
3243
-                        'filters'     => urlencode(serialize($this->$method_name_for_getting_query_params($filters))),
3244
-                        'use_filters' => urlencode($use_filters),
3245
-                        'job_handler' => urlencode('EventEspressoBatchRequest\JobHandlers\RegistrationsReport'),
3246
-                        'return_url'  => urlencode($return_url),
3247
-                    ]
3248
-                )
3249
-            );
3250
-        } else {
3251
-            // Pull the current request params
3252
-            $request_args = $this->request->requestParams();
3253
-            // Set the required request_args to be passed to the export
3254
-            $required_request_args = [
3255
-                'export' => 'report',
3256
-                'action' => 'registrations_report_for_event',
3257
-                'EVT_ID' => $EVT_ID,
3258
-            ];
3259
-            // Merge required request args, overriding any currently set
3260
-            $request_args = array_merge($request_args, $required_request_args);
3261
-            if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3262
-                require_once(EE_CLASSES . 'EE_Export.class.php');
3263
-                $EE_Export = EE_Export::instance($request_args);
3264
-                $EE_Export->export();
3265
-            }
3266
-        }
3267
-    }
3268
-
3269
-
3270
-    /**
3271
-     * Creates a registration report using only query parameters in the request
3272
-     *
3273
-     * @return void
3274
-     */
3275
-    public function _registrations_report()
3276
-    {
3277
-        $this->_registrations_report_base('_get_registration_query_parameters');
3278
-    }
3279
-
3280
-
3281
-    public function _contact_list_export()
3282
-    {
3283
-        if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3284
-            require_once(EE_CLASSES . 'EE_Export.class.php');
3285
-            $EE_Export = EE_Export::instance($this->request->requestParams());
3286
-            $EE_Export->export_attendees();
3287
-        }
3288
-    }
3289
-
3290
-
3291
-    public function _contact_list_report()
3292
-    {
3293
-        if (! defined('EE_USE_OLD_CSV_REPORT_CLASS')) {
3294
-            wp_redirect(
3295
-                EE_Admin_Page::add_query_args_and_nonce(
3296
-                    [
3297
-                        'page'        => EED_Batch::PAGE_SLUG,
3298
-                        'batch'       => EED_Batch::batch_file_job,
3299
-                        'job_handler' => urlencode('EventEspressoBatchRequest\JobHandlers\AttendeesReport'),
3300
-                        'return_url'  => urlencode($this->request->getRequestParam('return_url', '', DataType::URL)),
3301
-                    ]
3302
-                )
3303
-            );
3304
-        } else {
3305
-            if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3306
-                require_once(EE_CLASSES . 'EE_Export.class.php');
3307
-                $EE_Export = EE_Export::instance($this->request->requestParams());
3308
-                $EE_Export->report_attendees();
3309
-            }
3310
-        }
3311
-    }
3312
-
3313
-
3314
-
3315
-
3316
-
3317
-    /***************************************        ATTENDEE DETAILS        ***************************************/
3318
-    /**
3319
-     * This duplicates the attendee object for the given incoming registration id and attendee_id.
3320
-     *
3321
-     * @return void
3322
-     * @throws EE_Error
3323
-     * @throws InvalidArgumentException
3324
-     * @throws InvalidDataTypeException
3325
-     * @throws InvalidInterfaceException
3326
-     * @throws ReflectionException
3327
-     */
3328
-    protected function _duplicate_attendee()
3329
-    {
3330
-        $REG_ID = $this->request->getRequestParam('_REG_ID', 0, 'int');
3331
-        $action = $this->request->getRequestParam('return', 'default');
3332
-        // verify we have necessary info
3333
-        if (! $REG_ID) {
3334
-            EE_Error::add_error(
3335
-                esc_html__(
3336
-                    'Unable to create the contact for the registration because the required parameters are not present (_REG_ID )',
3337
-                    'event_espresso'
3338
-                ),
3339
-                __FILE__,
3340
-                __LINE__,
3341
-                __FUNCTION__
3342
-            );
3343
-            $query_args = ['action' => $action];
3344
-            $this->_redirect_after_action('', '', '', $query_args, true);
3345
-        }
3346
-        // okay necessary deets present... let's dupe the incoming attendee and attach to incoming registration.
3347
-        $registration = $this->getRegistrationModel()->get_one_by_ID($REG_ID);
3348
-        if (! $registration instanceof EE_Registration) {
3349
-            throw new RuntimeException(
3350
-                sprintf(
3351
-                    esc_html__(
3352
-                        'Unable to create the contact because a valid registration could not be retrieved for REG ID: %1$d',
3353
-                        'event_espresso'
3354
-                    ),
3355
-                    $REG_ID
3356
-                )
3357
-            );
3358
-        }
3359
-        $attendee = $registration->attendee();
3360
-        // remove relation of existing attendee on registration
3361
-        $registration->_remove_relation_to($attendee, 'Attendee');
3362
-        // new attendee
3363
-        $new_attendee = clone $attendee;
3364
-        $new_attendee->set('ATT_ID', 0);
3365
-        $new_attendee->save();
3366
-        // add new attendee to reg
3367
-        $registration->_add_relation_to($new_attendee, 'Attendee');
3368
-        EE_Error::add_success(
3369
-            esc_html__(
3370
-                'New Contact record created.  Now make any edits you wish to make for this contact.',
3371
-                'event_espresso'
3372
-            )
3373
-        );
3374
-        // redirect to edit page for attendee
3375
-        $query_args = ['post' => $new_attendee->ID(), 'action' => 'edit_attendee'];
3376
-        $this->_redirect_after_action('', '', '', $query_args, true);
3377
-    }
3378
-
3379
-
3380
-    /**
3381
-     * Callback invoked by parent EE_Admin_CPT class hooked in on `save_post` wp hook.
3382
-     *
3383
-     * @param int     $post_id
3384
-     * @param WP_Post $post
3385
-     * @throws DomainException
3386
-     * @throws EE_Error
3387
-     * @throws InvalidArgumentException
3388
-     * @throws InvalidDataTypeException
3389
-     * @throws InvalidInterfaceException
3390
-     * @throws LogicException
3391
-     * @throws InvalidFormSubmissionException
3392
-     * @throws ReflectionException
3393
-     */
3394
-    protected function _insert_update_cpt_item($post_id, $post)
3395
-    {
3396
-        $success  = true;
3397
-        $attendee = $post instanceof WP_Post && $post->post_type === 'espresso_attendees'
3398
-            ? $this->getAttendeeModel()->get_one_by_ID($post_id)
3399
-            : null;
3400
-        // for attendee updates
3401
-        if ($attendee instanceof EE_Attendee) {
3402
-            // note we should only be UPDATING attendees at this point.
3403
-            $fname          = $this->request->getRequestParam('ATT_fname', '');
3404
-            $lname          = $this->request->getRequestParam('ATT_lname', '');
3405
-            $updated_fields = [
3406
-                'ATT_fname'     => $fname,
3407
-                'ATT_lname'     => $lname,
3408
-                'ATT_full_name' => "{$fname} {$lname}",
3409
-                'ATT_address'   => $this->request->getRequestParam('ATT_address', ''),
3410
-                'ATT_address2'  => $this->request->getRequestParam('ATT_address2', ''),
3411
-                'ATT_city'      => $this->request->getRequestParam('ATT_city', ''),
3412
-                'STA_ID'        => $this->request->getRequestParam('STA_ID', ''),
3413
-                'CNT_ISO'       => $this->request->getRequestParam('CNT_ISO', ''),
3414
-                'ATT_zip'       => $this->request->getRequestParam('ATT_zip', ''),
3415
-            ];
3416
-            foreach ($updated_fields as $field => $value) {
3417
-                $attendee->set($field, $value);
3418
-            }
3419
-
3420
-            // process contact details metabox form handler (which will also save the attendee)
3421
-            $contact_details_form = $this->getAttendeeContactDetailsMetaboxFormHandler($attendee);
3422
-            $success              = $contact_details_form->process($this->request->requestParams());
3423
-
3424
-            $attendee_update_callbacks = apply_filters(
3425
-                'FHEE__Registrations_Admin_Page__insert_update_cpt_item__attendee_update',
3426
-                []
3427
-            );
3428
-            foreach ($attendee_update_callbacks as $a_callback) {
3429
-                if (false === call_user_func_array($a_callback, [$attendee, $this->request->requestParams()])) {
3430
-                    throw new EE_Error(
3431
-                        sprintf(
3432
-                            esc_html__(
3433
-                                '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.',
3434
-                                'event_espresso'
3435
-                            ),
3436
-                            $a_callback
3437
-                        )
3438
-                    );
3439
-                }
3440
-            }
3441
-        }
3442
-
3443
-        if ($success === false) {
3444
-            EE_Error::add_error(
3445
-                esc_html__(
3446
-                    'Something went wrong with updating the meta table data for the registration.',
3447
-                    'event_espresso'
3448
-                ),
3449
-                __FILE__,
3450
-                __FUNCTION__,
3451
-                __LINE__
3452
-            );
3453
-        }
3454
-    }
3455
-
3456
-
3457
-    public function trash_cpt_item($post_id)
3458
-    {
3459
-    }
3460
-
3461
-
3462
-    public function delete_cpt_item($post_id)
3463
-    {
3464
-    }
3465
-
3466
-
3467
-    public function restore_cpt_item($post_id)
3468
-    {
3469
-    }
3470
-
3471
-
3472
-    protected function _restore_cpt_item($post_id, $revision_id)
3473
-    {
3474
-    }
3475
-
3476
-
3477
-    /**
3478
-     * @throws EE_Error
3479
-     * @throws ReflectionException
3480
-     * @since 4.10.2.p
3481
-     */
3482
-    public function attendee_editor_metaboxes()
3483
-    {
3484
-        $this->verify_cpt_object();
3485
-        remove_meta_box(
3486
-            'postexcerpt',
3487
-            $this->_cpt_routes[ $this->_req_action ],
3488
-            'normal'
3489
-        );
3490
-        remove_meta_box('commentstatusdiv', $this->_cpt_routes[ $this->_req_action ], 'normal');
3491
-        if (post_type_supports('espresso_attendees', 'excerpt')) {
3492
-            $this->addMetaBox(
3493
-                'postexcerpt',
3494
-                esc_html__('Short Biography', 'event_espresso'),
3495
-                'post_excerpt_meta_box',
3496
-                $this->_cpt_routes[ $this->_req_action ]
3497
-            );
3498
-        }
3499
-        if (post_type_supports('espresso_attendees', 'comments')) {
3500
-            $this->addMetaBox(
3501
-                'commentsdiv',
3502
-                esc_html__('Notes on the Contact', 'event_espresso'),
3503
-                'post_comment_meta_box',
3504
-                $this->_cpt_routes[ $this->_req_action ],
3505
-                'normal',
3506
-                'core'
3507
-            );
3508
-        }
3509
-        $this->addMetaBox(
3510
-            'attendee_contact_info',
3511
-            esc_html__('Contact Info', 'event_espresso'),
3512
-            [$this, 'attendee_contact_info'],
3513
-            $this->_cpt_routes[ $this->_req_action ],
3514
-            'side',
3515
-            'core'
3516
-        );
3517
-        $this->addMetaBox(
3518
-            'attendee_details_address',
3519
-            esc_html__('Address Details', 'event_espresso'),
3520
-            [$this, 'attendee_address_details'],
3521
-            $this->_cpt_routes[ $this->_req_action ],
3522
-            'normal',
3523
-            'core'
3524
-        );
3525
-        $this->addMetaBox(
3526
-            'attendee_registrations',
3527
-            esc_html__('Registrations for this Contact', 'event_espresso'),
3528
-            [$this, 'attendee_registrations_meta_box'],
3529
-            $this->_cpt_routes[ $this->_req_action ]
3530
-        );
3531
-    }
3532
-
3533
-
3534
-    /**
3535
-     * Metabox for attendee contact info
3536
-     *
3537
-     * @param WP_Post $post wp post object
3538
-     * @return void attendee contact info ( and form )
3539
-     * @throws EE_Error
3540
-     * @throws InvalidArgumentException
3541
-     * @throws InvalidDataTypeException
3542
-     * @throws InvalidInterfaceException
3543
-     * @throws LogicException
3544
-     * @throws DomainException
3545
-     */
3546
-    public function attendee_contact_info($post)
3547
-    {
3548
-        // get attendee object ( should already have it )
3549
-        $form = $this->getAttendeeContactDetailsMetaboxFormHandler($this->_cpt_model_obj);
3550
-        $form->enqueueStylesAndScripts();
3551
-        echo wp_kses($form->display(), AllowedTags::getWithFormTags());
3552
-    }
3553
-
3554
-
3555
-    /**
3556
-     * Return form handler for the contact details metabox
3557
-     *
3558
-     * @param EE_Attendee $attendee
3559
-     * @return AttendeeContactDetailsMetaboxFormHandler
3560
-     * @throws DomainException
3561
-     * @throws InvalidArgumentException
3562
-     * @throws InvalidDataTypeException
3563
-     * @throws InvalidInterfaceException
3564
-     */
3565
-    protected function getAttendeeContactDetailsMetaboxFormHandler(EE_Attendee $attendee)
3566
-    {
3567
-        return new AttendeeContactDetailsMetaboxFormHandler($attendee, EE_Registry::instance());
3568
-    }
3569
-
3570
-
3571
-    /**
3572
-     * Metabox for attendee details
3573
-     *
3574
-     * @param WP_Post $post wp post object
3575
-     * @throws EE_Error
3576
-     * @throws ReflectionException
3577
-     */
3578
-    public function attendee_address_details($post)
3579
-    {
3580
-        // get attendee object (should already have it)
3581
-        $this->_template_args['attendee']     = $this->_cpt_model_obj;
3582
-        $this->_template_args['state_html']   = EEH_Form_Fields::generate_form_input(
3583
-            new EE_Question_Form_Input(
3584
-                EE_Question::new_instance(
3585
-                    [
3586
-                        'QST_ID'           => 0,
3587
-                        'QST_display_text' => esc_html__('State/Province', 'event_espresso'),
3588
-                        'QST_system'       => 'admin-state',
3589
-                    ]
3590
-                ),
3591
-                EE_Answer::new_instance(
3592
-                    [
3593
-                        'ANS_ID'    => 0,
3594
-                        'ANS_value' => $this->_cpt_model_obj->state_ID(),
3595
-                    ]
3596
-                ),
3597
-                [
3598
-                    'input_id'       => 'STA_ID',
3599
-                    'input_name'     => 'STA_ID',
3600
-                    'input_prefix'   => '',
3601
-                    'append_qstn_id' => false,
3602
-                ]
3603
-            )
3604
-        );
3605
-        $this->_template_args['country_html'] = EEH_Form_Fields::generate_form_input(
3606
-            new EE_Question_Form_Input(
3607
-                EE_Question::new_instance(
3608
-                    [
3609
-                        'QST_ID'           => 0,
3610
-                        'QST_display_text' => esc_html__('Country', 'event_espresso'),
3611
-                        'QST_system'       => 'admin-country',
3612
-                    ]
3613
-                ),
3614
-                EE_Answer::new_instance(
3615
-                    [
3616
-                        'ANS_ID'    => 0,
3617
-                        'ANS_value' => $this->_cpt_model_obj->country_ID(),
3618
-                    ]
3619
-                ),
3620
-                [
3621
-                    'input_id'       => 'CNT_ISO',
3622
-                    'input_name'     => 'CNT_ISO',
3623
-                    'input_prefix'   => '',
3624
-                    'append_qstn_id' => false,
3625
-                ]
3626
-            )
3627
-        );
3628
-        $template = REG_TEMPLATE_PATH . 'attendee_address_details_metabox_content.template.php';
3629
-        EEH_Template::display_template($template, $this->_template_args);
3630
-    }
3631
-
3632
-
3633
-    /**
3634
-     * _attendee_details
3635
-     *
3636
-     * @param $post
3637
-     * @return void
3638
-     * @throws DomainException
3639
-     * @throws EE_Error
3640
-     * @throws InvalidArgumentException
3641
-     * @throws InvalidDataTypeException
3642
-     * @throws InvalidInterfaceException
3643
-     * @throws ReflectionException
3644
-     */
3645
-    public function attendee_registrations_meta_box($post)
3646
-    {
3647
-        $this->_template_args['attendee']      = $this->_cpt_model_obj;
3648
-        $this->_template_args['registrations'] = $this->_cpt_model_obj->get_many_related('Registration');
3649
-        $template = REG_TEMPLATE_PATH . 'attendee_registrations_main_meta_box.template.php';
3650
-        EEH_Template::display_template($template, $this->_template_args);
3651
-    }
3652
-
3653
-
3654
-    /**
3655
-     * add in the form fields for the attendee edit
3656
-     *
3657
-     * @param WP_Post $post wp post object
3658
-     * @return void echos html for new form.
3659
-     * @throws DomainException
3660
-     */
3661
-    public function after_title_form_fields($post)
3662
-    {
3663
-        if ($post->post_type === 'espresso_attendees') {
3664
-            $template                  = REG_TEMPLATE_PATH . 'attendee_details_after_title_form_fields.template.php';
3665
-            $template_args['attendee'] = $this->_cpt_model_obj;
3666
-            EEH_Template::display_template($template, $template_args);
3667
-        }
3668
-    }
3669
-
3670
-
3671
-    /**
3672
-     * _trash_or_restore_attendee
3673
-     *
3674
-     * @param boolean $trash - whether to move item to trash (TRUE) or restore it (FALSE)
3675
-     * @return void
3676
-     * @throws EE_Error
3677
-     * @throws InvalidArgumentException
3678
-     * @throws InvalidDataTypeException
3679
-     * @throws InvalidInterfaceException
3680
-     */
3681
-    protected function _trash_or_restore_attendees($trash = true)
3682
-    {
3683
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3684
-        $status = $trash ? 'trash' : 'publish';
3685
-        // Checkboxes
3686
-        if ($this->request->requestParamIsSet('checkbox')) {
3687
-            $ATT_IDs = $this->request->getRequestParam('checkbox', [], 'int', true);
3688
-            // if array has more than one element than success message should be plural
3689
-            $success = count($ATT_IDs) > 1 ? 2 : 1;
3690
-            // cycle thru checkboxes
3691
-            foreach ($ATT_IDs as $ATT_ID) {
3692
-                $updated = $this->getAttendeeModel()->update_by_ID(['status' => $status], $ATT_ID);
3693
-                if (! $updated) {
3694
-                    $success = 0;
3695
-                }
3696
-            }
3697
-        } else {
3698
-            // grab single id and delete
3699
-            $ATT_ID = $this->request->getRequestParam('ATT_ID', 0, 'int');
3700
-            // update attendee
3701
-            $success = $this->getAttendeeModel()->update_by_ID(['status' => $status], $ATT_ID) ? 1 : 0;
3702
-        }
3703
-        $what        = $success > 1
3704
-            ? esc_html__('Contacts', 'event_espresso')
3705
-            : esc_html__('Contact', 'event_espresso');
3706
-        $action_desc = $trash
3707
-            ? esc_html__('moved to the trash', 'event_espresso')
3708
-            : esc_html__('restored', 'event_espresso');
3709
-        $this->_redirect_after_action($success, $what, $action_desc, ['action' => 'contact_list']);
3710
-    }
2875
+		}
2876
+		$template_args = [
2877
+			'title'                    => '',
2878
+			'content'                  => '',
2879
+			'step_button_text'         => '',
2880
+			'show_notification_toggle' => false,
2881
+		];
2882
+		// to indicate we're processing a new registration
2883
+		$hidden_fields = [
2884
+			'processing_registration' => [
2885
+				'type'  => 'hidden',
2886
+				'value' => 0,
2887
+			],
2888
+			'event_id'                => [
2889
+				'type'  => 'hidden',
2890
+				'value' => $this->_reg_event->ID(),
2891
+			],
2892
+		];
2893
+		// if the cart is empty then we know we're at step one, so we'll display the ticket selector
2894
+		$cart = EE_Registry::instance()->SSN->cart();
2895
+		$step = ! $cart instanceof EE_Cart ? 'ticket' : 'questions';
2896
+		switch ($step) {
2897
+			case 'ticket':
2898
+				$hidden_fields['processing_registration']['value'] = 1;
2899
+				$template_args['title']                            = esc_html__(
2900
+					'Step One: Select the Ticket for this registration',
2901
+					'event_espresso'
2902
+				);
2903
+				$template_args['content'] = EED_Ticket_Selector::instance()->display_ticket_selector($this->_reg_event);
2904
+				$template_args['content'] .= '</div>';
2905
+				$template_args['step_button_text'] = esc_html__(
2906
+					'Add Tickets and Continue to Registrant Details',
2907
+					'event_espresso'
2908
+				);
2909
+				$template_args['show_notification_toggle']         = false;
2910
+				break;
2911
+			case 'questions':
2912
+				$hidden_fields['processing_registration']['value'] = 2;
2913
+				$template_args['title']                            = esc_html__(
2914
+					'Step Two: Add Registrant Details for this Registration',
2915
+					'event_espresso'
2916
+				);
2917
+				// in theory, we should be able to run EED_SPCO at this point
2918
+				// because the cart should have been set up properly by the first process_reg_step run.
2919
+				$template_args['content'] = EED_Single_Page_Checkout::registration_checkout_for_admin();
2920
+				$template_args['step_button_text'] = esc_html__(
2921
+					'Save Registration and Continue to Details',
2922
+					'event_espresso'
2923
+				);
2924
+				$template_args['show_notification_toggle'] = true;
2925
+				break;
2926
+		}
2927
+		// we come back to the process_registration_step route.
2928
+		$this->_set_add_edit_form_tags('process_reg_step', $hidden_fields);
2929
+		return EEH_Template::display_template(
2930
+			REG_TEMPLATE_PATH . 'reg_admin_register_new_attendee_step_content.template.php',
2931
+			$template_args,
2932
+			true
2933
+		);
2934
+	}
2935
+
2936
+
2937
+	/**
2938
+	 * set_reg_event
2939
+	 *
2940
+	 * @return bool
2941
+	 * @throws EE_Error
2942
+	 * @throws InvalidArgumentException
2943
+	 * @throws InvalidDataTypeException
2944
+	 * @throws InvalidInterfaceException
2945
+	 */
2946
+	private function _set_reg_event()
2947
+	{
2948
+		if (is_object($this->_reg_event)) {
2949
+			return true;
2950
+		}
2951
+
2952
+		$EVT_ID = $this->request->getRequestParam('event_id', 0, 'int');
2953
+		if (! $EVT_ID) {
2954
+			return false;
2955
+		}
2956
+		$this->_reg_event = $this->getEventModel()->get_one_by_ID($EVT_ID);
2957
+		return true;
2958
+	}
2959
+
2960
+
2961
+	/**
2962
+	 * process_reg_step
2963
+	 *
2964
+	 * @return void
2965
+	 * @throws DomainException
2966
+	 * @throws EE_Error
2967
+	 * @throws InvalidArgumentException
2968
+	 * @throws InvalidDataTypeException
2969
+	 * @throws InvalidInterfaceException
2970
+	 * @throws ReflectionException
2971
+	 * @throws RuntimeException
2972
+	 */
2973
+	public function process_reg_step()
2974
+	{
2975
+		EE_System::do_not_cache();
2976
+		$this->_set_reg_event();
2977
+		/** @var CurrentPage $current_page */
2978
+		$current_page = $this->loader->getShared(CurrentPage::class);
2979
+		$current_page->setEspressoPage(true);
2980
+		$this->request->setRequestParam('uts', time());
2981
+		// what step are we on?
2982
+		$cart = EE_Registry::instance()->SSN->cart();
2983
+		$step = ! $cart instanceof EE_Cart ? 'ticket' : 'questions';
2984
+		// if doing ajax then we need to verify the nonce
2985
+		if ($this->request->isAjax()) {
2986
+			$nonce = $this->request->getRequestParam($this->_req_nonce, '');
2987
+			$this->_verify_nonce($nonce, $this->_req_nonce);
2988
+		}
2989
+		switch ($step) {
2990
+			case 'ticket':
2991
+				// process ticket selection
2992
+				$success = EED_Ticket_Selector::instance()->process_ticket_selections();
2993
+				if ($success) {
2994
+					EE_Error::add_success(
2995
+						esc_html__(
2996
+							'Tickets Selected. Now complete the registration.',
2997
+							'event_espresso'
2998
+						)
2999
+					);
3000
+				} else {
3001
+					$this->request->setRequestParam('step_error', true);
3002
+					$query_args['step_error'] = $this->request->getRequestParam('step_error', true, 'bool');
3003
+				}
3004
+				if ($this->request->isAjax()) {
3005
+					$this->new_registration(); // display next step
3006
+				} else {
3007
+					$query_args = [
3008
+						'action'                  => 'new_registration',
3009
+						'processing_registration' => 1,
3010
+						'event_id'                => $this->_reg_event->ID(),
3011
+						'uts'                     => time(),
3012
+					];
3013
+					$this->_redirect_after_action(
3014
+						false,
3015
+						'',
3016
+						'',
3017
+						$query_args,
3018
+						true
3019
+					);
3020
+				}
3021
+				break;
3022
+			case 'questions':
3023
+				if (! $this->request->requestParamIsSet('txn_reg_status_change[send_notifications]')) {
3024
+					add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_false', 15);
3025
+				}
3026
+				// process registration
3027
+				$transaction = EED_Single_Page_Checkout::instance()->process_registration_from_admin();
3028
+				if ($cart instanceof EE_Cart) {
3029
+					$grand_total = $cart->get_grand_total();
3030
+					if ($grand_total instanceof EE_Line_Item) {
3031
+						$grand_total->save_this_and_descendants_to_txn();
3032
+					}
3033
+				}
3034
+				if (! $transaction instanceof EE_Transaction) {
3035
+					$query_args = [
3036
+						'action'                  => 'new_registration',
3037
+						'processing_registration' => 2,
3038
+						'event_id'                => $this->_reg_event->ID(),
3039
+						'uts'                     => time(),
3040
+					];
3041
+					if ($this->request->isAjax()) {
3042
+						// display registration form again because there are errors (maybe validation?)
3043
+						$this->new_registration();
3044
+						return;
3045
+					}
3046
+					$this->_redirect_after_action(
3047
+						false,
3048
+						'',
3049
+						'',
3050
+						$query_args,
3051
+						true
3052
+					);
3053
+					return;
3054
+				}
3055
+				// maybe update status, and make sure to save transaction if not done already
3056
+				if (! $transaction->update_status_based_on_total_paid()) {
3057
+					$transaction->save();
3058
+				}
3059
+				EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
3060
+				$query_args = [
3061
+					'action'        => 'redirect_to_txn',
3062
+					'TXN_ID'        => $transaction->ID(),
3063
+					'EVT_ID'        => $this->_reg_event->ID(),
3064
+					'event_name'    => urlencode($this->_reg_event->name()),
3065
+					'redirect_from' => 'new_registration',
3066
+				];
3067
+				$this->_redirect_after_action(false, '', '', $query_args, true);
3068
+				break;
3069
+		}
3070
+		// what are you looking here for?  Should be nothing to do at this point.
3071
+	}
3072
+
3073
+
3074
+	/**
3075
+	 * redirect_to_txn
3076
+	 *
3077
+	 * @return void
3078
+	 * @throws EE_Error
3079
+	 * @throws InvalidArgumentException
3080
+	 * @throws InvalidDataTypeException
3081
+	 * @throws InvalidInterfaceException
3082
+	 * @throws ReflectionException
3083
+	 */
3084
+	public function redirect_to_txn()
3085
+	{
3086
+		EE_System::do_not_cache();
3087
+		EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
3088
+		$query_args = [
3089
+			'action' => 'view_transaction',
3090
+			'TXN_ID' => $this->request->getRequestParam('TXN_ID', 0, 'int'),
3091
+			'page'   => 'espresso_transactions',
3092
+		];
3093
+		if ($this->request->requestParamIsSet('EVT_ID') && $this->request->requestParamIsSet('redirect_from')) {
3094
+			$query_args['EVT_ID']        = $this->request->getRequestParam('EVT_ID', 0, 'int');
3095
+			$query_args['event_name']    = urlencode($this->request->getRequestParam('event_name'));
3096
+			$query_args['redirect_from'] = $this->request->getRequestParam('redirect_from');
3097
+		}
3098
+		EE_Error::add_success(
3099
+			esc_html__(
3100
+				'Registration Created.  Please review the transaction and add any payments as necessary',
3101
+				'event_espresso'
3102
+			)
3103
+		);
3104
+		$this->_redirect_after_action(false, '', '', $query_args, true);
3105
+	}
3106
+
3107
+
3108
+	/**
3109
+	 * generates HTML for the Attendee Contact List
3110
+	 *
3111
+	 * @return void
3112
+	 * @throws DomainException
3113
+	 * @throws EE_Error
3114
+	 */
3115
+	protected function _attendee_contact_list_table()
3116
+	{
3117
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3118
+		$this->_search_btn_label = esc_html__('Contacts', 'event_espresso');
3119
+		$this->display_admin_list_table_page_with_no_sidebar();
3120
+	}
3121
+
3122
+
3123
+	/**
3124
+	 * get_attendees
3125
+	 *
3126
+	 * @param      $per_page
3127
+	 * @param bool $count whether to return count or data.
3128
+	 * @param bool $trash
3129
+	 * @return array|int
3130
+	 * @throws EE_Error
3131
+	 * @throws InvalidArgumentException
3132
+	 * @throws InvalidDataTypeException
3133
+	 * @throws InvalidInterfaceException
3134
+	 */
3135
+	public function get_attendees($per_page, $count = false, $trash = false)
3136
+	{
3137
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3138
+		require_once(REG_ADMIN . 'EE_Attendee_Contact_List_Table.class.php');
3139
+		$orderby = $this->request->getRequestParam('orderby');
3140
+		switch ($orderby) {
3141
+			case 'ATT_ID':
3142
+			case 'ATT_fname':
3143
+			case 'ATT_email':
3144
+			case 'ATT_city':
3145
+			case 'STA_ID':
3146
+			case 'CNT_ID':
3147
+				break;
3148
+			case 'Registration_Count':
3149
+				$orderby = 'Registration_Count';
3150
+				break;
3151
+			default:
3152
+				$orderby = 'ATT_lname';
3153
+		}
3154
+		$sort         = $this->request->getRequestParam('order', 'ASC');
3155
+		$current_page = $this->request->getRequestParam('paged', 1, 'int');
3156
+		$per_page     = absint($per_page) ? $per_page : 10;
3157
+		$per_page     = $this->request->getRequestParam('perpage', $per_page, 'int');
3158
+		$_where       = [];
3159
+		$search_term  = $this->request->getRequestParam('s');
3160
+		if ($search_term) {
3161
+			$search_term  = '%' . $search_term . '%';
3162
+			$_where['OR'] = [
3163
+				'Registration.Event.EVT_name'       => ['LIKE', $search_term],
3164
+				'Registration.Event.EVT_desc'       => ['LIKE', $search_term],
3165
+				'Registration.Event.EVT_short_desc' => ['LIKE', $search_term],
3166
+				'ATT_fname'                         => ['LIKE', $search_term],
3167
+				'ATT_lname'                         => ['LIKE', $search_term],
3168
+				'ATT_short_bio'                     => ['LIKE', $search_term],
3169
+				'ATT_email'                         => ['LIKE', $search_term],
3170
+				'ATT_address'                       => ['LIKE', $search_term],
3171
+				'ATT_address2'                      => ['LIKE', $search_term],
3172
+				'ATT_city'                          => ['LIKE', $search_term],
3173
+				'Country.CNT_name'                  => ['LIKE', $search_term],
3174
+				'State.STA_name'                    => ['LIKE', $search_term],
3175
+				'ATT_phone'                         => ['LIKE', $search_term],
3176
+				'Registration.REG_final_price'      => ['LIKE', $search_term],
3177
+				'Registration.REG_code'             => ['LIKE', $search_term],
3178
+				'Registration.REG_group_size'       => ['LIKE', $search_term],
3179
+			];
3180
+		}
3181
+		$offset     = ($current_page - 1) * $per_page;
3182
+		$limit      = $count ? null : [$offset, $per_page];
3183
+		$query_args = [
3184
+			$_where,
3185
+			'extra_selects' => ['Registration_Count' => ['Registration.REG_ID', 'count', '%d']],
3186
+			'limit'         => $limit,
3187
+		];
3188
+		if (! $count) {
3189
+			$query_args['order_by'] = [$orderby => $sort];
3190
+		}
3191
+		$query_args[0]['status'] = $trash ? ['!=', 'publish'] : ['IN', ['publish']];
3192
+		return $count
3193
+			? $this->getAttendeeModel()->count($query_args, 'ATT_ID', true)
3194
+			: $this->getAttendeeModel()->get_all($query_args);
3195
+	}
3196
+
3197
+
3198
+	/**
3199
+	 * This is just taking care of resending the registration confirmation
3200
+	 *
3201
+	 * @return void
3202
+	 * @throws EE_Error
3203
+	 * @throws InvalidArgumentException
3204
+	 * @throws InvalidDataTypeException
3205
+	 * @throws InvalidInterfaceException
3206
+	 * @throws ReflectionException
3207
+	 */
3208
+	protected function _resend_registration()
3209
+	{
3210
+		$this->_process_resend_registration();
3211
+		$REG_ID      = $this->request->getRequestParam('_REG_ID', 0, 'int');
3212
+		$redirect_to = $this->request->getRequestParam('redirect_to');
3213
+		$query_args  = $redirect_to
3214
+			? ['action' => $redirect_to, '_REG_ID' => $REG_ID]
3215
+			: ['action' => 'default'];
3216
+		$this->_redirect_after_action(false, '', '', $query_args, true);
3217
+	}
3218
+
3219
+
3220
+	/**
3221
+	 * Creates a registration report, but accepts the name of a method to use for preparing the query parameters
3222
+	 * to use when selecting registrations
3223
+	 *
3224
+	 * @param string $method_name_for_getting_query_params the name of the method (on this class) to use for preparing
3225
+	 *                                                     the query parameters from the request
3226
+	 * @return void ends the request with a redirect or download
3227
+	 */
3228
+	public function _registrations_report_base($method_name_for_getting_query_params)
3229
+	{
3230
+		$EVT_ID = $this->request->requestParamIsSet('EVT_ID')
3231
+			? $this->request->getRequestParam('EVT_ID', 0, DataType::INT)
3232
+			: null;
3233
+		if (! defined('EE_USE_OLD_CSV_REPORT_CLASS')) {
3234
+			$return_url = $this->request->getRequestParam('return_url', '', DataType::URL);
3235
+			$filters = $this->request->getRequestParam('filters', [], DataType::STRING, true);
3236
+			$use_filters = $this->request->getRequestParam('use_filters', false, DataType::BOOL);
3237
+			wp_redirect(
3238
+				EE_Admin_Page::add_query_args_and_nonce(
3239
+					[
3240
+						'page'        => EED_Batch::PAGE_SLUG,
3241
+						'batch'       => EED_Batch::batch_file_job,
3242
+						'EVT_ID'      => $EVT_ID,
3243
+						'filters'     => urlencode(serialize($this->$method_name_for_getting_query_params($filters))),
3244
+						'use_filters' => urlencode($use_filters),
3245
+						'job_handler' => urlencode('EventEspressoBatchRequest\JobHandlers\RegistrationsReport'),
3246
+						'return_url'  => urlencode($return_url),
3247
+					]
3248
+				)
3249
+			);
3250
+		} else {
3251
+			// Pull the current request params
3252
+			$request_args = $this->request->requestParams();
3253
+			// Set the required request_args to be passed to the export
3254
+			$required_request_args = [
3255
+				'export' => 'report',
3256
+				'action' => 'registrations_report_for_event',
3257
+				'EVT_ID' => $EVT_ID,
3258
+			];
3259
+			// Merge required request args, overriding any currently set
3260
+			$request_args = array_merge($request_args, $required_request_args);
3261
+			if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3262
+				require_once(EE_CLASSES . 'EE_Export.class.php');
3263
+				$EE_Export = EE_Export::instance($request_args);
3264
+				$EE_Export->export();
3265
+			}
3266
+		}
3267
+	}
3268
+
3269
+
3270
+	/**
3271
+	 * Creates a registration report using only query parameters in the request
3272
+	 *
3273
+	 * @return void
3274
+	 */
3275
+	public function _registrations_report()
3276
+	{
3277
+		$this->_registrations_report_base('_get_registration_query_parameters');
3278
+	}
3279
+
3280
+
3281
+	public function _contact_list_export()
3282
+	{
3283
+		if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3284
+			require_once(EE_CLASSES . 'EE_Export.class.php');
3285
+			$EE_Export = EE_Export::instance($this->request->requestParams());
3286
+			$EE_Export->export_attendees();
3287
+		}
3288
+	}
3289
+
3290
+
3291
+	public function _contact_list_report()
3292
+	{
3293
+		if (! defined('EE_USE_OLD_CSV_REPORT_CLASS')) {
3294
+			wp_redirect(
3295
+				EE_Admin_Page::add_query_args_and_nonce(
3296
+					[
3297
+						'page'        => EED_Batch::PAGE_SLUG,
3298
+						'batch'       => EED_Batch::batch_file_job,
3299
+						'job_handler' => urlencode('EventEspressoBatchRequest\JobHandlers\AttendeesReport'),
3300
+						'return_url'  => urlencode($this->request->getRequestParam('return_url', '', DataType::URL)),
3301
+					]
3302
+				)
3303
+			);
3304
+		} else {
3305
+			if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3306
+				require_once(EE_CLASSES . 'EE_Export.class.php');
3307
+				$EE_Export = EE_Export::instance($this->request->requestParams());
3308
+				$EE_Export->report_attendees();
3309
+			}
3310
+		}
3311
+	}
3312
+
3313
+
3314
+
3315
+
3316
+
3317
+	/***************************************        ATTENDEE DETAILS        ***************************************/
3318
+	/**
3319
+	 * This duplicates the attendee object for the given incoming registration id and attendee_id.
3320
+	 *
3321
+	 * @return void
3322
+	 * @throws EE_Error
3323
+	 * @throws InvalidArgumentException
3324
+	 * @throws InvalidDataTypeException
3325
+	 * @throws InvalidInterfaceException
3326
+	 * @throws ReflectionException
3327
+	 */
3328
+	protected function _duplicate_attendee()
3329
+	{
3330
+		$REG_ID = $this->request->getRequestParam('_REG_ID', 0, 'int');
3331
+		$action = $this->request->getRequestParam('return', 'default');
3332
+		// verify we have necessary info
3333
+		if (! $REG_ID) {
3334
+			EE_Error::add_error(
3335
+				esc_html__(
3336
+					'Unable to create the contact for the registration because the required parameters are not present (_REG_ID )',
3337
+					'event_espresso'
3338
+				),
3339
+				__FILE__,
3340
+				__LINE__,
3341
+				__FUNCTION__
3342
+			);
3343
+			$query_args = ['action' => $action];
3344
+			$this->_redirect_after_action('', '', '', $query_args, true);
3345
+		}
3346
+		// okay necessary deets present... let's dupe the incoming attendee and attach to incoming registration.
3347
+		$registration = $this->getRegistrationModel()->get_one_by_ID($REG_ID);
3348
+		if (! $registration instanceof EE_Registration) {
3349
+			throw new RuntimeException(
3350
+				sprintf(
3351
+					esc_html__(
3352
+						'Unable to create the contact because a valid registration could not be retrieved for REG ID: %1$d',
3353
+						'event_espresso'
3354
+					),
3355
+					$REG_ID
3356
+				)
3357
+			);
3358
+		}
3359
+		$attendee = $registration->attendee();
3360
+		// remove relation of existing attendee on registration
3361
+		$registration->_remove_relation_to($attendee, 'Attendee');
3362
+		// new attendee
3363
+		$new_attendee = clone $attendee;
3364
+		$new_attendee->set('ATT_ID', 0);
3365
+		$new_attendee->save();
3366
+		// add new attendee to reg
3367
+		$registration->_add_relation_to($new_attendee, 'Attendee');
3368
+		EE_Error::add_success(
3369
+			esc_html__(
3370
+				'New Contact record created.  Now make any edits you wish to make for this contact.',
3371
+				'event_espresso'
3372
+			)
3373
+		);
3374
+		// redirect to edit page for attendee
3375
+		$query_args = ['post' => $new_attendee->ID(), 'action' => 'edit_attendee'];
3376
+		$this->_redirect_after_action('', '', '', $query_args, true);
3377
+	}
3378
+
3379
+
3380
+	/**
3381
+	 * Callback invoked by parent EE_Admin_CPT class hooked in on `save_post` wp hook.
3382
+	 *
3383
+	 * @param int     $post_id
3384
+	 * @param WP_Post $post
3385
+	 * @throws DomainException
3386
+	 * @throws EE_Error
3387
+	 * @throws InvalidArgumentException
3388
+	 * @throws InvalidDataTypeException
3389
+	 * @throws InvalidInterfaceException
3390
+	 * @throws LogicException
3391
+	 * @throws InvalidFormSubmissionException
3392
+	 * @throws ReflectionException
3393
+	 */
3394
+	protected function _insert_update_cpt_item($post_id, $post)
3395
+	{
3396
+		$success  = true;
3397
+		$attendee = $post instanceof WP_Post && $post->post_type === 'espresso_attendees'
3398
+			? $this->getAttendeeModel()->get_one_by_ID($post_id)
3399
+			: null;
3400
+		// for attendee updates
3401
+		if ($attendee instanceof EE_Attendee) {
3402
+			// note we should only be UPDATING attendees at this point.
3403
+			$fname          = $this->request->getRequestParam('ATT_fname', '');
3404
+			$lname          = $this->request->getRequestParam('ATT_lname', '');
3405
+			$updated_fields = [
3406
+				'ATT_fname'     => $fname,
3407
+				'ATT_lname'     => $lname,
3408
+				'ATT_full_name' => "{$fname} {$lname}",
3409
+				'ATT_address'   => $this->request->getRequestParam('ATT_address', ''),
3410
+				'ATT_address2'  => $this->request->getRequestParam('ATT_address2', ''),
3411
+				'ATT_city'      => $this->request->getRequestParam('ATT_city', ''),
3412
+				'STA_ID'        => $this->request->getRequestParam('STA_ID', ''),
3413
+				'CNT_ISO'       => $this->request->getRequestParam('CNT_ISO', ''),
3414
+				'ATT_zip'       => $this->request->getRequestParam('ATT_zip', ''),
3415
+			];
3416
+			foreach ($updated_fields as $field => $value) {
3417
+				$attendee->set($field, $value);
3418
+			}
3419
+
3420
+			// process contact details metabox form handler (which will also save the attendee)
3421
+			$contact_details_form = $this->getAttendeeContactDetailsMetaboxFormHandler($attendee);
3422
+			$success              = $contact_details_form->process($this->request->requestParams());
3423
+
3424
+			$attendee_update_callbacks = apply_filters(
3425
+				'FHEE__Registrations_Admin_Page__insert_update_cpt_item__attendee_update',
3426
+				[]
3427
+			);
3428
+			foreach ($attendee_update_callbacks as $a_callback) {
3429
+				if (false === call_user_func_array($a_callback, [$attendee, $this->request->requestParams()])) {
3430
+					throw new EE_Error(
3431
+						sprintf(
3432
+							esc_html__(
3433
+								'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.',
3434
+								'event_espresso'
3435
+							),
3436
+							$a_callback
3437
+						)
3438
+					);
3439
+				}
3440
+			}
3441
+		}
3442
+
3443
+		if ($success === false) {
3444
+			EE_Error::add_error(
3445
+				esc_html__(
3446
+					'Something went wrong with updating the meta table data for the registration.',
3447
+					'event_espresso'
3448
+				),
3449
+				__FILE__,
3450
+				__FUNCTION__,
3451
+				__LINE__
3452
+			);
3453
+		}
3454
+	}
3455
+
3456
+
3457
+	public function trash_cpt_item($post_id)
3458
+	{
3459
+	}
3460
+
3461
+
3462
+	public function delete_cpt_item($post_id)
3463
+	{
3464
+	}
3465
+
3466
+
3467
+	public function restore_cpt_item($post_id)
3468
+	{
3469
+	}
3470
+
3471
+
3472
+	protected function _restore_cpt_item($post_id, $revision_id)
3473
+	{
3474
+	}
3475
+
3476
+
3477
+	/**
3478
+	 * @throws EE_Error
3479
+	 * @throws ReflectionException
3480
+	 * @since 4.10.2.p
3481
+	 */
3482
+	public function attendee_editor_metaboxes()
3483
+	{
3484
+		$this->verify_cpt_object();
3485
+		remove_meta_box(
3486
+			'postexcerpt',
3487
+			$this->_cpt_routes[ $this->_req_action ],
3488
+			'normal'
3489
+		);
3490
+		remove_meta_box('commentstatusdiv', $this->_cpt_routes[ $this->_req_action ], 'normal');
3491
+		if (post_type_supports('espresso_attendees', 'excerpt')) {
3492
+			$this->addMetaBox(
3493
+				'postexcerpt',
3494
+				esc_html__('Short Biography', 'event_espresso'),
3495
+				'post_excerpt_meta_box',
3496
+				$this->_cpt_routes[ $this->_req_action ]
3497
+			);
3498
+		}
3499
+		if (post_type_supports('espresso_attendees', 'comments')) {
3500
+			$this->addMetaBox(
3501
+				'commentsdiv',
3502
+				esc_html__('Notes on the Contact', 'event_espresso'),
3503
+				'post_comment_meta_box',
3504
+				$this->_cpt_routes[ $this->_req_action ],
3505
+				'normal',
3506
+				'core'
3507
+			);
3508
+		}
3509
+		$this->addMetaBox(
3510
+			'attendee_contact_info',
3511
+			esc_html__('Contact Info', 'event_espresso'),
3512
+			[$this, 'attendee_contact_info'],
3513
+			$this->_cpt_routes[ $this->_req_action ],
3514
+			'side',
3515
+			'core'
3516
+		);
3517
+		$this->addMetaBox(
3518
+			'attendee_details_address',
3519
+			esc_html__('Address Details', 'event_espresso'),
3520
+			[$this, 'attendee_address_details'],
3521
+			$this->_cpt_routes[ $this->_req_action ],
3522
+			'normal',
3523
+			'core'
3524
+		);
3525
+		$this->addMetaBox(
3526
+			'attendee_registrations',
3527
+			esc_html__('Registrations for this Contact', 'event_espresso'),
3528
+			[$this, 'attendee_registrations_meta_box'],
3529
+			$this->_cpt_routes[ $this->_req_action ]
3530
+		);
3531
+	}
3532
+
3533
+
3534
+	/**
3535
+	 * Metabox for attendee contact info
3536
+	 *
3537
+	 * @param WP_Post $post wp post object
3538
+	 * @return void attendee contact info ( and form )
3539
+	 * @throws EE_Error
3540
+	 * @throws InvalidArgumentException
3541
+	 * @throws InvalidDataTypeException
3542
+	 * @throws InvalidInterfaceException
3543
+	 * @throws LogicException
3544
+	 * @throws DomainException
3545
+	 */
3546
+	public function attendee_contact_info($post)
3547
+	{
3548
+		// get attendee object ( should already have it )
3549
+		$form = $this->getAttendeeContactDetailsMetaboxFormHandler($this->_cpt_model_obj);
3550
+		$form->enqueueStylesAndScripts();
3551
+		echo wp_kses($form->display(), AllowedTags::getWithFormTags());
3552
+	}
3553
+
3554
+
3555
+	/**
3556
+	 * Return form handler for the contact details metabox
3557
+	 *
3558
+	 * @param EE_Attendee $attendee
3559
+	 * @return AttendeeContactDetailsMetaboxFormHandler
3560
+	 * @throws DomainException
3561
+	 * @throws InvalidArgumentException
3562
+	 * @throws InvalidDataTypeException
3563
+	 * @throws InvalidInterfaceException
3564
+	 */
3565
+	protected function getAttendeeContactDetailsMetaboxFormHandler(EE_Attendee $attendee)
3566
+	{
3567
+		return new AttendeeContactDetailsMetaboxFormHandler($attendee, EE_Registry::instance());
3568
+	}
3569
+
3570
+
3571
+	/**
3572
+	 * Metabox for attendee details
3573
+	 *
3574
+	 * @param WP_Post $post wp post object
3575
+	 * @throws EE_Error
3576
+	 * @throws ReflectionException
3577
+	 */
3578
+	public function attendee_address_details($post)
3579
+	{
3580
+		// get attendee object (should already have it)
3581
+		$this->_template_args['attendee']     = $this->_cpt_model_obj;
3582
+		$this->_template_args['state_html']   = EEH_Form_Fields::generate_form_input(
3583
+			new EE_Question_Form_Input(
3584
+				EE_Question::new_instance(
3585
+					[
3586
+						'QST_ID'           => 0,
3587
+						'QST_display_text' => esc_html__('State/Province', 'event_espresso'),
3588
+						'QST_system'       => 'admin-state',
3589
+					]
3590
+				),
3591
+				EE_Answer::new_instance(
3592
+					[
3593
+						'ANS_ID'    => 0,
3594
+						'ANS_value' => $this->_cpt_model_obj->state_ID(),
3595
+					]
3596
+				),
3597
+				[
3598
+					'input_id'       => 'STA_ID',
3599
+					'input_name'     => 'STA_ID',
3600
+					'input_prefix'   => '',
3601
+					'append_qstn_id' => false,
3602
+				]
3603
+			)
3604
+		);
3605
+		$this->_template_args['country_html'] = EEH_Form_Fields::generate_form_input(
3606
+			new EE_Question_Form_Input(
3607
+				EE_Question::new_instance(
3608
+					[
3609
+						'QST_ID'           => 0,
3610
+						'QST_display_text' => esc_html__('Country', 'event_espresso'),
3611
+						'QST_system'       => 'admin-country',
3612
+					]
3613
+				),
3614
+				EE_Answer::new_instance(
3615
+					[
3616
+						'ANS_ID'    => 0,
3617
+						'ANS_value' => $this->_cpt_model_obj->country_ID(),
3618
+					]
3619
+				),
3620
+				[
3621
+					'input_id'       => 'CNT_ISO',
3622
+					'input_name'     => 'CNT_ISO',
3623
+					'input_prefix'   => '',
3624
+					'append_qstn_id' => false,
3625
+				]
3626
+			)
3627
+		);
3628
+		$template = REG_TEMPLATE_PATH . 'attendee_address_details_metabox_content.template.php';
3629
+		EEH_Template::display_template($template, $this->_template_args);
3630
+	}
3631
+
3632
+
3633
+	/**
3634
+	 * _attendee_details
3635
+	 *
3636
+	 * @param $post
3637
+	 * @return void
3638
+	 * @throws DomainException
3639
+	 * @throws EE_Error
3640
+	 * @throws InvalidArgumentException
3641
+	 * @throws InvalidDataTypeException
3642
+	 * @throws InvalidInterfaceException
3643
+	 * @throws ReflectionException
3644
+	 */
3645
+	public function attendee_registrations_meta_box($post)
3646
+	{
3647
+		$this->_template_args['attendee']      = $this->_cpt_model_obj;
3648
+		$this->_template_args['registrations'] = $this->_cpt_model_obj->get_many_related('Registration');
3649
+		$template = REG_TEMPLATE_PATH . 'attendee_registrations_main_meta_box.template.php';
3650
+		EEH_Template::display_template($template, $this->_template_args);
3651
+	}
3652
+
3653
+
3654
+	/**
3655
+	 * add in the form fields for the attendee edit
3656
+	 *
3657
+	 * @param WP_Post $post wp post object
3658
+	 * @return void echos html for new form.
3659
+	 * @throws DomainException
3660
+	 */
3661
+	public function after_title_form_fields($post)
3662
+	{
3663
+		if ($post->post_type === 'espresso_attendees') {
3664
+			$template                  = REG_TEMPLATE_PATH . 'attendee_details_after_title_form_fields.template.php';
3665
+			$template_args['attendee'] = $this->_cpt_model_obj;
3666
+			EEH_Template::display_template($template, $template_args);
3667
+		}
3668
+	}
3669
+
3670
+
3671
+	/**
3672
+	 * _trash_or_restore_attendee
3673
+	 *
3674
+	 * @param boolean $trash - whether to move item to trash (TRUE) or restore it (FALSE)
3675
+	 * @return void
3676
+	 * @throws EE_Error
3677
+	 * @throws InvalidArgumentException
3678
+	 * @throws InvalidDataTypeException
3679
+	 * @throws InvalidInterfaceException
3680
+	 */
3681
+	protected function _trash_or_restore_attendees($trash = true)
3682
+	{
3683
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3684
+		$status = $trash ? 'trash' : 'publish';
3685
+		// Checkboxes
3686
+		if ($this->request->requestParamIsSet('checkbox')) {
3687
+			$ATT_IDs = $this->request->getRequestParam('checkbox', [], 'int', true);
3688
+			// if array has more than one element than success message should be plural
3689
+			$success = count($ATT_IDs) > 1 ? 2 : 1;
3690
+			// cycle thru checkboxes
3691
+			foreach ($ATT_IDs as $ATT_ID) {
3692
+				$updated = $this->getAttendeeModel()->update_by_ID(['status' => $status], $ATT_ID);
3693
+				if (! $updated) {
3694
+					$success = 0;
3695
+				}
3696
+			}
3697
+		} else {
3698
+			// grab single id and delete
3699
+			$ATT_ID = $this->request->getRequestParam('ATT_ID', 0, 'int');
3700
+			// update attendee
3701
+			$success = $this->getAttendeeModel()->update_by_ID(['status' => $status], $ATT_ID) ? 1 : 0;
3702
+		}
3703
+		$what        = $success > 1
3704
+			? esc_html__('Contacts', 'event_espresso')
3705
+			: esc_html__('Contact', 'event_espresso');
3706
+		$action_desc = $trash
3707
+			? esc_html__('moved to the trash', 'event_espresso')
3708
+			: esc_html__('restored', 'event_espresso');
3709
+		$this->_redirect_after_action($success, $what, $action_desc, ['action' => 'contact_list']);
3710
+	}
3711 3711
 }
Please login to merge, or discard this patch.
Spacing   +104 added lines, -104 removed lines patch added patch discarded remove patch
@@ -93,7 +93,7 @@  discard block
 block discarded – undo
93 93
      */
94 94
     protected function getRegistrationModel()
95 95
     {
96
-        if (! $this->registration_model instanceof EEM_Registration) {
96
+        if ( ! $this->registration_model instanceof EEM_Registration) {
97 97
             $this->registration_model = $this->loader->getShared('EEM_Registration');
98 98
         }
99 99
         return $this->registration_model;
@@ -109,7 +109,7 @@  discard block
 block discarded – undo
109 109
      */
110 110
     protected function getAttendeeModel()
111 111
     {
112
-        if (! $this->attendee_model instanceof EEM_Attendee) {
112
+        if ( ! $this->attendee_model instanceof EEM_Attendee) {
113 113
             $this->attendee_model = $this->loader->getShared('EEM_Attendee');
114 114
         }
115 115
         return $this->attendee_model;
@@ -125,7 +125,7 @@  discard block
 block discarded – undo
125 125
      */
126 126
     protected function getEventModel()
127 127
     {
128
-        if (! $this->event_model instanceof EEM_Event) {
128
+        if ( ! $this->event_model instanceof EEM_Event) {
129 129
             $this->event_model = $this->loader->getShared('EEM_Event');
130 130
         }
131 131
         return $this->event_model;
@@ -141,7 +141,7 @@  discard block
 block discarded – undo
141 141
      */
142 142
     protected function getStatusModel()
143 143
     {
144
-        if (! $this->status_model instanceof EEM_Status) {
144
+        if ( ! $this->status_model instanceof EEM_Status) {
145 145
             $this->status_model = $this->loader->getShared('EEM_Status');
146 146
         }
147 147
         return $this->status_model;
@@ -763,7 +763,7 @@  discard block
 block discarded – undo
763 763
         // style
764 764
         wp_register_style(
765 765
             'espresso_reg',
766
-            REG_ASSETS_URL . 'espresso_registrations_admin.css',
766
+            REG_ASSETS_URL.'espresso_registrations_admin.css',
767 767
             ['ee-admin-css'],
768 768
             EVENT_ESPRESSO_VERSION
769 769
         );
@@ -771,7 +771,7 @@  discard block
 block discarded – undo
771 771
         // script
772 772
         wp_register_script(
773 773
             'espresso_reg',
774
-            REG_ASSETS_URL . 'espresso_registrations_admin.js',
774
+            REG_ASSETS_URL.'espresso_registrations_admin.js',
775 775
             ['jquery-ui-datepicker', 'jquery-ui-draggable', 'ee_admin_js'],
776 776
             EVENT_ESPRESSO_VERSION,
777 777
             true
@@ -795,7 +795,7 @@  discard block
 block discarded – undo
795 795
             'att_publish_text' => sprintf(
796 796
             /* translators: The date and time */
797 797
                 wp_strip_all_tags(__('Created on: %s', 'event_espresso')),
798
-                '<b>' . $this->_cpt_model_obj->get_datetime('ATT_created') . '</b>'
798
+                '<b>'.$this->_cpt_model_obj->get_datetime('ATT_created').'</b>'
799 799
             ),
800 800
         ];
801 801
         wp_localize_script('espresso_reg', 'ATTENDEE_DETAILS', $attendee_details_translations);
@@ -826,7 +826,7 @@  discard block
 block discarded – undo
826 826
         wp_dequeue_style('espresso_reg');
827 827
         wp_register_style(
828 828
             'espresso_att',
829
-            REG_ASSETS_URL . 'espresso_attendees_admin.css',
829
+            REG_ASSETS_URL.'espresso_attendees_admin.css',
830 830
             ['ee-admin-css'],
831 831
             EVENT_ESPRESSO_VERSION
832 832
         );
@@ -838,7 +838,7 @@  discard block
 block discarded – undo
838 838
     {
839 839
         wp_register_script(
840 840
             'ee-spco-for-admin',
841
-            REG_ASSETS_URL . 'spco_for_admin.js',
841
+            REG_ASSETS_URL.'spco_for_admin.js',
842 842
             ['underscore', 'jquery'],
843 843
             EVENT_ESPRESSO_VERSION,
844 844
             true
@@ -886,7 +886,7 @@  discard block
 block discarded – undo
886 886
             'no_approve_registrations' => 'not_approved_registration',
887 887
             'cancel_registrations'     => 'cancelled_registration',
888 888
         ];
889
-        $can_send    = EE_Registry::instance()->CAP->current_user_can(
889
+        $can_send = EE_Registry::instance()->CAP->current_user_can(
890 890
             'ee_send_message',
891 891
             'batch_send_messages'
892 892
         );
@@ -991,7 +991,7 @@  discard block
 block discarded – undo
991 991
                     'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
992 992
                 ],
993 993
             ];
994
-            $this->_views['trash']      = [
994
+            $this->_views['trash'] = [
995 995
                 'slug'        => 'trash',
996 996
                 'label'       => esc_html__('Trash', 'event_espresso'),
997 997
                 'count'       => 0,
@@ -1091,7 +1091,7 @@  discard block
 block discarded – undo
1091 1091
         }
1092 1092
         $sc_items = [
1093 1093
             'approved_status'   => [
1094
-                'class' => 'ee-status-legend ee-status-bg--' . EEM_Registration::status_id_approved,
1094
+                'class' => 'ee-status-legend ee-status-bg--'.EEM_Registration::status_id_approved,
1095 1095
                 'desc'  => EEH_Template::pretty_status(
1096 1096
                     EEM_Registration::status_id_approved,
1097 1097
                     false,
@@ -1099,7 +1099,7 @@  discard block
 block discarded – undo
1099 1099
                 ),
1100 1100
             ],
1101 1101
             'pending_status'    => [
1102
-                'class' => 'ee-status-legend ee-status-bg--' . EEM_Registration::status_id_pending_payment,
1102
+                'class' => 'ee-status-legend ee-status-bg--'.EEM_Registration::status_id_pending_payment,
1103 1103
                 'desc'  => EEH_Template::pretty_status(
1104 1104
                     EEM_Registration::status_id_pending_payment,
1105 1105
                     false,
@@ -1107,7 +1107,7 @@  discard block
 block discarded – undo
1107 1107
                 ),
1108 1108
             ],
1109 1109
             'wait_list'         => [
1110
-                'class' => 'ee-status-legend ee-status-bg--' . EEM_Registration::status_id_wait_list,
1110
+                'class' => 'ee-status-legend ee-status-bg--'.EEM_Registration::status_id_wait_list,
1111 1111
                 'desc'  => EEH_Template::pretty_status(
1112 1112
                     EEM_Registration::status_id_wait_list,
1113 1113
                     false,
@@ -1115,7 +1115,7 @@  discard block
 block discarded – undo
1115 1115
                 ),
1116 1116
             ],
1117 1117
             'incomplete_status' => [
1118
-                'class' => 'ee-status-legend ee-status-bg--' . EEM_Registration::status_id_incomplete,
1118
+                'class' => 'ee-status-legend ee-status-bg--'.EEM_Registration::status_id_incomplete,
1119 1119
                 'desc'  => EEH_Template::pretty_status(
1120 1120
                     EEM_Registration::status_id_incomplete,
1121 1121
                     false,
@@ -1123,7 +1123,7 @@  discard block
 block discarded – undo
1123 1123
                 ),
1124 1124
             ],
1125 1125
             'not_approved'      => [
1126
-                'class' => 'ee-status-legend ee-status-bg--' . EEM_Registration::status_id_not_approved,
1126
+                'class' => 'ee-status-legend ee-status-bg--'.EEM_Registration::status_id_not_approved,
1127 1127
                 'desc'  => EEH_Template::pretty_status(
1128 1128
                     EEM_Registration::status_id_not_approved,
1129 1129
                     false,
@@ -1131,7 +1131,7 @@  discard block
 block discarded – undo
1131 1131
                 ),
1132 1132
             ],
1133 1133
             'declined_status'   => [
1134
-                'class' => 'ee-status-legend ee-status-bg--' . EEM_Registration::status_id_declined,
1134
+                'class' => 'ee-status-legend ee-status-bg--'.EEM_Registration::status_id_declined,
1135 1135
                 'desc'  => EEH_Template::pretty_status(
1136 1136
                     EEM_Registration::status_id_declined,
1137 1137
                     false,
@@ -1139,7 +1139,7 @@  discard block
 block discarded – undo
1139 1139
                 ),
1140 1140
             ],
1141 1141
             'cancelled_status'  => [
1142
-                'class' => 'ee-status-legend ee-status-bg--' . EEM_Registration::status_id_cancelled,
1142
+                'class' => 'ee-status-legend ee-status-bg--'.EEM_Registration::status_id_cancelled,
1143 1143
                 'desc'  => EEH_Template::pretty_status(
1144 1144
                     EEM_Registration::status_id_cancelled,
1145 1145
                     false,
@@ -1176,8 +1176,8 @@  discard block
 block discarded – undo
1176 1176
             $filter_header_decorator = $this->loader->getNew($admin_page_header_decorator);
1177 1177
             $header_text = $filter_header_decorator->getHeaderText($header_text);
1178 1178
         }
1179
-        $this->_template_args['before_list_table']  = $header_text;
1180
-        $this->_template_args['after_list_table']  = $this->_display_legend($this->_registration_legend_items());
1179
+        $this->_template_args['before_list_table'] = $header_text;
1180
+        $this->_template_args['after_list_table'] = $this->_display_legend($this->_registration_legend_items());
1181 1181
         $this->display_admin_list_table_page_with_no_sidebar();
1182 1182
     }
1183 1183
 
@@ -1199,7 +1199,7 @@  discard block
 block discarded – undo
1199 1199
                 $EVT_ID
1200 1200
             )
1201 1201
         ) {
1202
-            $this->_admin_page_title .= ' ' . $this->get_action_link_or_button(
1202
+            $this->_admin_page_title .= ' '.$this->get_action_link_or_button(
1203 1203
                 'new_registration',
1204 1204
                 'add-registrant',
1205 1205
                 ['event_id' => $EVT_ID],
@@ -1357,7 +1357,7 @@  discard block
 block discarded – undo
1357 1357
                 ],
1358 1358
                 REG_ADMIN_URL
1359 1359
             );
1360
-            $this->_template_args['filtered_transactions_link']  = EE_Admin_Page::add_query_args_and_nonce(
1360
+            $this->_template_args['filtered_transactions_link'] = EE_Admin_Page::add_query_args_and_nonce(
1361 1361
                 [
1362 1362
                     'action' => 'default',
1363 1363
                     'EVT_ID' => $event_id,
@@ -1365,7 +1365,7 @@  discard block
 block discarded – undo
1365 1365
                 ],
1366 1366
                 admin_url('admin.php')
1367 1367
             );
1368
-            $this->_template_args['event_link']                  = EE_Admin_Page::add_query_args_and_nonce(
1368
+            $this->_template_args['event_link'] = EE_Admin_Page::add_query_args_and_nonce(
1369 1369
                 [
1370 1370
                     'page'   => 'espresso_events',
1371 1371
                     'action' => 'edit',
@@ -1374,12 +1374,12 @@  discard block
 block discarded – undo
1374 1374
                 admin_url('admin.php')
1375 1375
             );
1376 1376
             // next and previous links
1377
-            $next_reg                                      = $this->_registration->next(
1377
+            $next_reg = $this->_registration->next(
1378 1378
                 null,
1379 1379
                 [],
1380 1380
                 'REG_ID'
1381 1381
             );
1382
-            $this->_template_args['next_registration']     = $next_reg
1382
+            $this->_template_args['next_registration'] = $next_reg
1383 1383
                 ? $this->_next_link(
1384 1384
                     EE_Admin_Page::add_query_args_and_nonce(
1385 1385
                         [
@@ -1391,7 +1391,7 @@  discard block
 block discarded – undo
1391 1391
                     'dashicons dashicons-arrow-right ee-icon-size-22'
1392 1392
                 )
1393 1393
                 : '';
1394
-            $previous_reg                                  = $this->_registration->previous(
1394
+            $previous_reg = $this->_registration->previous(
1395 1395
                 null,
1396 1396
                 [],
1397 1397
                 'REG_ID'
@@ -1409,7 +1409,7 @@  discard block
 block discarded – undo
1409 1409
                 )
1410 1410
                 : '';
1411 1411
             // grab header
1412
-            $template_path                             = REG_TEMPLATE_PATH . 'reg_admin_details_header.template.php';
1412
+            $template_path                             = REG_TEMPLATE_PATH.'reg_admin_details_header.template.php';
1413 1413
             $this->_template_args['REG_ID']            = $this->_registration->ID();
1414 1414
             $this->_template_args['admin_page_header'] = EEH_Template::display_template(
1415 1415
                 $template_path,
@@ -1446,7 +1446,7 @@  discard block
 block discarded – undo
1446 1446
         );
1447 1447
         $this->addMetaBox(
1448 1448
             'edit-reg-details-mbox',
1449
-            '<span>' . esc_html__('Registration Details', 'event_espresso')
1449
+            '<span>'.esc_html__('Registration Details', 'event_espresso')
1450 1450
             . '&nbsp;<span class="dashicons dashicons-clipboard"></span></span>',
1451 1451
             [$this, '_reg_details_meta_box'],
1452 1452
             $this->_wp_page_slug
@@ -1550,7 +1550,7 @@  discard block
 block discarded – undo
1550 1550
                 $this->_registration->ID()
1551 1551
             )
1552 1552
         ) {
1553
-            $reg_status_change_form_array['subsections']['reg_status']         = new EE_Select_Input(
1553
+            $reg_status_change_form_array['subsections']['reg_status'] = new EE_Select_Input(
1554 1554
                 $this->_get_reg_statuses(),
1555 1555
                 [
1556 1556
                     'html_label_text' => esc_html__('Change Registration Status to', 'event_espresso'),
@@ -1567,7 +1567,7 @@  discard block
 block discarded – undo
1567 1567
                     ),
1568 1568
                 ]
1569 1569
             );
1570
-            $reg_status_change_form_array['subsections']['submit']             = new EE_Submit_Input(
1570
+            $reg_status_change_form_array['subsections']['submit'] = new EE_Submit_Input(
1571 1571
                 [
1572 1572
                     'html_class'      => 'button--primary',
1573 1573
                     'html_label_text' => '&nbsp;',
@@ -1592,7 +1592,7 @@  discard block
 block discarded – undo
1592 1592
     protected function _get_reg_statuses()
1593 1593
     {
1594 1594
         $reg_status_array = $this->getRegistrationModel()->reg_status_array();
1595
-        unset($reg_status_array[ EEM_Registration::status_id_incomplete ]);
1595
+        unset($reg_status_array[EEM_Registration::status_id_incomplete]);
1596 1596
         // get current reg status
1597 1597
         $current_status = $this->_registration->status_ID();
1598 1598
         // is registration for free event? This will determine whether to display the pending payment option
@@ -1600,7 +1600,7 @@  discard block
 block discarded – undo
1600 1600
             $current_status !== EEM_Registration::status_id_pending_payment
1601 1601
             && EEH_Money::compare_floats($this->_registration->ticket()->price(), 0.00)
1602 1602
         ) {
1603
-            unset($reg_status_array[ EEM_Registration::status_id_pending_payment ]);
1603
+            unset($reg_status_array[EEM_Registration::status_id_pending_payment]);
1604 1604
         }
1605 1605
         return $this->getStatusModel()->localized_status($reg_status_array, false, 'sentence');
1606 1606
     }
@@ -1691,7 +1691,7 @@  discard block
 block discarded – undo
1691 1691
         $success = false;
1692 1692
         // typecast $REG_IDs
1693 1693
         $REG_IDs = (array) $REG_IDs;
1694
-        if (! empty($REG_IDs)) {
1694
+        if ( ! empty($REG_IDs)) {
1695 1695
             $success = true;
1696 1696
             // set default status if none is passed
1697 1697
             $status         = $status ?: EEM_Registration::status_id_pending_payment;
@@ -1851,7 +1851,7 @@  discard block
 block discarded – undo
1851 1851
             $action,
1852 1852
             $notify
1853 1853
         );
1854
-        $method = $action . '_registration';
1854
+        $method = $action.'_registration';
1855 1855
         if (method_exists($this, $method)) {
1856 1856
             $this->$method($notify);
1857 1857
         }
@@ -2001,7 +2001,7 @@  discard block
 block discarded – undo
2001 2001
         $filters        = new EE_Line_Item_Filter_Collection();
2002 2002
         $filters->add(new EE_Single_Registration_Line_Item_Filter($this->_registration));
2003 2003
         $filters->add(new EE_Non_Zero_Line_Item_Filter());
2004
-        $line_item_filter_processor              = new EE_Line_Item_Filter_Processor(
2004
+        $line_item_filter_processor = new EE_Line_Item_Filter_Processor(
2005 2005
             $filters,
2006 2006
             $transaction->total_line_item()
2007 2007
         );
@@ -2014,7 +2014,7 @@  discard block
 block discarded – undo
2014 2014
             $filtered_line_item_tree,
2015 2015
             ['EE_Registration' => $this->_registration]
2016 2016
         );
2017
-        $attendee                                = $this->_registration->attendee();
2017
+        $attendee = $this->_registration->attendee();
2018 2018
         if (
2019 2019
             EE_Registry::instance()->CAP->current_user_can(
2020 2020
                 'ee_read_transaction',
@@ -2096,7 +2096,7 @@  discard block
 block discarded – undo
2096 2096
                 'Payment method response',
2097 2097
                 'event_espresso'
2098 2098
             );
2099
-            $this->_template_args['reg_details']['response_msg']['class']   = 'regular-text';
2099
+            $this->_template_args['reg_details']['response_msg']['class'] = 'regular-text';
2100 2100
         }
2101 2101
         $this->_template_args['reg_details']['registration_session']['value'] = $reg_details['registration_session'];
2102 2102
         $this->_template_args['reg_details']['registration_session']['label'] = esc_html__(
@@ -2127,7 +2127,7 @@  discard block
 block discarded – undo
2127 2127
         $this->_template_args['REG_ID'] = $this->_registration->ID();
2128 2128
         $this->_template_args['event_id'] = $this->_registration->event_ID();
2129 2129
 
2130
-        $template_path = REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_reg_details.template.php';
2130
+        $template_path = REG_TEMPLATE_PATH.'reg_admin_details_main_meta_box_reg_details.template.php';
2131 2131
         EEH_Template::display_template($template_path, $this->_template_args); // already escaped
2132 2132
     }
2133 2133
 
@@ -2166,7 +2166,7 @@  discard block
 block discarded – undo
2166 2166
 
2167 2167
             $this->_template_args['reg_questions_form_action'] = 'edit_registration';
2168 2168
             $this->_template_args['REG_ID'] = $this->_registration->ID();
2169
-            $template_path = REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_reg_questions.template.php';
2169
+            $template_path = REG_TEMPLATE_PATH.'reg_admin_details_main_meta_box_reg_questions.template.php';
2170 2170
             EEH_Template::display_template($template_path, $this->_template_args);
2171 2171
         }
2172 2172
     }
@@ -2182,7 +2182,7 @@  discard block
 block discarded – undo
2182 2182
     public function form_before_question_group($output)
2183 2183
     {
2184 2184
         EE_Error::doing_it_wrong(
2185
-            __CLASS__ . '::' . __FUNCTION__,
2185
+            __CLASS__.'::'.__FUNCTION__,
2186 2186
             esc_html__(
2187 2187
                 '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.',
2188 2188
                 'event_espresso'
@@ -2206,7 +2206,7 @@  discard block
 block discarded – undo
2206 2206
     public function form_after_question_group($output)
2207 2207
     {
2208 2208
         EE_Error::doing_it_wrong(
2209
-            __CLASS__ . '::' . __FUNCTION__,
2209
+            __CLASS__.'::'.__FUNCTION__,
2210 2210
             esc_html__(
2211 2211
                 '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.',
2212 2212
                 'event_espresso'
@@ -2243,7 +2243,7 @@  discard block
 block discarded – undo
2243 2243
     public function form_form_field_label_wrap($label)
2244 2244
     {
2245 2245
         EE_Error::doing_it_wrong(
2246
-            __CLASS__ . '::' . __FUNCTION__,
2246
+            __CLASS__.'::'.__FUNCTION__,
2247 2247
             esc_html__(
2248 2248
                 '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.',
2249 2249
                 'event_espresso'
@@ -2253,7 +2253,7 @@  discard block
 block discarded – undo
2253 2253
         return '
2254 2254
 			<tr>
2255 2255
 				<th>
2256
-					' . $label . '
2256
+					' . $label.'
2257 2257
 				</th>';
2258 2258
     }
2259 2259
 
@@ -2268,7 +2268,7 @@  discard block
 block discarded – undo
2268 2268
     public function form_form_field_input__wrap($input)
2269 2269
     {
2270 2270
         EE_Error::doing_it_wrong(
2271
-            __CLASS__ . '::' . __FUNCTION__,
2271
+            __CLASS__.'::'.__FUNCTION__,
2272 2272
             esc_html__(
2273 2273
                 '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.',
2274 2274
                 'event_espresso'
@@ -2277,7 +2277,7 @@  discard block
 block discarded – undo
2277 2277
         );
2278 2278
         return '
2279 2279
 				<td class="reg-admin-attendee-questions-input-td disabled-input">
2280
-					' . $input . '
2280
+					' . $input.'
2281 2281
 				</td>
2282 2282
 			</tr>';
2283 2283
     }
@@ -2326,8 +2326,8 @@  discard block
 block discarded – undo
2326 2326
      */
2327 2327
     protected function _get_reg_custom_questions_form($REG_ID)
2328 2328
     {
2329
-        if (! $this->_reg_custom_questions_form) {
2330
-            require_once(REG_ADMIN . 'form_sections/EE_Registration_Custom_Questions_Form.form.php');
2329
+        if ( ! $this->_reg_custom_questions_form) {
2330
+            require_once(REG_ADMIN.'form_sections/EE_Registration_Custom_Questions_Form.form.php');
2331 2331
             $this->_reg_custom_questions_form = new EE_Registration_Custom_Questions_Form(
2332 2332
                 $this->getRegistrationModel()->get_one_by_ID($REG_ID)
2333 2333
             );
@@ -2350,7 +2350,7 @@  discard block
 block discarded – undo
2350 2350
      */
2351 2351
     private function _save_reg_custom_questions_form($REG_ID = 0)
2352 2352
     {
2353
-        if (! $REG_ID) {
2353
+        if ( ! $REG_ID) {
2354 2354
             EE_Error::add_error(
2355 2355
                 esc_html__(
2356 2356
                     'An error occurred. No registration ID was received.',
@@ -2367,7 +2367,7 @@  discard block
 block discarded – undo
2367 2367
         if ($form->is_valid()) {
2368 2368
             foreach ($form->subforms() as $question_group_form) {
2369 2369
                 foreach ($question_group_form->inputs() as $question_id => $input) {
2370
-                    $where_conditions    = [
2370
+                    $where_conditions = [
2371 2371
                         'QST_ID' => $question_id,
2372 2372
                         'REG_ID' => $REG_ID,
2373 2373
                     ];
@@ -2408,7 +2408,7 @@  discard block
 block discarded – undo
2408 2408
         $REG = $this->getRegistrationModel();
2409 2409
         // get all other registrations on this transaction, and cache
2410 2410
         // the attendees for them so we don't have to run another query using force_join
2411
-        $registrations                           = $REG->get_all(
2411
+        $registrations = $REG->get_all(
2412 2412
             [
2413 2413
                 [
2414 2414
                     'TXN_ID' => $this->_registration->transaction_ID(),
@@ -2442,23 +2442,23 @@  discard block
 block discarded – undo
2442 2442
                 $attendee                                                      = $registration->attendee()
2443 2443
                     ? $registration->attendee()
2444 2444
                     : $this->getAttendeeModel()->create_default_object();
2445
-                $this->_template_args['attendees'][ $att_nmbr ]['STS_ID']      = $registration->status_ID();
2446
-                $this->_template_args['attendees'][ $att_nmbr ]['fname']       = $attendee->fname();
2447
-                $this->_template_args['attendees'][ $att_nmbr ]['lname']       = $attendee->lname();
2448
-                $this->_template_args['attendees'][ $att_nmbr ]['email']       = $attendee->email();
2449
-                $this->_template_args['attendees'][ $att_nmbr ]['final_price'] = $registration->final_price();
2450
-                $this->_template_args['attendees'][ $att_nmbr ]['address']     = implode(
2445
+                $this->_template_args['attendees'][$att_nmbr]['STS_ID']      = $registration->status_ID();
2446
+                $this->_template_args['attendees'][$att_nmbr]['fname']       = $attendee->fname();
2447
+                $this->_template_args['attendees'][$att_nmbr]['lname']       = $attendee->lname();
2448
+                $this->_template_args['attendees'][$att_nmbr]['email']       = $attendee->email();
2449
+                $this->_template_args['attendees'][$att_nmbr]['final_price'] = $registration->final_price();
2450
+                $this->_template_args['attendees'][$att_nmbr]['address']     = implode(
2451 2451
                     ', ',
2452 2452
                     $attendee->full_address_as_array()
2453 2453
                 );
2454
-                $this->_template_args['attendees'][ $att_nmbr ]['att_link']    = self::add_query_args_and_nonce(
2454
+                $this->_template_args['attendees'][$att_nmbr]['att_link'] = self::add_query_args_and_nonce(
2455 2455
                     [
2456 2456
                         'action' => 'edit_attendee',
2457 2457
                         'post'   => $attendee->ID(),
2458 2458
                     ],
2459 2459
                     REG_ADMIN_URL
2460 2460
                 );
2461
-                $this->_template_args['attendees'][ $att_nmbr ]['event_name']  =
2461
+                $this->_template_args['attendees'][$att_nmbr]['event_name'] =
2462 2462
                     $registration->event_obj() instanceof EE_Event
2463 2463
                         ? $registration->event_obj()->name()
2464 2464
                         : '';
@@ -2466,7 +2466,7 @@  discard block
 block discarded – undo
2466 2466
             }
2467 2467
             $this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
2468 2468
         }
2469
-        $template_path = REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_attendees.template.php';
2469
+        $template_path = REG_TEMPLATE_PATH.'reg_admin_details_main_meta_box_attendees.template.php';
2470 2470
         EEH_Template::display_template($template_path, $this->_template_args);
2471 2471
     }
2472 2472
 
@@ -2492,11 +2492,11 @@  discard block
 block discarded – undo
2492 2492
         // now let's determine if this is not the primary registration.  If it isn't then we set the
2493 2493
         // primary_registration object for reference BUT ONLY if the Attendee object loaded is not the same as the
2494 2494
         // primary registration object (that way we know if we need to show create button or not)
2495
-        if (! $this->_registration->is_primary_registrant()) {
2495
+        if ( ! $this->_registration->is_primary_registrant()) {
2496 2496
             $primary_registration = $this->_registration->get_primary_registration();
2497 2497
             $primary_attendee     = $primary_registration instanceof EE_Registration ? $primary_registration->attendee()
2498 2498
                 : null;
2499
-            if (! $primary_attendee instanceof EE_Attendee || $attendee->ID() !== $primary_attendee->ID()) {
2499
+            if ( ! $primary_attendee instanceof EE_Attendee || $attendee->ID() !== $primary_attendee->ID()) {
2500 2500
                 // in here?  This means the displayed registration is not the primary registrant but ALREADY HAS its own
2501 2501
                 // custom attendee object so let's not worry about the primary reg.
2502 2502
                 $primary_registration = null;
@@ -2511,7 +2511,7 @@  discard block
 block discarded – undo
2511 2511
         $this->_template_args['phone']             = $attendee->phone();
2512 2512
         $this->_template_args['formatted_address'] = EEH_Address::format($attendee);
2513 2513
         // edit link
2514
-        $this->_template_args['att_edit_link']  = EE_Admin_Page::add_query_args_and_nonce(
2514
+        $this->_template_args['att_edit_link'] = EE_Admin_Page::add_query_args_and_nonce(
2515 2515
             [
2516 2516
                 'action' => 'edit_attendee',
2517 2517
                 'post'   => $attendee->ID(),
@@ -2521,7 +2521,7 @@  discard block
 block discarded – undo
2521 2521
         $this->_template_args['att_edit_title'] = esc_html__('View details for this contact.', 'event_espresso');
2522 2522
         $this->_template_args['att_edit_label'] = esc_html__('View/Edit Contact', 'event_espresso');
2523 2523
         // create link
2524
-        $this->_template_args['create_link']  = $primary_registration instanceof EE_Registration
2524
+        $this->_template_args['create_link'] = $primary_registration instanceof EE_Registration
2525 2525
             ? EE_Admin_Page::add_query_args_and_nonce(
2526 2526
                 [
2527 2527
                     'action'  => 'duplicate_attendee',
@@ -2531,7 +2531,7 @@  discard block
 block discarded – undo
2531 2531
             ) : '';
2532 2532
         $this->_template_args['create_label'] = esc_html__('Create Contact', 'event_espresso');
2533 2533
         $this->_template_args['att_check'] = $att_check;
2534
-        $template_path = REG_TEMPLATE_PATH . 'reg_admin_details_side_meta_box_registrant.template.php';
2534
+        $template_path = REG_TEMPLATE_PATH.'reg_admin_details_side_meta_box_registrant.template.php';
2535 2535
         EEH_Template::display_template($template_path, $this->_template_args);
2536 2536
     }
2537 2537
 
@@ -2575,7 +2575,7 @@  discard block
 block discarded – undo
2575 2575
             /** @var EE_Registration $REG */
2576 2576
             $REG      = $this->getRegistrationModel()->get_one_by_ID($REG_ID);
2577 2577
             $payments = $REG->registration_payments();
2578
-            if (! empty($payments)) {
2578
+            if ( ! empty($payments)) {
2579 2579
                 $name           = $REG->attendee() instanceof EE_Attendee
2580 2580
                     ? $REG->attendee()->full_name()
2581 2581
                     : esc_html__('Unknown Attendee', 'event_espresso');
@@ -2639,17 +2639,17 @@  discard block
 block discarded – undo
2639 2639
         // Checkboxes
2640 2640
         $REG_IDs = $this->request->getRequestParam('_REG_ID', [], 'int', true);
2641 2641
 
2642
-        if (! empty($REG_IDs)) {
2642
+        if ( ! empty($REG_IDs)) {
2643 2643
             // if array has more than one element than success message should be plural
2644 2644
             $success = count($REG_IDs) > 1 ? 2 : 1;
2645 2645
             // cycle thru checkboxes
2646 2646
             foreach ($REG_IDs as $REG_ID) {
2647 2647
                 $REG = $REG_MDL->get_one_by_ID($REG_ID);
2648
-                if (! $REG instanceof EE_Registration) {
2648
+                if ( ! $REG instanceof EE_Registration) {
2649 2649
                     continue;
2650 2650
                 }
2651 2651
                 $deleted = $this->_delete_registration($REG);
2652
-                if (! $deleted) {
2652
+                if ( ! $deleted) {
2653 2653
                     $success = 0;
2654 2654
                 }
2655 2655
             }
@@ -2686,7 +2686,7 @@  discard block
 block discarded – undo
2686 2686
         // first we start with the transaction... ultimately, we WILL not delete permanently if there are any related
2687 2687
         // registrations on the transaction that are NOT trashed.
2688 2688
         $TXN = $REG->get_first_related('Transaction');
2689
-        if (! $TXN instanceof EE_Transaction) {
2689
+        if ( ! $TXN instanceof EE_Transaction) {
2690 2690
             EE_Error::add_error(
2691 2691
                 sprintf(
2692 2692
                     esc_html__(
@@ -2704,11 +2704,11 @@  discard block
 block discarded – undo
2704 2704
         $REGS        = $TXN->get_many_related('Registration');
2705 2705
         $all_trashed = true;
2706 2706
         foreach ($REGS as $registration) {
2707
-            if (! $registration->get('REG_deleted')) {
2707
+            if ( ! $registration->get('REG_deleted')) {
2708 2708
                 $all_trashed = false;
2709 2709
             }
2710 2710
         }
2711
-        if (! $all_trashed) {
2711
+        if ( ! $all_trashed) {
2712 2712
             EE_Error::add_error(
2713 2713
                 esc_html__(
2714 2714
                     '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.',
@@ -2770,7 +2770,7 @@  discard block
 block discarded – undo
2770 2770
      */
2771 2771
     public function new_registration()
2772 2772
     {
2773
-        if (! $this->_set_reg_event()) {
2773
+        if ( ! $this->_set_reg_event()) {
2774 2774
             throw new EE_Error(
2775 2775
                 esc_html__(
2776 2776
                     'Unable to continue with registering because there is no Event ID in the request',
@@ -2802,7 +2802,7 @@  discard block
 block discarded – undo
2802 2802
                 ],
2803 2803
                 EVENTS_ADMIN_URL
2804 2804
             );
2805
-            $edit_event_lnk                     = '<a href="'
2805
+            $edit_event_lnk = '<a href="'
2806 2806
                                                   . $edit_event_url
2807 2807
                                                   . '" title="'
2808 2808
                                                   . esc_attr__('Edit ', 'event_espresso')
@@ -2819,7 +2819,7 @@  discard block
 block discarded – undo
2819 2819
             $this->_return_json();
2820 2820
         }
2821 2821
         // grab header
2822
-        $template_path = REG_TEMPLATE_PATH . 'reg_admin_register_new_attendee.template.php';
2822
+        $template_path = REG_TEMPLATE_PATH.'reg_admin_register_new_attendee.template.php';
2823 2823
         $this->_template_args['admin_page_content'] = EEH_Template::display_template(
2824 2824
             $template_path,
2825 2825
             $this->_template_args,
@@ -2860,7 +2860,7 @@  discard block
 block discarded – undo
2860 2860
                 '</b>'
2861 2861
             );
2862 2862
             return '
2863
-	<div id="ee-add-reg-back-button-dv"><p>' . $warning_msg . '</p></div>
2863
+	<div id="ee-add-reg-back-button-dv"><p>' . $warning_msg.'</p></div>
2864 2864
 	<script >
2865 2865
 		// WHOAH !!! it appears that someone is using the back button from the Transaction admin page
2866 2866
 		// after just adding a new registration... we gotta try to put a stop to that !!!
@@ -2927,7 +2927,7 @@  discard block
 block discarded – undo
2927 2927
         // we come back to the process_registration_step route.
2928 2928
         $this->_set_add_edit_form_tags('process_reg_step', $hidden_fields);
2929 2929
         return EEH_Template::display_template(
2930
-            REG_TEMPLATE_PATH . 'reg_admin_register_new_attendee_step_content.template.php',
2930
+            REG_TEMPLATE_PATH.'reg_admin_register_new_attendee_step_content.template.php',
2931 2931
             $template_args,
2932 2932
             true
2933 2933
         );
@@ -2950,7 +2950,7 @@  discard block
 block discarded – undo
2950 2950
         }
2951 2951
 
2952 2952
         $EVT_ID = $this->request->getRequestParam('event_id', 0, 'int');
2953
-        if (! $EVT_ID) {
2953
+        if ( ! $EVT_ID) {
2954 2954
             return false;
2955 2955
         }
2956 2956
         $this->_reg_event = $this->getEventModel()->get_one_by_ID($EVT_ID);
@@ -3020,7 +3020,7 @@  discard block
 block discarded – undo
3020 3020
                 }
3021 3021
                 break;
3022 3022
             case 'questions':
3023
-                if (! $this->request->requestParamIsSet('txn_reg_status_change[send_notifications]')) {
3023
+                if ( ! $this->request->requestParamIsSet('txn_reg_status_change[send_notifications]')) {
3024 3024
                     add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_false', 15);
3025 3025
                 }
3026 3026
                 // process registration
@@ -3031,7 +3031,7 @@  discard block
 block discarded – undo
3031 3031
                         $grand_total->save_this_and_descendants_to_txn();
3032 3032
                     }
3033 3033
                 }
3034
-                if (! $transaction instanceof EE_Transaction) {
3034
+                if ( ! $transaction instanceof EE_Transaction) {
3035 3035
                     $query_args = [
3036 3036
                         'action'                  => 'new_registration',
3037 3037
                         'processing_registration' => 2,
@@ -3053,7 +3053,7 @@  discard block
 block discarded – undo
3053 3053
                     return;
3054 3054
                 }
3055 3055
                 // maybe update status, and make sure to save transaction if not done already
3056
-                if (! $transaction->update_status_based_on_total_paid()) {
3056
+                if ( ! $transaction->update_status_based_on_total_paid()) {
3057 3057
                     $transaction->save();
3058 3058
                 }
3059 3059
                 EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
@@ -3135,7 +3135,7 @@  discard block
 block discarded – undo
3135 3135
     public function get_attendees($per_page, $count = false, $trash = false)
3136 3136
     {
3137 3137
         do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3138
-        require_once(REG_ADMIN . 'EE_Attendee_Contact_List_Table.class.php');
3138
+        require_once(REG_ADMIN.'EE_Attendee_Contact_List_Table.class.php');
3139 3139
         $orderby = $this->request->getRequestParam('orderby');
3140 3140
         switch ($orderby) {
3141 3141
             case 'ATT_ID':
@@ -3158,7 +3158,7 @@  discard block
 block discarded – undo
3158 3158
         $_where       = [];
3159 3159
         $search_term  = $this->request->getRequestParam('s');
3160 3160
         if ($search_term) {
3161
-            $search_term  = '%' . $search_term . '%';
3161
+            $search_term  = '%'.$search_term.'%';
3162 3162
             $_where['OR'] = [
3163 3163
                 'Registration.Event.EVT_name'       => ['LIKE', $search_term],
3164 3164
                 'Registration.Event.EVT_desc'       => ['LIKE', $search_term],
@@ -3185,7 +3185,7 @@  discard block
 block discarded – undo
3185 3185
             'extra_selects' => ['Registration_Count' => ['Registration.REG_ID', 'count', '%d']],
3186 3186
             'limit'         => $limit,
3187 3187
         ];
3188
-        if (! $count) {
3188
+        if ( ! $count) {
3189 3189
             $query_args['order_by'] = [$orderby => $sort];
3190 3190
         }
3191 3191
         $query_args[0]['status'] = $trash ? ['!=', 'publish'] : ['IN', ['publish']];
@@ -3230,7 +3230,7 @@  discard block
 block discarded – undo
3230 3230
         $EVT_ID = $this->request->requestParamIsSet('EVT_ID')
3231 3231
             ? $this->request->getRequestParam('EVT_ID', 0, DataType::INT)
3232 3232
             : null;
3233
-        if (! defined('EE_USE_OLD_CSV_REPORT_CLASS')) {
3233
+        if ( ! defined('EE_USE_OLD_CSV_REPORT_CLASS')) {
3234 3234
             $return_url = $this->request->getRequestParam('return_url', '', DataType::URL);
3235 3235
             $filters = $this->request->getRequestParam('filters', [], DataType::STRING, true);
3236 3236
             $use_filters = $this->request->getRequestParam('use_filters', false, DataType::BOOL);
@@ -3258,8 +3258,8 @@  discard block
 block discarded – undo
3258 3258
             ];
3259 3259
             // Merge required request args, overriding any currently set
3260 3260
             $request_args = array_merge($request_args, $required_request_args);
3261
-            if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3262
-                require_once(EE_CLASSES . 'EE_Export.class.php');
3261
+            if (is_readable(EE_CLASSES.'EE_Export.class.php')) {
3262
+                require_once(EE_CLASSES.'EE_Export.class.php');
3263 3263
                 $EE_Export = EE_Export::instance($request_args);
3264 3264
                 $EE_Export->export();
3265 3265
             }
@@ -3280,8 +3280,8 @@  discard block
 block discarded – undo
3280 3280
 
3281 3281
     public function _contact_list_export()
3282 3282
     {
3283
-        if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3284
-            require_once(EE_CLASSES . 'EE_Export.class.php');
3283
+        if (is_readable(EE_CLASSES.'EE_Export.class.php')) {
3284
+            require_once(EE_CLASSES.'EE_Export.class.php');
3285 3285
             $EE_Export = EE_Export::instance($this->request->requestParams());
3286 3286
             $EE_Export->export_attendees();
3287 3287
         }
@@ -3290,7 +3290,7 @@  discard block
 block discarded – undo
3290 3290
 
3291 3291
     public function _contact_list_report()
3292 3292
     {
3293
-        if (! defined('EE_USE_OLD_CSV_REPORT_CLASS')) {
3293
+        if ( ! defined('EE_USE_OLD_CSV_REPORT_CLASS')) {
3294 3294
             wp_redirect(
3295 3295
                 EE_Admin_Page::add_query_args_and_nonce(
3296 3296
                     [
@@ -3302,8 +3302,8 @@  discard block
 block discarded – undo
3302 3302
                 )
3303 3303
             );
3304 3304
         } else {
3305
-            if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3306
-                require_once(EE_CLASSES . 'EE_Export.class.php');
3305
+            if (is_readable(EE_CLASSES.'EE_Export.class.php')) {
3306
+                require_once(EE_CLASSES.'EE_Export.class.php');
3307 3307
                 $EE_Export = EE_Export::instance($this->request->requestParams());
3308 3308
                 $EE_Export->report_attendees();
3309 3309
             }
@@ -3330,7 +3330,7 @@  discard block
 block discarded – undo
3330 3330
         $REG_ID = $this->request->getRequestParam('_REG_ID', 0, 'int');
3331 3331
         $action = $this->request->getRequestParam('return', 'default');
3332 3332
         // verify we have necessary info
3333
-        if (! $REG_ID) {
3333
+        if ( ! $REG_ID) {
3334 3334
             EE_Error::add_error(
3335 3335
                 esc_html__(
3336 3336
                     'Unable to create the contact for the registration because the required parameters are not present (_REG_ID )',
@@ -3345,7 +3345,7 @@  discard block
 block discarded – undo
3345 3345
         }
3346 3346
         // okay necessary deets present... let's dupe the incoming attendee and attach to incoming registration.
3347 3347
         $registration = $this->getRegistrationModel()->get_one_by_ID($REG_ID);
3348
-        if (! $registration instanceof EE_Registration) {
3348
+        if ( ! $registration instanceof EE_Registration) {
3349 3349
             throw new RuntimeException(
3350 3350
                 sprintf(
3351 3351
                     esc_html__(
@@ -3484,16 +3484,16 @@  discard block
 block discarded – undo
3484 3484
         $this->verify_cpt_object();
3485 3485
         remove_meta_box(
3486 3486
             'postexcerpt',
3487
-            $this->_cpt_routes[ $this->_req_action ],
3487
+            $this->_cpt_routes[$this->_req_action],
3488 3488
             'normal'
3489 3489
         );
3490
-        remove_meta_box('commentstatusdiv', $this->_cpt_routes[ $this->_req_action ], 'normal');
3490
+        remove_meta_box('commentstatusdiv', $this->_cpt_routes[$this->_req_action], 'normal');
3491 3491
         if (post_type_supports('espresso_attendees', 'excerpt')) {
3492 3492
             $this->addMetaBox(
3493 3493
                 'postexcerpt',
3494 3494
                 esc_html__('Short Biography', 'event_espresso'),
3495 3495
                 'post_excerpt_meta_box',
3496
-                $this->_cpt_routes[ $this->_req_action ]
3496
+                $this->_cpt_routes[$this->_req_action]
3497 3497
             );
3498 3498
         }
3499 3499
         if (post_type_supports('espresso_attendees', 'comments')) {
@@ -3501,7 +3501,7 @@  discard block
 block discarded – undo
3501 3501
                 'commentsdiv',
3502 3502
                 esc_html__('Notes on the Contact', 'event_espresso'),
3503 3503
                 'post_comment_meta_box',
3504
-                $this->_cpt_routes[ $this->_req_action ],
3504
+                $this->_cpt_routes[$this->_req_action],
3505 3505
                 'normal',
3506 3506
                 'core'
3507 3507
             );
@@ -3510,7 +3510,7 @@  discard block
 block discarded – undo
3510 3510
             'attendee_contact_info',
3511 3511
             esc_html__('Contact Info', 'event_espresso'),
3512 3512
             [$this, 'attendee_contact_info'],
3513
-            $this->_cpt_routes[ $this->_req_action ],
3513
+            $this->_cpt_routes[$this->_req_action],
3514 3514
             'side',
3515 3515
             'core'
3516 3516
         );
@@ -3518,7 +3518,7 @@  discard block
 block discarded – undo
3518 3518
             'attendee_details_address',
3519 3519
             esc_html__('Address Details', 'event_espresso'),
3520 3520
             [$this, 'attendee_address_details'],
3521
-            $this->_cpt_routes[ $this->_req_action ],
3521
+            $this->_cpt_routes[$this->_req_action],
3522 3522
             'normal',
3523 3523
             'core'
3524 3524
         );
@@ -3526,7 +3526,7 @@  discard block
 block discarded – undo
3526 3526
             'attendee_registrations',
3527 3527
             esc_html__('Registrations for this Contact', 'event_espresso'),
3528 3528
             [$this, 'attendee_registrations_meta_box'],
3529
-            $this->_cpt_routes[ $this->_req_action ]
3529
+            $this->_cpt_routes[$this->_req_action]
3530 3530
         );
3531 3531
     }
3532 3532
 
@@ -3625,7 +3625,7 @@  discard block
 block discarded – undo
3625 3625
                 ]
3626 3626
             )
3627 3627
         );
3628
-        $template = REG_TEMPLATE_PATH . 'attendee_address_details_metabox_content.template.php';
3628
+        $template = REG_TEMPLATE_PATH.'attendee_address_details_metabox_content.template.php';
3629 3629
         EEH_Template::display_template($template, $this->_template_args);
3630 3630
     }
3631 3631
 
@@ -3646,7 +3646,7 @@  discard block
 block discarded – undo
3646 3646
     {
3647 3647
         $this->_template_args['attendee']      = $this->_cpt_model_obj;
3648 3648
         $this->_template_args['registrations'] = $this->_cpt_model_obj->get_many_related('Registration');
3649
-        $template = REG_TEMPLATE_PATH . 'attendee_registrations_main_meta_box.template.php';
3649
+        $template = REG_TEMPLATE_PATH.'attendee_registrations_main_meta_box.template.php';
3650 3650
         EEH_Template::display_template($template, $this->_template_args);
3651 3651
     }
3652 3652
 
@@ -3661,7 +3661,7 @@  discard block
 block discarded – undo
3661 3661
     public function after_title_form_fields($post)
3662 3662
     {
3663 3663
         if ($post->post_type === 'espresso_attendees') {
3664
-            $template                  = REG_TEMPLATE_PATH . 'attendee_details_after_title_form_fields.template.php';
3664
+            $template                  = REG_TEMPLATE_PATH.'attendee_details_after_title_form_fields.template.php';
3665 3665
             $template_args['attendee'] = $this->_cpt_model_obj;
3666 3666
             EEH_Template::display_template($template, $template_args);
3667 3667
         }
@@ -3690,7 +3690,7 @@  discard block
 block discarded – undo
3690 3690
             // cycle thru checkboxes
3691 3691
             foreach ($ATT_IDs as $ATT_ID) {
3692 3692
                 $updated = $this->getAttendeeModel()->update_by_ID(['status' => $status], $ATT_ID);
3693
-                if (! $updated) {
3693
+                if ( ! $updated) {
3694 3694
                     $success = 0;
3695 3695
                 }
3696 3696
             }
Please login to merge, or discard this patch.
admin_pages/payments/Payments_Admin_Page.core.php 1 patch
Indentation   +1205 added lines, -1205 removed lines patch added patch discarded remove patch
@@ -16,1209 +16,1209 @@
 block discarded – undo
16 16
  */
17 17
 class Payments_Admin_Page extends EE_Admin_Page
18 18
 {
19
-    /**
20
-     * Variables used for when we're re-sorting the logs results,
21
-     * in case we needed to do two queries, and we need to resort
22
-     *
23
-     * @var string
24
-     */
25
-    private $_sort_logs_again_direction;
26
-
27
-
28
-    /**
29
-     * @Constructor
30
-     * @access public
31
-     * @param bool $routing indicate whether we want to just load the object and handle routing or just load the object.
32
-     * @throws EE_Error
33
-     * @throws InvalidArgumentException
34
-     * @throws InvalidDataTypeException
35
-     * @throws InvalidInterfaceException
36
-     * @throws ReflectionException
37
-     */
38
-    public function __construct($routing = true)
39
-    {
40
-        parent::__construct($routing);
41
-    }
42
-
43
-
44
-    protected function _init_page_props()
45
-    {
46
-        $this->page_slug = EE_PAYMENTS_PG_SLUG;
47
-        $this->page_label = esc_html__('Payment Methods', 'event_espresso');
48
-        $this->_admin_base_url = EE_PAYMENTS_ADMIN_URL;
49
-        $this->_admin_base_path = EE_PAYMENTS_ADMIN;
50
-    }
51
-
52
-
53
-    protected function _ajax_hooks()
54
-    {
55
-        // todo: all hooks for ajax goes here.
56
-    }
57
-
58
-
59
-    protected function _define_page_props()
60
-    {
61
-        $this->_admin_page_title = $this->page_label;
62
-        $this->_labels = array(
63
-            'publishbox' => esc_html__('Update Settings', 'event_espresso'),
64
-        );
65
-    }
66
-
67
-
68
-    protected function _set_page_routes()
69
-    {
70
-        /**
71
-         * note that with payment method capabilities, although we've implemented
72
-         * capability mapping which will be used for accessing payment methods owned by
73
-         * other users.  This is not fully implemented yet in the payment method ui.
74
-         * Currently, only the "plural" caps are in active use.
75
-         * When cap mapping is implemented, some routes will need to use the singular form of
76
-         * capability method and also include the $id of the payment method for the route.
77
-         **/
78
-        $this->_page_routes = array(
79
-            'default'                   => array(
80
-                'func'       => '_payment_methods_list',
81
-                'capability' => 'ee_edit_payment_methods',
82
-            ),
83
-            'payment_settings'          => array(
84
-                'func'       => '_payment_settings',
85
-                'capability' => 'ee_manage_gateways',
86
-            ),
87
-            'activate_payment_method'   => array(
88
-                'func'       => '_activate_payment_method',
89
-                'noheader'   => true,
90
-                'capability' => 'ee_edit_payment_methods',
91
-            ),
92
-            'deactivate_payment_method' => array(
93
-                'func'       => '_deactivate_payment_method',
94
-                'noheader'   => true,
95
-                'capability' => 'ee_delete_payment_methods',
96
-            ),
97
-            'update_payment_method'     => array(
98
-                'func'               => '_update_payment_method',
99
-                'noheader'           => true,
100
-                'headers_sent_route' => 'default',
101
-                'capability'         => 'ee_edit_payment_methods',
102
-            ),
103
-            'update_payment_settings'   => array(
104
-                'func'       => '_update_payment_settings',
105
-                'noheader'   => true,
106
-                'capability' => 'ee_manage_gateways',
107
-            ),
108
-            'payment_log'               => array(
109
-                'func'       => '_payment_log_overview_list_table',
110
-                'capability' => 'ee_read_payment_methods',
111
-            ),
112
-            'payment_log_details'       => array(
113
-                'func'       => '_payment_log_details',
114
-                'capability' => 'ee_read_payment_methods',
115
-            ),
116
-        );
117
-    }
118
-
119
-
120
-    /**
121
-     * @throws EE_Error
122
-     * @throws ReflectionException
123
-     */
124
-    protected function _set_page_config()
125
-    {
126
-        $payment_method_list_config = array(
127
-            'nav'           => array(
128
-                'label' => esc_html__('Payment Methods', 'event_espresso'),
129
-                'icon' => 'dashicons-bank',
130
-                'order' => 10,
131
-            ),
132
-            'metaboxes'     => $this->_default_espresso_metaboxes,
133
-            'help_tabs'     => array_merge(
134
-                array(
135
-                    'payment_methods_overview_help_tab' => array(
136
-                        'title'    => esc_html__('Payment Methods Overview', 'event_espresso'),
137
-                        'filename' => 'payment_methods_overview',
138
-                    ),
139
-                ),
140
-                $this->_add_payment_method_help_tabs()
141
-            ),
142
-            'require_nonce' => false,
143
-        );
144
-        $this->_page_config = array(
145
-            'default'          => $payment_method_list_config,
146
-            'payment_settings' => array(
147
-                'nav'           => array(
148
-                    'label' => esc_html__('Settings', 'event_espresso'),
149
-                    'icon' => 'dashicons-admin-generic',
150
-                    'order' => 20,
151
-                ),
152
-                'help_tabs'     => array(
153
-                    'payment_methods_settings_help_tab' => array(
154
-                        'title'    => esc_html__('Payment Method Settings', 'event_espresso'),
155
-                        'filename' => 'payment_methods_settings',
156
-                    ),
157
-                ),
158
-                'metaboxes'     => array_merge($this->_default_espresso_metaboxes, array('_publish_post_box')),
159
-                'require_nonce' => false,
160
-            ),
161
-            'payment_log'      => array(
162
-                'nav'           => array(
163
-                    'label' => esc_html__("Logs", 'event_espresso'),
164
-                    'icon' => 'dashicons-text-page',
165
-                    'order' => 30,
166
-                ),
167
-                'list_table'    => 'Payment_Log_Admin_List_Table',
168
-                'metaboxes'     => $this->_default_espresso_metaboxes,
169
-                'require_nonce' => false,
170
-            ),
171
-        );
172
-    }
173
-
174
-
175
-    /**
176
-     * @return array
177
-     * @throws DomainException
178
-     * @throws EE_Error
179
-     * @throws InvalidArgumentException
180
-     * @throws InvalidDataTypeException
181
-     * @throws InvalidInterfaceException
182
-     * @throws ReflectionException
183
-     */
184
-    protected function _add_payment_method_help_tabs()
185
-    {
186
-        EE_Registry::instance()->load_lib('Payment_Method_Manager');
187
-        $payment_method_types = EE_Payment_Method_Manager::instance()->payment_method_types();
188
-        $all_pmt_help_tabs_config = array();
189
-        foreach ($payment_method_types as $payment_method_type) {
190
-            if (
191
-                ! EE_Registry::instance()->CAP->current_user_can(
192
-                    $payment_method_type->cap_name(),
193
-                    'specific_payment_method_type_access'
194
-                )
195
-            ) {
196
-                continue;
197
-            }
198
-            foreach ($payment_method_type->help_tabs_config() as $help_tab_name => $config) {
199
-                $template_args = isset($config['template_args']) ? $config['template_args'] : array();
200
-                $template_args['admin_page_obj'] = $this;
201
-                $all_pmt_help_tabs_config[ $help_tab_name ] = array(
202
-                    'title'   => $config['title'],
203
-                    'content' => EEH_Template::display_template(
204
-                        $payment_method_type->file_folder() . 'help_tabs/' . $config['filename'] . '.help_tab.php',
205
-                        $template_args,
206
-                        true
207
-                    ),
208
-                );
209
-            }
210
-        }
211
-        return $all_pmt_help_tabs_config;
212
-    }
213
-
214
-
215
-    // none of the below group are currently used for Gateway Settings
216
-    protected function _add_screen_options()
217
-    {
218
-    }
219
-
220
-
221
-    protected function _add_feature_pointers()
222
-    {
223
-    }
224
-
225
-
226
-    public function admin_init()
227
-    {
228
-    }
229
-
230
-
231
-    public function admin_notices()
232
-    {
233
-    }
234
-
235
-
236
-    public function admin_footer_scripts()
237
-    {
238
-    }
239
-
240
-
241
-    public function load_scripts_styles()
242
-    {
243
-        // styles
244
-        wp_enqueue_style('espresso-ui-theme');
245
-        wp_register_style(
246
-            'espresso_payments',
247
-            EE_PAYMENTS_ASSETS_URL . 'ee-payments.css',
248
-            [],
249
-            EVENT_ESPRESSO_VERSION
250
-        );
251
-        // scripts
252
-        wp_enqueue_script('ee_admin_js');
253
-        wp_enqueue_script('ee-text-links');
254
-        wp_enqueue_script(
255
-            'espresso_payments',
256
-            EE_PAYMENTS_ASSETS_URL . 'espresso_payments_admin.js',
257
-            ['ee-datepicker'],
258
-            EVENT_ESPRESSO_VERSION,
259
-            true
260
-        );
261
-    }
262
-
263
-
264
-    public function load_scripts_styles_default()
265
-    {
266
-        wp_enqueue_style('espresso_payments');
267
-        wp_enqueue_style('ee-text-links');
268
-    }
269
-
270
-
271
-    public function load_scripts_styles_payment_log_details()
272
-    {
273
-        wp_enqueue_style('espresso_payments');
274
-    }
275
-
276
-
277
-    /**
278
-     * @throws EE_Error
279
-     * @throws ReflectionException
280
-     */
281
-    protected function _payment_methods_list()
282
-    {
283
-        /**
284
-         * first let's ensure payment methods have been set up.
285
-         * We do this here because when people activate a payment method for the first time (as an addon),
286
-         * it may not set up its capabilities or get registered correctly due to the loading process.
287
-         * However, people MUST set up the details for the payment method,
288
-         * so it's safe to do a recheck here.
289
-         */
290
-        EE_Registry::instance()->load_lib('Payment_Method_Manager');
291
-        EEM_Payment_Method::instance()->verify_button_urls();
292
-        // set up tabs, one for each payment method type
293
-        $tabs = array();
294
-        $payment_methods = array();
295
-        foreach (EE_Payment_Method_Manager::instance()->payment_method_types() as $pmt_obj) {
296
-            // we don't want to show admin-only PMTs for now
297
-            if ($pmt_obj instanceof EE_PMT_Admin_Only) {
298
-                continue;
299
-            }
300
-            // check access
301
-            if (
302
-                ! EE_Registry::instance()->CAP->current_user_can(
303
-                    $pmt_obj->cap_name(),
304
-                    'specific_payment_method_type_access'
305
-                )
306
-            ) {
307
-                continue;
308
-            }
309
-            // check for any active pms of that type
310
-            $payment_method = EEM_Payment_Method::instance()->get_one_of_type($pmt_obj->system_name());
311
-            if (! $payment_method instanceof EE_Payment_Method) {
312
-                $payment_method = EE_Payment_Method::new_instance(
313
-                    array(
314
-                        'PMD_slug'       => sanitize_key($pmt_obj->system_name()),
315
-                        'PMD_type'       => $pmt_obj->system_name(),
316
-                        'PMD_name'       => $pmt_obj->pretty_name(),
317
-                        'PMD_admin_name' => $pmt_obj->pretty_name(),
318
-                    )
319
-                );
320
-            }
321
-            $payment_methods[ $payment_method->slug() ] = $payment_method;
322
-        }
323
-        $payment_methods = apply_filters(
324
-            'FHEE__Payments_Admin_Page___payment_methods_list__payment_methods',
325
-            $payment_methods
326
-        );
327
-        foreach ($payment_methods as $payment_method) {
328
-            if ($payment_method instanceof EE_Payment_Method) {
329
-                $this->addMetaBox(
330
-                    // html id
331
-                    'espresso_' . $payment_method->slug() . '_payment_settings',
332
-                    // title
333
-                    sprintf(esc_html__('%s Settings', 'event_espresso'), $payment_method->admin_name()),
334
-                    // callback
335
-                    array($this, 'payment_method_settings_meta_box'),
336
-                    // post type
337
-                    null,
338
-                    // context
339
-                    'normal',
340
-                    // priority
341
-                    'default',
342
-                    // callback args
343
-                    array('payment_method' => $payment_method)
344
-                );
345
-                // setup for tabbed content
346
-                $tabs[ $payment_method->slug() ] = array(
347
-                    'label' => $payment_method->admin_name(),
348
-                    'class' => $payment_method->active() ? 'gateway-active' : '',
349
-                    'href'  => 'espresso_' . $payment_method->slug() . '_payment_settings',
350
-                    'title' => esc_html__('Modify this Payment Method', 'event_espresso'),
351
-                    'slug'  => $payment_method->slug(),
352
-                    'icon'  => $payment_method->active()
353
-                        ? '<span class="dashicons dashicons-yes-alt"></span>'
354
-                        : '<span class="dashicons dashicons-remove"></span>',
355
-                );
356
-            }
357
-        }
358
-        $this->_template_args['admin_page_header'] = EEH_Tabbed_Content::tab_text_links(
359
-            $tabs,
360
-            'payment_method_links',
361
-            '',
362
-            $this->_get_active_payment_method_slug()
363
-        );
364
-        $this->display_admin_page_with_sidebar();
365
-    }
366
-
367
-
368
-    /**
369
-     *   _get_active_payment_method_slug
370
-     *
371
-     * @return string
372
-     * @throws EE_Error
373
-     */
374
-    protected function _get_active_payment_method_slug()
375
-    {
376
-        $payment_method_slug = false;
377
-        // decide which payment method tab to open first, as dictated by the request's 'payment_method'
378
-        if (isset($this->_req_data['payment_method'])) {
379
-            // if they provided the current payment method, use it
380
-            $payment_method_slug = sanitize_key($this->_req_data['payment_method']);
381
-        }
382
-        /** @var EE_Payment_Method $payment_method */
383
-        $payment_method = EEM_Payment_Method::instance()->get_one(array(array('PMD_slug' => $payment_method_slug)));
384
-        // if that didn't work or wasn't provided, find another way to select the current pm
385
-        if (! $this->_verify_payment_method($payment_method)) {
386
-            // like, looking for an active one
387
-            $payment_method = EEM_Payment_Method::instance()->get_one_active('CART');
388
-            // test that one as well
389
-            if ($this->_verify_payment_method($payment_method)) {
390
-                $payment_method_slug = $payment_method->slug();
391
-            } else {
392
-                $payment_method_slug = 'paypal_standard';
393
-            }
394
-        }
395
-        return $payment_method_slug;
396
-    }
397
-
398
-
399
-    /**
400
-     *    payment_method_settings_meta_box
401
-     *    returns TRUE if the passed payment method is properly constructed and the logged-in user has the correct
402
-     *    capabilities to access it
403
-     *
404
-     * @param EE_Payment_Method $payment_method
405
-     * @return boolean
406
-     * @throws EE_Error
407
-     */
408
-    protected function _verify_payment_method($payment_method)
409
-    {
410
-        if (
411
-            $payment_method instanceof EE_Payment_Method && $payment_method->type_obj() instanceof EE_PMT_Base
412
-            && EE_Registry::instance()->CAP->current_user_can(
413
-                $payment_method->type_obj()->cap_name(),
414
-                'specific_payment_method_type_access'
415
-            )
416
-        ) {
417
-            return true;
418
-        }
419
-        return false;
420
-    }
421
-
422
-
423
-    /**
424
-     *    payment_method_settings_meta_box
425
-     *
426
-     * @param NULL  $post_obj_which_is_null is an object containing the current post (as a $post object)
427
-     * @param array $metabox                is an array with metabox id, title, callback, and args elements. the value
428
-     *                                      at 'args' has key 'payment_method', as set within _payment_methods_list
429
-     * @return void
430
-     * @throws EE_Error
431
-     * @throws ReflectionException
432
-     */
433
-    public function payment_method_settings_meta_box($post_obj_which_is_null, $metabox)
434
-    {
435
-        $payment_method = isset($metabox['args'], $metabox['args']['payment_method'])
436
-            ? $metabox['args']['payment_method'] : null;
437
-        if (! $payment_method instanceof EE_Payment_Method) {
438
-            throw new EE_Error(
439
-                esc_html__(
440
-                    'Payment method metabox setup incorrectly. No Payment method object was supplied',
441
-                    'event_espresso'
442
-                )
443
-            );
444
-        }
445
-        $payment_method_scopes = $payment_method->active();
446
-        // if the payment method really exists show its form, otherwise the activation template
447
-        if ($payment_method->ID() && ! empty($payment_method_scopes)) {
448
-            $form = $this->_generate_payment_method_settings_form($payment_method);
449
-            if ($form->form_data_present_in($this->_req_data)) {
450
-                $form->receive_form_submission($this->_req_data);
451
-            }
452
-            echo wp_kses($form->form_open() . $form->get_html_and_js() . $form->form_close(), AllowedTags::getWithFormTags());
453
-        } else {
454
-            echo wp_kses($this->_activate_payment_method_button($payment_method)->get_html_and_js(), AllowedTags::getWithFormTags());
455
-        }
456
-    }
457
-
458
-
459
-    /**
460
-     * Gets the form for all the settings related to this payment method type
461
-     *
462
-     * @access protected
463
-     * @param EE_Payment_Method $payment_method
464
-     * @return EE_Form_Section_Proper
465
-     * @throws EE_Error
466
-     */
467
-    protected function _generate_payment_method_settings_form(EE_Payment_Method $payment_method = null)
468
-    {
469
-        if (! $payment_method instanceof EE_Payment_Method) {
470
-            return new EE_Form_Section_Proper();
471
-        }
472
-        return new EE_Form_Section_Proper(
473
-            array(
474
-                'name'            => $payment_method->slug() . '_settings_form',
475
-                'html_id'         => $payment_method->slug() . '_settings_form',
476
-                'action'          => EE_Admin_Page::add_query_args_and_nonce(
477
-                    array(
478
-                        'action'         => 'update_payment_method',
479
-                        'payment_method' => $payment_method->slug(),
480
-                    ),
481
-                    EE_PAYMENTS_ADMIN_URL
482
-                ),
483
-                'layout_strategy' => new EE_Admin_Two_Column_Layout(),
484
-                'subsections'     => apply_filters(
485
-                    'FHEE__Payments_Admin_Page___generate_payment_method_settings_form__form_subsections',
486
-                    array(
487
-                        'pci_dss_compliance'      => $this->_pci_dss_compliance($payment_method),
488
-                        'currency_support'        => $this->_currency_support($payment_method),
489
-                        'payment_method_settings' => $this->_payment_method_settings($payment_method),
490
-                        'update'                  => $this->_update_payment_method_button($payment_method),
491
-                        'deactivate'              => $this->_deactivate_payment_method_button($payment_method),
492
-                        'fine_print'              => $this->_fine_print(),
493
-                    ),
494
-                    $payment_method
495
-                ),
496
-            )
497
-        );
498
-    }
499
-
500
-
501
-    /**
502
-     * _pci_dss_compliance
503
-     *
504
-     * @access protected
505
-     * @param EE_Payment_Method $payment_method
506
-     * @return EE_Form_Section_HTML
507
-     * @throws EE_Error
508
-     */
509
-    protected function _pci_dss_compliance(EE_Payment_Method $payment_method)
510
-    {
511
-        if ($payment_method->type_obj()->requires_https()) {
512
-            return new EE_Form_Section_HTML(
513
-                EEH_HTML::table(
514
-                    EEH_HTML::tr(
515
-                        EEH_HTML::th(
516
-                            EEH_HTML::label(
517
-                                EEH_HTML::strong(
518
-                                    esc_html__('IMPORTANT', 'event_espresso'),
519
-                                    '',
520
-                                    'important-notice'
521
-                                )
522
-                            )
523
-                        ) .
524
-                        EEH_HTML::td(
525
-                            EEH_HTML::strong(
526
-                                esc_html__(
527
-                                    'You are responsible for your own website security and Payment Card Industry Data Security Standards (PCI DSS) compliance.',
528
-                                    'event_espresso'
529
-                                )
530
-                            )
531
-                            .
532
-                            EEH_HTML::br()
533
-                            .
534
-                            esc_html__('Learn more about ', 'event_espresso')
535
-                            . EEH_HTML::link(
536
-                                'https://www.pcisecuritystandards.org/merchants/index.php',
537
-                                esc_html__('PCI DSS compliance', 'event_espresso')
538
-                            )
539
-                        )
540
-                    )
541
-                )
542
-            );
543
-        }
544
-        return new EE_Form_Section_HTML('');
545
-    }
546
-
547
-
548
-    /**
549
-     * _currency_support
550
-     *
551
-     * @access protected
552
-     * @param EE_Payment_Method $payment_method
553
-     * @return EE_Form_Section_HTML
554
-     * @throws EE_Error
555
-     */
556
-    protected function _currency_support(EE_Payment_Method $payment_method)
557
-    {
558
-        if (! $payment_method->usable_for_currency(EE_Config::instance()->currency->code)) {
559
-            return new EE_Form_Section_HTML(
560
-                EEH_HTML::table(
561
-                    EEH_HTML::tr(
562
-                        EEH_HTML::th(
563
-                            EEH_HTML::label(
564
-                                EEH_HTML::strong(
565
-                                    esc_html__('IMPORTANT', 'event_espresso'),
566
-                                    '',
567
-                                    'important-notice'
568
-                                )
569
-                            )
570
-                        ) .
571
-                        EEH_HTML::td(
572
-                            EEH_HTML::strong(
573
-                                sprintf(
574
-                                    esc_html__(
575
-                                        'This payment method does not support the currency set on your site (%1$s). Please activate a different payment method or change your site\'s country and associated currency.',
576
-                                        'event_espresso'
577
-                                    ),
578
-                                    EE_Config::instance()->currency->code
579
-                                )
580
-                            )
581
-                        )
582
-                    )
583
-                )
584
-            );
585
-        }
586
-        return new EE_Form_Section_HTML('');
587
-    }
588
-
589
-
590
-    /**
591
-     * _update_payment_method_button
592
-     *
593
-     * @access protected
594
-     * @param EE_Payment_Method $payment_method
595
-     * @return EE_Payment_Method_Form
596
-     * @throws EE_Error
597
-     */
598
-    protected function _payment_method_settings(EE_Payment_Method $payment_method)
599
-    {
600
-        // modify the form, so we only have/show fields that will be implemented for this version
601
-        return $this->_simplify_form($payment_method->type_obj()->settings_form(), $payment_method->name());
602
-    }
603
-
604
-
605
-    /**
606
-     * Simplifies the form to merely reproduce 4.1's gateway settings functionality
607
-     *
608
-     * @param EE_Form_Section_Proper $form_section
609
-     * @param string                 $payment_method_name
610
-     * @return EE_Payment_Method_Form
611
-     * @throws EE_Error
612
-     */
613
-    protected function _simplify_form($form_section, $payment_method_name = '')
614
-    {
615
-        if ($form_section instanceof EE_Payment_Method_Form) {
616
-            $form_section->exclude(
617
-                array(
618
-                    'PMD_type', // don't want them changing the type
619
-                    'PMD_slug', // or the slug (probably never)
620
-                    'PMD_wp_user', // or the user's ID
621
-                    'Currency' // or the currency, until the rest of EE supports simultaneous currencies
622
-                )
623
-            );
624
-            return $form_section;
625
-        } else {
626
-            throw new EE_Error(
627
-                sprintf(
628
-                    esc_html__(
629
-                        'The EE_Payment_Method_Form for the "%1$s" payment method is missing or invalid.',
630
-                        'event_espresso'
631
-                    ),
632
-                    $payment_method_name
633
-                )
634
-            );
635
-        }
636
-    }
637
-
638
-
639
-    /**
640
-     * _update_payment_method_button
641
-     *
642
-     * @access protected
643
-     * @param EE_Payment_Method $payment_method
644
-     * @return EE_Form_Section_HTML
645
-     * @throws EE_Error
646
-     */
647
-    protected function _update_payment_method_button(EE_Payment_Method $payment_method)
648
-    {
649
-        $update_button = new EE_Submit_Input(
650
-            array(
651
-                'name'       => 'submit',
652
-                'html_id'    => 'save_' . $payment_method->slug() . '_settings',
653
-                'default'    => sprintf(
654
-                    esc_html__('Update %s Payment Settings', 'event_espresso'),
655
-                    $payment_method->admin_name()
656
-                ),
657
-                'html_label' => EEH_HTML::nbsp(),
658
-            )
659
-        );
660
-        return new EE_Form_Section_HTML(
661
-            EEH_HTML::table(
662
-                EEH_HTML::no_row(EEH_HTML::br(2)) .
663
-                EEH_HTML::tr(
664
-                    EEH_HTML::th(esc_html__('Update Settings', 'event_espresso')) .
665
-                    EEH_HTML::td(
666
-                        $update_button->get_html_for_input()
667
-                    )
668
-                )
669
-            )
670
-        );
671
-    }
672
-
673
-
674
-    /**
675
-     * _deactivate_payment_method_button
676
-     *
677
-     * @access protected
678
-     * @param EE_Payment_Method $payment_method
679
-     * @return EE_Form_Section_HTML
680
-     */
681
-    protected function _deactivate_payment_method_button(EE_Payment_Method $payment_method)
682
-    {
683
-        $link_text_and_title = sprintf(
684
-            esc_html__('Deactivate %1$s Payments?', 'event_espresso'),
685
-            $payment_method->admin_name()
686
-        );
687
-        return new EE_Form_Section_HTML(
688
-            EEH_HTML::table(
689
-                EEH_HTML::tr(
690
-                    EEH_HTML::th(esc_html__('Deactivate Payment Method', 'event_espresso')) .
691
-                    EEH_HTML::td(
692
-                        EEH_HTML::link(
693
-                            EE_Admin_Page::add_query_args_and_nonce(
694
-                                array(
695
-                                    'action'         => 'deactivate_payment_method',
696
-                                    'payment_method' => $payment_method->slug(),
697
-                                ),
698
-                                EE_PAYMENTS_ADMIN_URL
699
-                            ),
700
-                            $link_text_and_title,
701
-                            $link_text_and_title,
702
-                            'deactivate_' . $payment_method->slug(),
703
-                            'button button--secondary'
704
-                        )
705
-                    )
706
-                )
707
-            )
708
-        );
709
-    }
710
-
711
-
712
-    /**
713
-     * _activate_payment_method_button
714
-     *
715
-     * @access protected
716
-     * @param EE_Payment_Method $payment_method
717
-     * @return EE_Form_Section_Proper
718
-     * @throws EE_Error
719
-     */
720
-    protected function _activate_payment_method_button(EE_Payment_Method $payment_method)
721
-    {
722
-        $link_text_and_title = sprintf(
723
-            esc_html__('Activate %1$s Payment Method?', 'event_espresso'),
724
-            $payment_method->admin_name()
725
-        );
726
-        return new EE_Form_Section_Proper(
727
-            array(
728
-                'name'            => 'activate_' . $payment_method->slug() . '_settings_form',
729
-                'html_id'         => 'activate_' . $payment_method->slug() . '_settings_form',
730
-                'action'          => '#',
731
-                'layout_strategy' => new EE_Admin_Two_Column_Layout(),
732
-                'subsections'     => apply_filters(
733
-                    'FHEE__Payments_Admin_Page___activate_payment_method_button__form_subsections',
734
-                    array(
735
-                        new EE_Form_Section_HTML(
736
-                            EEH_HTML::table(
737
-                                EEH_HTML::tr(
738
-                                    EEH_HTML::td(
739
-                                        $payment_method->type_obj()->introductory_html(),
740
-                                        '',
741
-                                        '',
742
-                                        '',
743
-                                        'colspan="2"'
744
-                                    )
745
-                                ) .
746
-                                EEH_HTML::tr(
747
-                                    EEH_HTML::th(
748
-                                        EEH_HTML::label(esc_html__('Click to Activate ', 'event_espresso'))
749
-                                    ) .
750
-                                    EEH_HTML::td(
751
-                                        EEH_HTML::link(
752
-                                            EE_Admin_Page::add_query_args_and_nonce(
753
-                                                array(
754
-                                                    'action'              => 'activate_payment_method',
755
-                                                    'payment_method_type' => $payment_method->type(),
756
-                                                ),
757
-                                                EE_PAYMENTS_ADMIN_URL
758
-                                            ),
759
-                                            $link_text_and_title,
760
-                                            $link_text_and_title,
761
-                                            'activate_' . $payment_method->slug(),
762
-                                            'button button--primary-alt'
763
-                                        )
764
-                                    )
765
-                                )
766
-                            )
767
-                        ),
768
-                    ),
769
-                    $payment_method
770
-                ),
771
-            )
772
-        );
773
-    }
774
-
775
-
776
-    /**
777
-     * _fine_print
778
-     *
779
-     * @access protected
780
-     * @return EE_Form_Section_HTML
781
-     */
782
-    protected function _fine_print()
783
-    {
784
-        return new EE_Form_Section_HTML(
785
-            EEH_HTML::table(
786
-                EEH_HTML::tr(
787
-                    EEH_HTML::th() .
788
-                    EEH_HTML::td(
789
-                        EEH_HTML::p(esc_html__('All fields marked with a * are required fields', 'event_espresso'), '', 'grey-text')
790
-                    )
791
-                )
792
-            )
793
-        );
794
-    }
795
-
796
-
797
-    /**
798
-     * Activates a payment method of that type. Mostly assuming there is only 1 of that type (or none so far)
799
-     *
800
-     * @throws EE_Error
801
-     * @throws ReflectionException
802
-     * @global WP_User $current_user
803
-     */
804
-    protected function _activate_payment_method()
805
-    {
806
-        if (isset($this->_req_data['payment_method_type'])) {
807
-            $payment_method_type = sanitize_text_field($this->_req_data['payment_method_type']);
808
-            // see if one exists
809
-            EE_Registry::instance()->load_lib('Payment_Method_Manager');
810
-            $payment_method = EE_Payment_Method_Manager::instance()
811
-                                                       ->activate_a_payment_method_of_type($payment_method_type);
812
-            $this->_redirect_after_action(
813
-                1,
814
-                'Payment Method',
815
-                'activated',
816
-                array('action' => 'default', 'payment_method' => $payment_method->slug())
817
-            );
818
-        } else {
819
-            $this->_redirect_after_action(false, 'Payment Method', 'activated', array('action' => 'default'));
820
-        }
821
-    }
822
-
823
-
824
-    /**
825
-     * @throws EE_Error
826
-     * @throws ReflectionException
827
-     */
828
-    protected function _deactivate_payment_method()
829
-    {
830
-        if (isset($this->_req_data['payment_method'])) {
831
-            $payment_method_slug = sanitize_key($this->_req_data['payment_method']);
832
-            // deactivate it
833
-            EE_Registry::instance()->load_lib('Payment_Method_Manager');
834
-            $count_updated = EE_Payment_Method_Manager::instance()->deactivate_payment_method($payment_method_slug);
835
-            $this->_redirect_after_action(
836
-                $count_updated,
837
-                'Payment Method',
838
-                'deactivated',
839
-                array('action' => 'default', 'payment_method' => $payment_method_slug)
840
-            );
841
-        } else {
842
-            $this->_redirect_after_action(false, 'Payment Method', 'deactivated', array('action' => 'default'));
843
-        }
844
-    }
845
-
846
-
847
-    /**
848
-     * Processes the payment method form that was submitted. This is slightly trickier than usual form
849
-     * processing because we first need to identify WHICH form was processed and which payment method
850
-     * it corresponds to. Once we have done that, we see if the form is valid. If it is, the
851
-     * form's data is saved, and we redirect to the default payment methods page, setting the updated payment method
852
-     * as the currently-selected one. If it DOESN'T validate, we render the page with the form's errors (in the
853
-     * subsequently called 'headers_sent_func' which is _payment_methods_list)
854
-     *
855
-     * @return void
856
-     * @throws EE_Error
857
-     * @throws ReflectionException
858
-     */
859
-    protected function _update_payment_method()
860
-    {
861
-        if ($_SERVER['REQUEST_METHOD'] == 'POST') {
862
-            // ok let's find which gateway form to use based on the form input
863
-            EE_Registry::instance()->load_lib('Payment_Method_Manager');
864
-            /** @var $correct_pmt_form_to_use EE_Payment_Method_Form */
865
-            $correct_pmt_form_to_use = null;
866
-            $payment_method = null;
867
-            foreach (EEM_Payment_Method::instance()->get_all() as $payment_method) {
868
-                if ($payment_method instanceof EE_Payment_Method) {
869
-                    // get the form and simplify it, like what we do when we display it
870
-                    $pmt_form = $this->_generate_payment_method_settings_form($payment_method);
871
-                    if ($pmt_form->form_data_present_in($this->_req_data)) {
872
-                        $correct_pmt_form_to_use = $pmt_form;
873
-                        break;
874
-                    }
875
-                }
876
-            }
877
-            // if we couldn't find the correct payment method type...
878
-            if (! $correct_pmt_form_to_use) {
879
-                EE_Error::add_error(
880
-                    esc_html__(
881
-                        "We could not find which payment method type your form submission related to. Please contact support",
882
-                        'event_espresso'
883
-                    ),
884
-                    __FILE__,
885
-                    __FUNCTION__,
886
-                    __LINE__
887
-                );
888
-                $this->_redirect_after_action(false, 'Payment Method', 'activated', array('action' => 'default'));
889
-            }
890
-            $correct_pmt_form_to_use->receive_form_submission($this->_req_data);
891
-            if ($correct_pmt_form_to_use->is_valid()) {
892
-                $payment_settings_subform = $correct_pmt_form_to_use->get_subsection('payment_method_settings');
893
-                if (! $payment_settings_subform instanceof EE_Payment_Method_Form) {
894
-                    throw new EE_Error(
895
-                        sprintf(
896
-                            esc_html__(
897
-                                'The payment method could not be saved because the form sections were misnamed. We expected to find %1$s, but did not.',
898
-                                'event_espresso'
899
-                            ),
900
-                            'payment_method_settings'
901
-                        )
902
-                    );
903
-                }
904
-                $payment_settings_subform->save();
905
-                /** @var $pm EE_Payment_Method */
906
-                $this->_redirect_after_action(
907
-                    true,
908
-                    'Payment Method',
909
-                    'updated',
910
-                    array('action' => 'default', 'payment_method' => $payment_method->slug())
911
-                );
912
-            } else {
913
-                EE_Error::add_error(
914
-                    sprintf(
915
-                        esc_html__(
916
-                            'Payment method of type %s was not saved because there were validation errors. They have been marked in the form',
917
-                            'event_espresso'
918
-                        ),
919
-                        $payment_method instanceof EE_Payment_Method ? $payment_method->type_obj()->pretty_name()
920
-                            : esc_html__('"(unknown)"', 'event_espresso')
921
-                    ),
922
-                    __FILE__,
923
-                    __FUNCTION__,
924
-                    __LINE__
925
-                );
926
-            }
927
-        }
928
-    }
929
-
930
-
931
-    /**
932
-     * Displays payment settings (not payment METHOD settings, that's _payment_method_settings)
933
-     * @throws DomainException
934
-     * @throws EE_Error
935
-     * @throws InvalidArgumentException
936
-     * @throws InvalidDataTypeException
937
-     * @throws InvalidInterfaceException
938
-     */
939
-    protected function _payment_settings()
940
-    {
941
-        $form = $this->getPaymentSettingsForm();
942
-        $this->_set_add_edit_form_tags('update_payment_settings');
943
-        $this->_set_publish_post_box_vars(null, false, false, null, false);
944
-        $this->_template_args['admin_page_content'] = EEH_HTML::div(
945
-            $form->get_html_and_js(),
946
-            '',
947
-            'padding'
948
-        );
949
-        $this->display_admin_page_with_sidebar();
950
-    }
951
-
952
-
953
-    /**
954
-     *        _update_payment_settings
955
-     *
956
-     * @access protected
957
-     * @return void
958
-     * @throws EE_Error
959
-     * @throws InvalidArgumentException
960
-     * @throws InvalidDataTypeException
961
-     * @throws InvalidInterfaceException
962
-     */
963
-    protected function _update_payment_settings()
964
-    {
965
-        $form = $this->getPaymentSettingsForm();
966
-        if ($form->was_submitted($this->_req_data)) {
967
-            $form->receive_form_submission($this->_req_data);
968
-            if ($form->is_valid()) {
969
-                /**
970
-                 * @var $reg_config EE_Registration_Config
971
-                 */
972
-                $loader = LoaderFactory::getLoader();
973
-                $reg_config = $loader->getShared('EE_Registration_Config');
974
-                $valid_data = $form->valid_data();
975
-                $reg_config->show_pending_payment_options = $valid_data['show_pending_payment_options'];
976
-                $reg_config->gateway_log_lifespan = $valid_data['gateway_log_lifespan'];
977
-            }
978
-        }
979
-        EE_Registry::instance()->CFG = apply_filters(
980
-            'FHEE__Payments_Admin_Page___update_payment_settings__CFG',
981
-            EE_Registry::instance()->CFG
982
-        );
983
-
984
-        $what = esc_html__('Payment Settings', 'event_espresso');
985
-        $success = $this->_update_espresso_configuration(
986
-            $what,
987
-            EE_Registry::instance()->CFG,
988
-            __FILE__,
989
-            __FUNCTION__,
990
-            __LINE__
991
-        );
992
-        $this->_redirect_after_action(
993
-            $success,
994
-            $what,
995
-            esc_html__('updated', 'event_espresso'),
996
-            array('action' => 'payment_settings')
997
-        );
998
-    }
999
-
1000
-
1001
-    /**
1002
-     * Gets the form used for updating payment settings
1003
-     *
1004
-     * @return EE_Form_Section_Proper
1005
-     * @throws EE_Error
1006
-     * @throws InvalidArgumentException
1007
-     * @throws InvalidDataTypeException
1008
-     * @throws InvalidInterfaceException
1009
-     */
1010
-    protected function getPaymentSettingsForm()
1011
-    {
1012
-        /**
1013
-         * @var $reg_config EE_Registration_Config
1014
-         */
1015
-        $reg_config = LoaderFactory::getLoader()->getShared('EE_Registration_Config');
1016
-        return new EE_Form_Section_Proper(
1017
-            array(
1018
-                'name' => 'payment-settings',
1019
-                'layout_strategy' => new EE_Admin_Two_Column_Layout(),
1020
-                'subsections' => array(
1021
-                    'show_pending_payment_options' => new EE_Yes_No_Input(
1022
-                        array(
1023
-                            'html_name' => 'show_pending_payment_options',
1024
-                            'default' => $reg_config->show_pending_payment_options,
1025
-                            'html_help_text' => esc_html__(
1026
-                                "If a payment is marked as 'Pending Payment', or if payment is deferred (ie, an offline gateway like Check, Bank, or Invoice is used), then give registrants the option to retry payment. ",
1027
-                                'event_espresso'
1028
-                            )
1029
-                        )
1030
-                    ),
1031
-                    'gateway_log_lifespan' => new EE_Select_Input(
1032
-                        $reg_config->gatewayLogLifespanOptions(),
1033
-                        array(
1034
-                            'html_label_text' => esc_html__('Gateway Logs Lifespan', 'event_espresso'),
1035
-                            'html_help_text' => esc_html__('If issues arise with payments being made through a payment gateway, it\'s helpful to log non-sensitive communications with the payment gateway. But it\'s a security responsibility, so it\'s a good idea to not keep them for any longer than necessary.', 'event_espresso'),
1036
-                            'default' => $reg_config->gateway_log_lifespan,
1037
-                        )
1038
-                    )
1039
-                )
1040
-            )
1041
-        );
1042
-    }
1043
-
1044
-
1045
-    /**
1046
-     * @throws EE_Error
1047
-     */
1048
-    protected function _payment_log_overview_list_table()
1049
-    {
1050
-        $this->display_admin_list_table_page_with_sidebar();
1051
-    }
1052
-
1053
-
1054
-    protected function _set_list_table_views_payment_log()
1055
-    {
1056
-        $this->_views = array(
1057
-            'all' => array(
1058
-                'slug'  => 'all',
1059
-                'label' => esc_html__('View All Logs', 'event_espresso'),
1060
-                'count' => 0,
1061
-            ),
1062
-        );
1063
-    }
1064
-
1065
-
1066
-    /**
1067
-     * @param int  $per_page
1068
-     * @param int  $current_page
1069
-     * @param bool $count
1070
-     * @return array|int
1071
-     * @throws EE_Error
1072
-     * @throws ReflectionException
1073
-     */
1074
-    public function get_payment_logs($per_page = 50, $current_page = 0, $count = false)
1075
-    {
1076
-        EE_Registry::instance()->load_model('Change_Log');
1077
-        // we may need to do multiple queries (joining differently), so we actually want an array of query params
1078
-        $query_params = array(array('LOG_type' => EEM_Change_Log::type_gateway));
1079
-        // check if they've selected a specific payment method
1080
-        if (isset($this->_req_data['_payment_method']) && $this->_req_data['_payment_method'] !== 'all') {
1081
-            $query_params[0]['OR*pm_or_pay_pm'] = array(
1082
-                'Payment.Payment_Method.PMD_ID' => $this->_req_data['_payment_method'],
1083
-                'Payment_Method.PMD_ID'         => $this->_req_data['_payment_method'],
1084
-            );
1085
-        }
1086
-        // take into account search
1087
-        if (isset($this->_req_data['s']) && $this->_req_data['s']) {
1088
-            $similarity_string = array('LIKE', '%' . str_replace("", "%", $this->_req_data['s']) . '%');
1089
-            $query_params[0]['OR*s']['Payment.Transaction.Registration.Attendee.ATT_fname'] = $similarity_string;
1090
-            $query_params[0]['OR*s']['Payment.Transaction.Registration.Attendee.ATT_lname'] = $similarity_string;
1091
-            $query_params[0]['OR*s']['Payment.Transaction.Registration.Attendee.ATT_email'] = $similarity_string;
1092
-            $query_params[0]['OR*s']['Payment.Payment_Method.PMD_name'] = $similarity_string;
1093
-            $query_params[0]['OR*s']['Payment.Payment_Method.PMD_admin_name'] = $similarity_string;
1094
-            $query_params[0]['OR*s']['Payment.Payment_Method.PMD_type'] = $similarity_string;
1095
-            $query_params[0]['OR*s']['LOG_message'] = $similarity_string;
1096
-            $query_params[0]['OR*s']['Payment_Method.PMD_name'] = $similarity_string;
1097
-            $query_params[0]['OR*s']['Payment_Method.PMD_admin_name'] = $similarity_string;
1098
-            $query_params[0]['OR*s']['Payment_Method.PMD_type'] = $similarity_string;
1099
-            $query_params[0]['OR*s']['LOG_message'] = $similarity_string;
1100
-        }
1101
-        if (
1102
-            isset($this->_req_data['payment-filter-start-date'])
1103
-            && isset($this->_req_data['payment-filter-end-date'])
1104
-        ) {
1105
-            // add date
1106
-            $start_date = wp_strip_all_tags($this->_req_data['payment-filter-start-date']);
1107
-            $end_date = wp_strip_all_tags($this->_req_data['payment-filter-end-date']);
1108
-            // make sure our timestamps start and end right at the boundaries for each day
1109
-            $start_date = date('Y-m-d', strtotime($start_date)) . ' 00:00:00';
1110
-            $end_date = date('Y-m-d', strtotime($end_date)) . ' 23:59:59';
1111
-            // convert to timestamps
1112
-            $start_date = strtotime($start_date);
1113
-            $end_date = strtotime($end_date);
1114
-            // makes sure start date is the lowest value and vice versa
1115
-            $start_date = min($start_date, $end_date);
1116
-            $end_date = max($start_date, $end_date);
1117
-            // convert for query
1118
-            $start_date = EEM_Change_Log::instance()->convert_datetime_for_query(
1119
-                'LOG_time',
1120
-                date('Y-m-d H:i:s', $start_date),
1121
-                'Y-m-d H:i:s'
1122
-            );
1123
-            $end_date   = EEM_Change_Log::instance()->convert_datetime_for_query(
1124
-                'LOG_time',
1125
-                date('Y-m-d H:i:s', $end_date),
1126
-                'Y-m-d H:i:s'
1127
-            );
1128
-            $query_params[0]['LOG_time'] = array('BETWEEN', array($start_date, $end_date));
1129
-        }
1130
-        if ($count) {
1131
-            return EEM_Change_Log::instance()->count($query_params);
1132
-        }
1133
-        if (isset($this->_req_data['order'])) {
1134
-            $sort = (isset($this->_req_data['order']) && ! empty($this->_req_data['order']))
1135
-                ? $this->_req_data['order']
1136
-                : 'DESC';
1137
-            $query_params['order_by'] = array('LOG_time' => $sort);
1138
-        } else {
1139
-            $query_params['order_by'] = array('LOG_time' => 'DESC');
1140
-        }
1141
-        $offset = ($current_page - 1) * $per_page;
1142
-        if (! isset($this->_req_data['download_results'])) {
1143
-            $query_params['limit'] = array($offset, $per_page);
1144
-        }
1145
-        // now they've requested to instead just download the file instead of viewing it.
1146
-        if (isset($this->_req_data['download_results'])) {
1147
-            $wpdb_results = EEM_Change_Log::instance()->get_all_efficiently($query_params);
1148
-            header('Content-Disposition: attachment');
1149
-            header("Content-Disposition: attachment; filename=ee_payment_logs_for_" . sanitize_key(site_url()));
1150
-            echo '<h1> '
1151
-                . sprintf(
1152
-                    esc_html__('Payment Logs for %1$s', 'event_espresso'),
1153
-                    esc_url_raw(site_url())
1154
-                )
1155
-                . '</h1 >';
1156
-            echo '<h3>' . esc_html__('Query:', 'event_espresso') . '</h3>';
1157
-            echo esc_html(var_export($query_params, true));
1158
-            echo '<h3>' . esc_html__('Results:', 'event_espresso') . '</h3>';
1159
-            echo esc_html(var_export($wpdb_results, true));
1160
-            die;
1161
-        }
1162
-        return EEM_Change_Log::instance()->get_all($query_params);
1163
-    }
1164
-
1165
-
1166
-    /**
1167
-     * Used by usort to RE-sort log query results, because we lose the ordering
1168
-     * because we're possibly combining the results from two queries
1169
-     *
1170
-     * @param EE_Change_Log $logA
1171
-     * @param EE_Change_Log $logB
1172
-     * @return int
1173
-     * @throws EE_Error
1174
-     * @throws ReflectionException
1175
-     */
1176
-    protected function _sort_logs_again($logA, $logB)
1177
-    {
1178
-        $timeA = $logA->get_raw('LOG_time');
1179
-        $timeB = $logB->get_raw('LOG_time');
1180
-        if ($timeA == $timeB) {
1181
-            return 0;
1182
-        }
1183
-        $comparison = $timeA < $timeB ? -1 : 1;
1184
-        if (strtoupper($this->_sort_logs_again_direction) == 'DESC') {
1185
-            return $comparison * -1;
1186
-        }
1187
-        return $comparison;
1188
-    }
1189
-
1190
-
1191
-    /**
1192
-     * @throws EE_Error
1193
-     * @throws ReflectionException
1194
-     */
1195
-    protected function _payment_log_details()
1196
-    {
1197
-        EE_Registry::instance()->load_model('Change_Log');
1198
-        /** @var $payment_log EE_Change_Log */
1199
-        $payment_log = EEM_Change_Log::instance()->get_one_by_ID($this->_req_data['ID']);
1200
-        $payment_method = null;
1201
-        $transaction = null;
1202
-        if ($payment_log instanceof EE_Change_Log) {
1203
-            if ($payment_log->object() instanceof EE_Payment) {
1204
-                $payment_method = $payment_log->object()->payment_method();
1205
-                $transaction = $payment_log->object()->transaction();
1206
-            } elseif ($payment_log->object() instanceof EE_Payment_Method) {
1207
-                $payment_method = $payment_log->object();
1208
-            } elseif ($payment_log->object() instanceof EE_Transaction) {
1209
-                $transaction = $payment_log->object();
1210
-                $payment_method = $transaction->payment_method();
1211
-            }
1212
-        }
1213
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
1214
-            EE_PAYMENTS_TEMPLATE_PATH . 'payment_log_details.template.php',
1215
-            array(
1216
-                'payment_log'    => $payment_log,
1217
-                'payment_method' => $payment_method,
1218
-                'transaction'    => $transaction,
1219
-            ),
1220
-            true
1221
-        );
1222
-        $this->display_admin_page_with_no_sidebar();
1223
-    }
19
+	/**
20
+	 * Variables used for when we're re-sorting the logs results,
21
+	 * in case we needed to do two queries, and we need to resort
22
+	 *
23
+	 * @var string
24
+	 */
25
+	private $_sort_logs_again_direction;
26
+
27
+
28
+	/**
29
+	 * @Constructor
30
+	 * @access public
31
+	 * @param bool $routing indicate whether we want to just load the object and handle routing or just load the object.
32
+	 * @throws EE_Error
33
+	 * @throws InvalidArgumentException
34
+	 * @throws InvalidDataTypeException
35
+	 * @throws InvalidInterfaceException
36
+	 * @throws ReflectionException
37
+	 */
38
+	public function __construct($routing = true)
39
+	{
40
+		parent::__construct($routing);
41
+	}
42
+
43
+
44
+	protected function _init_page_props()
45
+	{
46
+		$this->page_slug = EE_PAYMENTS_PG_SLUG;
47
+		$this->page_label = esc_html__('Payment Methods', 'event_espresso');
48
+		$this->_admin_base_url = EE_PAYMENTS_ADMIN_URL;
49
+		$this->_admin_base_path = EE_PAYMENTS_ADMIN;
50
+	}
51
+
52
+
53
+	protected function _ajax_hooks()
54
+	{
55
+		// todo: all hooks for ajax goes here.
56
+	}
57
+
58
+
59
+	protected function _define_page_props()
60
+	{
61
+		$this->_admin_page_title = $this->page_label;
62
+		$this->_labels = array(
63
+			'publishbox' => esc_html__('Update Settings', 'event_espresso'),
64
+		);
65
+	}
66
+
67
+
68
+	protected function _set_page_routes()
69
+	{
70
+		/**
71
+		 * note that with payment method capabilities, although we've implemented
72
+		 * capability mapping which will be used for accessing payment methods owned by
73
+		 * other users.  This is not fully implemented yet in the payment method ui.
74
+		 * Currently, only the "plural" caps are in active use.
75
+		 * When cap mapping is implemented, some routes will need to use the singular form of
76
+		 * capability method and also include the $id of the payment method for the route.
77
+		 **/
78
+		$this->_page_routes = array(
79
+			'default'                   => array(
80
+				'func'       => '_payment_methods_list',
81
+				'capability' => 'ee_edit_payment_methods',
82
+			),
83
+			'payment_settings'          => array(
84
+				'func'       => '_payment_settings',
85
+				'capability' => 'ee_manage_gateways',
86
+			),
87
+			'activate_payment_method'   => array(
88
+				'func'       => '_activate_payment_method',
89
+				'noheader'   => true,
90
+				'capability' => 'ee_edit_payment_methods',
91
+			),
92
+			'deactivate_payment_method' => array(
93
+				'func'       => '_deactivate_payment_method',
94
+				'noheader'   => true,
95
+				'capability' => 'ee_delete_payment_methods',
96
+			),
97
+			'update_payment_method'     => array(
98
+				'func'               => '_update_payment_method',
99
+				'noheader'           => true,
100
+				'headers_sent_route' => 'default',
101
+				'capability'         => 'ee_edit_payment_methods',
102
+			),
103
+			'update_payment_settings'   => array(
104
+				'func'       => '_update_payment_settings',
105
+				'noheader'   => true,
106
+				'capability' => 'ee_manage_gateways',
107
+			),
108
+			'payment_log'               => array(
109
+				'func'       => '_payment_log_overview_list_table',
110
+				'capability' => 'ee_read_payment_methods',
111
+			),
112
+			'payment_log_details'       => array(
113
+				'func'       => '_payment_log_details',
114
+				'capability' => 'ee_read_payment_methods',
115
+			),
116
+		);
117
+	}
118
+
119
+
120
+	/**
121
+	 * @throws EE_Error
122
+	 * @throws ReflectionException
123
+	 */
124
+	protected function _set_page_config()
125
+	{
126
+		$payment_method_list_config = array(
127
+			'nav'           => array(
128
+				'label' => esc_html__('Payment Methods', 'event_espresso'),
129
+				'icon' => 'dashicons-bank',
130
+				'order' => 10,
131
+			),
132
+			'metaboxes'     => $this->_default_espresso_metaboxes,
133
+			'help_tabs'     => array_merge(
134
+				array(
135
+					'payment_methods_overview_help_tab' => array(
136
+						'title'    => esc_html__('Payment Methods Overview', 'event_espresso'),
137
+						'filename' => 'payment_methods_overview',
138
+					),
139
+				),
140
+				$this->_add_payment_method_help_tabs()
141
+			),
142
+			'require_nonce' => false,
143
+		);
144
+		$this->_page_config = array(
145
+			'default'          => $payment_method_list_config,
146
+			'payment_settings' => array(
147
+				'nav'           => array(
148
+					'label' => esc_html__('Settings', 'event_espresso'),
149
+					'icon' => 'dashicons-admin-generic',
150
+					'order' => 20,
151
+				),
152
+				'help_tabs'     => array(
153
+					'payment_methods_settings_help_tab' => array(
154
+						'title'    => esc_html__('Payment Method Settings', 'event_espresso'),
155
+						'filename' => 'payment_methods_settings',
156
+					),
157
+				),
158
+				'metaboxes'     => array_merge($this->_default_espresso_metaboxes, array('_publish_post_box')),
159
+				'require_nonce' => false,
160
+			),
161
+			'payment_log'      => array(
162
+				'nav'           => array(
163
+					'label' => esc_html__("Logs", 'event_espresso'),
164
+					'icon' => 'dashicons-text-page',
165
+					'order' => 30,
166
+				),
167
+				'list_table'    => 'Payment_Log_Admin_List_Table',
168
+				'metaboxes'     => $this->_default_espresso_metaboxes,
169
+				'require_nonce' => false,
170
+			),
171
+		);
172
+	}
173
+
174
+
175
+	/**
176
+	 * @return array
177
+	 * @throws DomainException
178
+	 * @throws EE_Error
179
+	 * @throws InvalidArgumentException
180
+	 * @throws InvalidDataTypeException
181
+	 * @throws InvalidInterfaceException
182
+	 * @throws ReflectionException
183
+	 */
184
+	protected function _add_payment_method_help_tabs()
185
+	{
186
+		EE_Registry::instance()->load_lib('Payment_Method_Manager');
187
+		$payment_method_types = EE_Payment_Method_Manager::instance()->payment_method_types();
188
+		$all_pmt_help_tabs_config = array();
189
+		foreach ($payment_method_types as $payment_method_type) {
190
+			if (
191
+				! EE_Registry::instance()->CAP->current_user_can(
192
+					$payment_method_type->cap_name(),
193
+					'specific_payment_method_type_access'
194
+				)
195
+			) {
196
+				continue;
197
+			}
198
+			foreach ($payment_method_type->help_tabs_config() as $help_tab_name => $config) {
199
+				$template_args = isset($config['template_args']) ? $config['template_args'] : array();
200
+				$template_args['admin_page_obj'] = $this;
201
+				$all_pmt_help_tabs_config[ $help_tab_name ] = array(
202
+					'title'   => $config['title'],
203
+					'content' => EEH_Template::display_template(
204
+						$payment_method_type->file_folder() . 'help_tabs/' . $config['filename'] . '.help_tab.php',
205
+						$template_args,
206
+						true
207
+					),
208
+				);
209
+			}
210
+		}
211
+		return $all_pmt_help_tabs_config;
212
+	}
213
+
214
+
215
+	// none of the below group are currently used for Gateway Settings
216
+	protected function _add_screen_options()
217
+	{
218
+	}
219
+
220
+
221
+	protected function _add_feature_pointers()
222
+	{
223
+	}
224
+
225
+
226
+	public function admin_init()
227
+	{
228
+	}
229
+
230
+
231
+	public function admin_notices()
232
+	{
233
+	}
234
+
235
+
236
+	public function admin_footer_scripts()
237
+	{
238
+	}
239
+
240
+
241
+	public function load_scripts_styles()
242
+	{
243
+		// styles
244
+		wp_enqueue_style('espresso-ui-theme');
245
+		wp_register_style(
246
+			'espresso_payments',
247
+			EE_PAYMENTS_ASSETS_URL . 'ee-payments.css',
248
+			[],
249
+			EVENT_ESPRESSO_VERSION
250
+		);
251
+		// scripts
252
+		wp_enqueue_script('ee_admin_js');
253
+		wp_enqueue_script('ee-text-links');
254
+		wp_enqueue_script(
255
+			'espresso_payments',
256
+			EE_PAYMENTS_ASSETS_URL . 'espresso_payments_admin.js',
257
+			['ee-datepicker'],
258
+			EVENT_ESPRESSO_VERSION,
259
+			true
260
+		);
261
+	}
262
+
263
+
264
+	public function load_scripts_styles_default()
265
+	{
266
+		wp_enqueue_style('espresso_payments');
267
+		wp_enqueue_style('ee-text-links');
268
+	}
269
+
270
+
271
+	public function load_scripts_styles_payment_log_details()
272
+	{
273
+		wp_enqueue_style('espresso_payments');
274
+	}
275
+
276
+
277
+	/**
278
+	 * @throws EE_Error
279
+	 * @throws ReflectionException
280
+	 */
281
+	protected function _payment_methods_list()
282
+	{
283
+		/**
284
+		 * first let's ensure payment methods have been set up.
285
+		 * We do this here because when people activate a payment method for the first time (as an addon),
286
+		 * it may not set up its capabilities or get registered correctly due to the loading process.
287
+		 * However, people MUST set up the details for the payment method,
288
+		 * so it's safe to do a recheck here.
289
+		 */
290
+		EE_Registry::instance()->load_lib('Payment_Method_Manager');
291
+		EEM_Payment_Method::instance()->verify_button_urls();
292
+		// set up tabs, one for each payment method type
293
+		$tabs = array();
294
+		$payment_methods = array();
295
+		foreach (EE_Payment_Method_Manager::instance()->payment_method_types() as $pmt_obj) {
296
+			// we don't want to show admin-only PMTs for now
297
+			if ($pmt_obj instanceof EE_PMT_Admin_Only) {
298
+				continue;
299
+			}
300
+			// check access
301
+			if (
302
+				! EE_Registry::instance()->CAP->current_user_can(
303
+					$pmt_obj->cap_name(),
304
+					'specific_payment_method_type_access'
305
+				)
306
+			) {
307
+				continue;
308
+			}
309
+			// check for any active pms of that type
310
+			$payment_method = EEM_Payment_Method::instance()->get_one_of_type($pmt_obj->system_name());
311
+			if (! $payment_method instanceof EE_Payment_Method) {
312
+				$payment_method = EE_Payment_Method::new_instance(
313
+					array(
314
+						'PMD_slug'       => sanitize_key($pmt_obj->system_name()),
315
+						'PMD_type'       => $pmt_obj->system_name(),
316
+						'PMD_name'       => $pmt_obj->pretty_name(),
317
+						'PMD_admin_name' => $pmt_obj->pretty_name(),
318
+					)
319
+				);
320
+			}
321
+			$payment_methods[ $payment_method->slug() ] = $payment_method;
322
+		}
323
+		$payment_methods = apply_filters(
324
+			'FHEE__Payments_Admin_Page___payment_methods_list__payment_methods',
325
+			$payment_methods
326
+		);
327
+		foreach ($payment_methods as $payment_method) {
328
+			if ($payment_method instanceof EE_Payment_Method) {
329
+				$this->addMetaBox(
330
+					// html id
331
+					'espresso_' . $payment_method->slug() . '_payment_settings',
332
+					// title
333
+					sprintf(esc_html__('%s Settings', 'event_espresso'), $payment_method->admin_name()),
334
+					// callback
335
+					array($this, 'payment_method_settings_meta_box'),
336
+					// post type
337
+					null,
338
+					// context
339
+					'normal',
340
+					// priority
341
+					'default',
342
+					// callback args
343
+					array('payment_method' => $payment_method)
344
+				);
345
+				// setup for tabbed content
346
+				$tabs[ $payment_method->slug() ] = array(
347
+					'label' => $payment_method->admin_name(),
348
+					'class' => $payment_method->active() ? 'gateway-active' : '',
349
+					'href'  => 'espresso_' . $payment_method->slug() . '_payment_settings',
350
+					'title' => esc_html__('Modify this Payment Method', 'event_espresso'),
351
+					'slug'  => $payment_method->slug(),
352
+					'icon'  => $payment_method->active()
353
+						? '<span class="dashicons dashicons-yes-alt"></span>'
354
+						: '<span class="dashicons dashicons-remove"></span>',
355
+				);
356
+			}
357
+		}
358
+		$this->_template_args['admin_page_header'] = EEH_Tabbed_Content::tab_text_links(
359
+			$tabs,
360
+			'payment_method_links',
361
+			'',
362
+			$this->_get_active_payment_method_slug()
363
+		);
364
+		$this->display_admin_page_with_sidebar();
365
+	}
366
+
367
+
368
+	/**
369
+	 *   _get_active_payment_method_slug
370
+	 *
371
+	 * @return string
372
+	 * @throws EE_Error
373
+	 */
374
+	protected function _get_active_payment_method_slug()
375
+	{
376
+		$payment_method_slug = false;
377
+		// decide which payment method tab to open first, as dictated by the request's 'payment_method'
378
+		if (isset($this->_req_data['payment_method'])) {
379
+			// if they provided the current payment method, use it
380
+			$payment_method_slug = sanitize_key($this->_req_data['payment_method']);
381
+		}
382
+		/** @var EE_Payment_Method $payment_method */
383
+		$payment_method = EEM_Payment_Method::instance()->get_one(array(array('PMD_slug' => $payment_method_slug)));
384
+		// if that didn't work or wasn't provided, find another way to select the current pm
385
+		if (! $this->_verify_payment_method($payment_method)) {
386
+			// like, looking for an active one
387
+			$payment_method = EEM_Payment_Method::instance()->get_one_active('CART');
388
+			// test that one as well
389
+			if ($this->_verify_payment_method($payment_method)) {
390
+				$payment_method_slug = $payment_method->slug();
391
+			} else {
392
+				$payment_method_slug = 'paypal_standard';
393
+			}
394
+		}
395
+		return $payment_method_slug;
396
+	}
397
+
398
+
399
+	/**
400
+	 *    payment_method_settings_meta_box
401
+	 *    returns TRUE if the passed payment method is properly constructed and the logged-in user has the correct
402
+	 *    capabilities to access it
403
+	 *
404
+	 * @param EE_Payment_Method $payment_method
405
+	 * @return boolean
406
+	 * @throws EE_Error
407
+	 */
408
+	protected function _verify_payment_method($payment_method)
409
+	{
410
+		if (
411
+			$payment_method instanceof EE_Payment_Method && $payment_method->type_obj() instanceof EE_PMT_Base
412
+			&& EE_Registry::instance()->CAP->current_user_can(
413
+				$payment_method->type_obj()->cap_name(),
414
+				'specific_payment_method_type_access'
415
+			)
416
+		) {
417
+			return true;
418
+		}
419
+		return false;
420
+	}
421
+
422
+
423
+	/**
424
+	 *    payment_method_settings_meta_box
425
+	 *
426
+	 * @param NULL  $post_obj_which_is_null is an object containing the current post (as a $post object)
427
+	 * @param array $metabox                is an array with metabox id, title, callback, and args elements. the value
428
+	 *                                      at 'args' has key 'payment_method', as set within _payment_methods_list
429
+	 * @return void
430
+	 * @throws EE_Error
431
+	 * @throws ReflectionException
432
+	 */
433
+	public function payment_method_settings_meta_box($post_obj_which_is_null, $metabox)
434
+	{
435
+		$payment_method = isset($metabox['args'], $metabox['args']['payment_method'])
436
+			? $metabox['args']['payment_method'] : null;
437
+		if (! $payment_method instanceof EE_Payment_Method) {
438
+			throw new EE_Error(
439
+				esc_html__(
440
+					'Payment method metabox setup incorrectly. No Payment method object was supplied',
441
+					'event_espresso'
442
+				)
443
+			);
444
+		}
445
+		$payment_method_scopes = $payment_method->active();
446
+		// if the payment method really exists show its form, otherwise the activation template
447
+		if ($payment_method->ID() && ! empty($payment_method_scopes)) {
448
+			$form = $this->_generate_payment_method_settings_form($payment_method);
449
+			if ($form->form_data_present_in($this->_req_data)) {
450
+				$form->receive_form_submission($this->_req_data);
451
+			}
452
+			echo wp_kses($form->form_open() . $form->get_html_and_js() . $form->form_close(), AllowedTags::getWithFormTags());
453
+		} else {
454
+			echo wp_kses($this->_activate_payment_method_button($payment_method)->get_html_and_js(), AllowedTags::getWithFormTags());
455
+		}
456
+	}
457
+
458
+
459
+	/**
460
+	 * Gets the form for all the settings related to this payment method type
461
+	 *
462
+	 * @access protected
463
+	 * @param EE_Payment_Method $payment_method
464
+	 * @return EE_Form_Section_Proper
465
+	 * @throws EE_Error
466
+	 */
467
+	protected function _generate_payment_method_settings_form(EE_Payment_Method $payment_method = null)
468
+	{
469
+		if (! $payment_method instanceof EE_Payment_Method) {
470
+			return new EE_Form_Section_Proper();
471
+		}
472
+		return new EE_Form_Section_Proper(
473
+			array(
474
+				'name'            => $payment_method->slug() . '_settings_form',
475
+				'html_id'         => $payment_method->slug() . '_settings_form',
476
+				'action'          => EE_Admin_Page::add_query_args_and_nonce(
477
+					array(
478
+						'action'         => 'update_payment_method',
479
+						'payment_method' => $payment_method->slug(),
480
+					),
481
+					EE_PAYMENTS_ADMIN_URL
482
+				),
483
+				'layout_strategy' => new EE_Admin_Two_Column_Layout(),
484
+				'subsections'     => apply_filters(
485
+					'FHEE__Payments_Admin_Page___generate_payment_method_settings_form__form_subsections',
486
+					array(
487
+						'pci_dss_compliance'      => $this->_pci_dss_compliance($payment_method),
488
+						'currency_support'        => $this->_currency_support($payment_method),
489
+						'payment_method_settings' => $this->_payment_method_settings($payment_method),
490
+						'update'                  => $this->_update_payment_method_button($payment_method),
491
+						'deactivate'              => $this->_deactivate_payment_method_button($payment_method),
492
+						'fine_print'              => $this->_fine_print(),
493
+					),
494
+					$payment_method
495
+				),
496
+			)
497
+		);
498
+	}
499
+
500
+
501
+	/**
502
+	 * _pci_dss_compliance
503
+	 *
504
+	 * @access protected
505
+	 * @param EE_Payment_Method $payment_method
506
+	 * @return EE_Form_Section_HTML
507
+	 * @throws EE_Error
508
+	 */
509
+	protected function _pci_dss_compliance(EE_Payment_Method $payment_method)
510
+	{
511
+		if ($payment_method->type_obj()->requires_https()) {
512
+			return new EE_Form_Section_HTML(
513
+				EEH_HTML::table(
514
+					EEH_HTML::tr(
515
+						EEH_HTML::th(
516
+							EEH_HTML::label(
517
+								EEH_HTML::strong(
518
+									esc_html__('IMPORTANT', 'event_espresso'),
519
+									'',
520
+									'important-notice'
521
+								)
522
+							)
523
+						) .
524
+						EEH_HTML::td(
525
+							EEH_HTML::strong(
526
+								esc_html__(
527
+									'You are responsible for your own website security and Payment Card Industry Data Security Standards (PCI DSS) compliance.',
528
+									'event_espresso'
529
+								)
530
+							)
531
+							.
532
+							EEH_HTML::br()
533
+							.
534
+							esc_html__('Learn more about ', 'event_espresso')
535
+							. EEH_HTML::link(
536
+								'https://www.pcisecuritystandards.org/merchants/index.php',
537
+								esc_html__('PCI DSS compliance', 'event_espresso')
538
+							)
539
+						)
540
+					)
541
+				)
542
+			);
543
+		}
544
+		return new EE_Form_Section_HTML('');
545
+	}
546
+
547
+
548
+	/**
549
+	 * _currency_support
550
+	 *
551
+	 * @access protected
552
+	 * @param EE_Payment_Method $payment_method
553
+	 * @return EE_Form_Section_HTML
554
+	 * @throws EE_Error
555
+	 */
556
+	protected function _currency_support(EE_Payment_Method $payment_method)
557
+	{
558
+		if (! $payment_method->usable_for_currency(EE_Config::instance()->currency->code)) {
559
+			return new EE_Form_Section_HTML(
560
+				EEH_HTML::table(
561
+					EEH_HTML::tr(
562
+						EEH_HTML::th(
563
+							EEH_HTML::label(
564
+								EEH_HTML::strong(
565
+									esc_html__('IMPORTANT', 'event_espresso'),
566
+									'',
567
+									'important-notice'
568
+								)
569
+							)
570
+						) .
571
+						EEH_HTML::td(
572
+							EEH_HTML::strong(
573
+								sprintf(
574
+									esc_html__(
575
+										'This payment method does not support the currency set on your site (%1$s). Please activate a different payment method or change your site\'s country and associated currency.',
576
+										'event_espresso'
577
+									),
578
+									EE_Config::instance()->currency->code
579
+								)
580
+							)
581
+						)
582
+					)
583
+				)
584
+			);
585
+		}
586
+		return new EE_Form_Section_HTML('');
587
+	}
588
+
589
+
590
+	/**
591
+	 * _update_payment_method_button
592
+	 *
593
+	 * @access protected
594
+	 * @param EE_Payment_Method $payment_method
595
+	 * @return EE_Payment_Method_Form
596
+	 * @throws EE_Error
597
+	 */
598
+	protected function _payment_method_settings(EE_Payment_Method $payment_method)
599
+	{
600
+		// modify the form, so we only have/show fields that will be implemented for this version
601
+		return $this->_simplify_form($payment_method->type_obj()->settings_form(), $payment_method->name());
602
+	}
603
+
604
+
605
+	/**
606
+	 * Simplifies the form to merely reproduce 4.1's gateway settings functionality
607
+	 *
608
+	 * @param EE_Form_Section_Proper $form_section
609
+	 * @param string                 $payment_method_name
610
+	 * @return EE_Payment_Method_Form
611
+	 * @throws EE_Error
612
+	 */
613
+	protected function _simplify_form($form_section, $payment_method_name = '')
614
+	{
615
+		if ($form_section instanceof EE_Payment_Method_Form) {
616
+			$form_section->exclude(
617
+				array(
618
+					'PMD_type', // don't want them changing the type
619
+					'PMD_slug', // or the slug (probably never)
620
+					'PMD_wp_user', // or the user's ID
621
+					'Currency' // or the currency, until the rest of EE supports simultaneous currencies
622
+				)
623
+			);
624
+			return $form_section;
625
+		} else {
626
+			throw new EE_Error(
627
+				sprintf(
628
+					esc_html__(
629
+						'The EE_Payment_Method_Form for the "%1$s" payment method is missing or invalid.',
630
+						'event_espresso'
631
+					),
632
+					$payment_method_name
633
+				)
634
+			);
635
+		}
636
+	}
637
+
638
+
639
+	/**
640
+	 * _update_payment_method_button
641
+	 *
642
+	 * @access protected
643
+	 * @param EE_Payment_Method $payment_method
644
+	 * @return EE_Form_Section_HTML
645
+	 * @throws EE_Error
646
+	 */
647
+	protected function _update_payment_method_button(EE_Payment_Method $payment_method)
648
+	{
649
+		$update_button = new EE_Submit_Input(
650
+			array(
651
+				'name'       => 'submit',
652
+				'html_id'    => 'save_' . $payment_method->slug() . '_settings',
653
+				'default'    => sprintf(
654
+					esc_html__('Update %s Payment Settings', 'event_espresso'),
655
+					$payment_method->admin_name()
656
+				),
657
+				'html_label' => EEH_HTML::nbsp(),
658
+			)
659
+		);
660
+		return new EE_Form_Section_HTML(
661
+			EEH_HTML::table(
662
+				EEH_HTML::no_row(EEH_HTML::br(2)) .
663
+				EEH_HTML::tr(
664
+					EEH_HTML::th(esc_html__('Update Settings', 'event_espresso')) .
665
+					EEH_HTML::td(
666
+						$update_button->get_html_for_input()
667
+					)
668
+				)
669
+			)
670
+		);
671
+	}
672
+
673
+
674
+	/**
675
+	 * _deactivate_payment_method_button
676
+	 *
677
+	 * @access protected
678
+	 * @param EE_Payment_Method $payment_method
679
+	 * @return EE_Form_Section_HTML
680
+	 */
681
+	protected function _deactivate_payment_method_button(EE_Payment_Method $payment_method)
682
+	{
683
+		$link_text_and_title = sprintf(
684
+			esc_html__('Deactivate %1$s Payments?', 'event_espresso'),
685
+			$payment_method->admin_name()
686
+		);
687
+		return new EE_Form_Section_HTML(
688
+			EEH_HTML::table(
689
+				EEH_HTML::tr(
690
+					EEH_HTML::th(esc_html__('Deactivate Payment Method', 'event_espresso')) .
691
+					EEH_HTML::td(
692
+						EEH_HTML::link(
693
+							EE_Admin_Page::add_query_args_and_nonce(
694
+								array(
695
+									'action'         => 'deactivate_payment_method',
696
+									'payment_method' => $payment_method->slug(),
697
+								),
698
+								EE_PAYMENTS_ADMIN_URL
699
+							),
700
+							$link_text_and_title,
701
+							$link_text_and_title,
702
+							'deactivate_' . $payment_method->slug(),
703
+							'button button--secondary'
704
+						)
705
+					)
706
+				)
707
+			)
708
+		);
709
+	}
710
+
711
+
712
+	/**
713
+	 * _activate_payment_method_button
714
+	 *
715
+	 * @access protected
716
+	 * @param EE_Payment_Method $payment_method
717
+	 * @return EE_Form_Section_Proper
718
+	 * @throws EE_Error
719
+	 */
720
+	protected function _activate_payment_method_button(EE_Payment_Method $payment_method)
721
+	{
722
+		$link_text_and_title = sprintf(
723
+			esc_html__('Activate %1$s Payment Method?', 'event_espresso'),
724
+			$payment_method->admin_name()
725
+		);
726
+		return new EE_Form_Section_Proper(
727
+			array(
728
+				'name'            => 'activate_' . $payment_method->slug() . '_settings_form',
729
+				'html_id'         => 'activate_' . $payment_method->slug() . '_settings_form',
730
+				'action'          => '#',
731
+				'layout_strategy' => new EE_Admin_Two_Column_Layout(),
732
+				'subsections'     => apply_filters(
733
+					'FHEE__Payments_Admin_Page___activate_payment_method_button__form_subsections',
734
+					array(
735
+						new EE_Form_Section_HTML(
736
+							EEH_HTML::table(
737
+								EEH_HTML::tr(
738
+									EEH_HTML::td(
739
+										$payment_method->type_obj()->introductory_html(),
740
+										'',
741
+										'',
742
+										'',
743
+										'colspan="2"'
744
+									)
745
+								) .
746
+								EEH_HTML::tr(
747
+									EEH_HTML::th(
748
+										EEH_HTML::label(esc_html__('Click to Activate ', 'event_espresso'))
749
+									) .
750
+									EEH_HTML::td(
751
+										EEH_HTML::link(
752
+											EE_Admin_Page::add_query_args_and_nonce(
753
+												array(
754
+													'action'              => 'activate_payment_method',
755
+													'payment_method_type' => $payment_method->type(),
756
+												),
757
+												EE_PAYMENTS_ADMIN_URL
758
+											),
759
+											$link_text_and_title,
760
+											$link_text_and_title,
761
+											'activate_' . $payment_method->slug(),
762
+											'button button--primary-alt'
763
+										)
764
+									)
765
+								)
766
+							)
767
+						),
768
+					),
769
+					$payment_method
770
+				),
771
+			)
772
+		);
773
+	}
774
+
775
+
776
+	/**
777
+	 * _fine_print
778
+	 *
779
+	 * @access protected
780
+	 * @return EE_Form_Section_HTML
781
+	 */
782
+	protected function _fine_print()
783
+	{
784
+		return new EE_Form_Section_HTML(
785
+			EEH_HTML::table(
786
+				EEH_HTML::tr(
787
+					EEH_HTML::th() .
788
+					EEH_HTML::td(
789
+						EEH_HTML::p(esc_html__('All fields marked with a * are required fields', 'event_espresso'), '', 'grey-text')
790
+					)
791
+				)
792
+			)
793
+		);
794
+	}
795
+
796
+
797
+	/**
798
+	 * Activates a payment method of that type. Mostly assuming there is only 1 of that type (or none so far)
799
+	 *
800
+	 * @throws EE_Error
801
+	 * @throws ReflectionException
802
+	 * @global WP_User $current_user
803
+	 */
804
+	protected function _activate_payment_method()
805
+	{
806
+		if (isset($this->_req_data['payment_method_type'])) {
807
+			$payment_method_type = sanitize_text_field($this->_req_data['payment_method_type']);
808
+			// see if one exists
809
+			EE_Registry::instance()->load_lib('Payment_Method_Manager');
810
+			$payment_method = EE_Payment_Method_Manager::instance()
811
+													   ->activate_a_payment_method_of_type($payment_method_type);
812
+			$this->_redirect_after_action(
813
+				1,
814
+				'Payment Method',
815
+				'activated',
816
+				array('action' => 'default', 'payment_method' => $payment_method->slug())
817
+			);
818
+		} else {
819
+			$this->_redirect_after_action(false, 'Payment Method', 'activated', array('action' => 'default'));
820
+		}
821
+	}
822
+
823
+
824
+	/**
825
+	 * @throws EE_Error
826
+	 * @throws ReflectionException
827
+	 */
828
+	protected function _deactivate_payment_method()
829
+	{
830
+		if (isset($this->_req_data['payment_method'])) {
831
+			$payment_method_slug = sanitize_key($this->_req_data['payment_method']);
832
+			// deactivate it
833
+			EE_Registry::instance()->load_lib('Payment_Method_Manager');
834
+			$count_updated = EE_Payment_Method_Manager::instance()->deactivate_payment_method($payment_method_slug);
835
+			$this->_redirect_after_action(
836
+				$count_updated,
837
+				'Payment Method',
838
+				'deactivated',
839
+				array('action' => 'default', 'payment_method' => $payment_method_slug)
840
+			);
841
+		} else {
842
+			$this->_redirect_after_action(false, 'Payment Method', 'deactivated', array('action' => 'default'));
843
+		}
844
+	}
845
+
846
+
847
+	/**
848
+	 * Processes the payment method form that was submitted. This is slightly trickier than usual form
849
+	 * processing because we first need to identify WHICH form was processed and which payment method
850
+	 * it corresponds to. Once we have done that, we see if the form is valid. If it is, the
851
+	 * form's data is saved, and we redirect to the default payment methods page, setting the updated payment method
852
+	 * as the currently-selected one. If it DOESN'T validate, we render the page with the form's errors (in the
853
+	 * subsequently called 'headers_sent_func' which is _payment_methods_list)
854
+	 *
855
+	 * @return void
856
+	 * @throws EE_Error
857
+	 * @throws ReflectionException
858
+	 */
859
+	protected function _update_payment_method()
860
+	{
861
+		if ($_SERVER['REQUEST_METHOD'] == 'POST') {
862
+			// ok let's find which gateway form to use based on the form input
863
+			EE_Registry::instance()->load_lib('Payment_Method_Manager');
864
+			/** @var $correct_pmt_form_to_use EE_Payment_Method_Form */
865
+			$correct_pmt_form_to_use = null;
866
+			$payment_method = null;
867
+			foreach (EEM_Payment_Method::instance()->get_all() as $payment_method) {
868
+				if ($payment_method instanceof EE_Payment_Method) {
869
+					// get the form and simplify it, like what we do when we display it
870
+					$pmt_form = $this->_generate_payment_method_settings_form($payment_method);
871
+					if ($pmt_form->form_data_present_in($this->_req_data)) {
872
+						$correct_pmt_form_to_use = $pmt_form;
873
+						break;
874
+					}
875
+				}
876
+			}
877
+			// if we couldn't find the correct payment method type...
878
+			if (! $correct_pmt_form_to_use) {
879
+				EE_Error::add_error(
880
+					esc_html__(
881
+						"We could not find which payment method type your form submission related to. Please contact support",
882
+						'event_espresso'
883
+					),
884
+					__FILE__,
885
+					__FUNCTION__,
886
+					__LINE__
887
+				);
888
+				$this->_redirect_after_action(false, 'Payment Method', 'activated', array('action' => 'default'));
889
+			}
890
+			$correct_pmt_form_to_use->receive_form_submission($this->_req_data);
891
+			if ($correct_pmt_form_to_use->is_valid()) {
892
+				$payment_settings_subform = $correct_pmt_form_to_use->get_subsection('payment_method_settings');
893
+				if (! $payment_settings_subform instanceof EE_Payment_Method_Form) {
894
+					throw new EE_Error(
895
+						sprintf(
896
+							esc_html__(
897
+								'The payment method could not be saved because the form sections were misnamed. We expected to find %1$s, but did not.',
898
+								'event_espresso'
899
+							),
900
+							'payment_method_settings'
901
+						)
902
+					);
903
+				}
904
+				$payment_settings_subform->save();
905
+				/** @var $pm EE_Payment_Method */
906
+				$this->_redirect_after_action(
907
+					true,
908
+					'Payment Method',
909
+					'updated',
910
+					array('action' => 'default', 'payment_method' => $payment_method->slug())
911
+				);
912
+			} else {
913
+				EE_Error::add_error(
914
+					sprintf(
915
+						esc_html__(
916
+							'Payment method of type %s was not saved because there were validation errors. They have been marked in the form',
917
+							'event_espresso'
918
+						),
919
+						$payment_method instanceof EE_Payment_Method ? $payment_method->type_obj()->pretty_name()
920
+							: esc_html__('"(unknown)"', 'event_espresso')
921
+					),
922
+					__FILE__,
923
+					__FUNCTION__,
924
+					__LINE__
925
+				);
926
+			}
927
+		}
928
+	}
929
+
930
+
931
+	/**
932
+	 * Displays payment settings (not payment METHOD settings, that's _payment_method_settings)
933
+	 * @throws DomainException
934
+	 * @throws EE_Error
935
+	 * @throws InvalidArgumentException
936
+	 * @throws InvalidDataTypeException
937
+	 * @throws InvalidInterfaceException
938
+	 */
939
+	protected function _payment_settings()
940
+	{
941
+		$form = $this->getPaymentSettingsForm();
942
+		$this->_set_add_edit_form_tags('update_payment_settings');
943
+		$this->_set_publish_post_box_vars(null, false, false, null, false);
944
+		$this->_template_args['admin_page_content'] = EEH_HTML::div(
945
+			$form->get_html_and_js(),
946
+			'',
947
+			'padding'
948
+		);
949
+		$this->display_admin_page_with_sidebar();
950
+	}
951
+
952
+
953
+	/**
954
+	 *        _update_payment_settings
955
+	 *
956
+	 * @access protected
957
+	 * @return void
958
+	 * @throws EE_Error
959
+	 * @throws InvalidArgumentException
960
+	 * @throws InvalidDataTypeException
961
+	 * @throws InvalidInterfaceException
962
+	 */
963
+	protected function _update_payment_settings()
964
+	{
965
+		$form = $this->getPaymentSettingsForm();
966
+		if ($form->was_submitted($this->_req_data)) {
967
+			$form->receive_form_submission($this->_req_data);
968
+			if ($form->is_valid()) {
969
+				/**
970
+				 * @var $reg_config EE_Registration_Config
971
+				 */
972
+				$loader = LoaderFactory::getLoader();
973
+				$reg_config = $loader->getShared('EE_Registration_Config');
974
+				$valid_data = $form->valid_data();
975
+				$reg_config->show_pending_payment_options = $valid_data['show_pending_payment_options'];
976
+				$reg_config->gateway_log_lifespan = $valid_data['gateway_log_lifespan'];
977
+			}
978
+		}
979
+		EE_Registry::instance()->CFG = apply_filters(
980
+			'FHEE__Payments_Admin_Page___update_payment_settings__CFG',
981
+			EE_Registry::instance()->CFG
982
+		);
983
+
984
+		$what = esc_html__('Payment Settings', 'event_espresso');
985
+		$success = $this->_update_espresso_configuration(
986
+			$what,
987
+			EE_Registry::instance()->CFG,
988
+			__FILE__,
989
+			__FUNCTION__,
990
+			__LINE__
991
+		);
992
+		$this->_redirect_after_action(
993
+			$success,
994
+			$what,
995
+			esc_html__('updated', 'event_espresso'),
996
+			array('action' => 'payment_settings')
997
+		);
998
+	}
999
+
1000
+
1001
+	/**
1002
+	 * Gets the form used for updating payment settings
1003
+	 *
1004
+	 * @return EE_Form_Section_Proper
1005
+	 * @throws EE_Error
1006
+	 * @throws InvalidArgumentException
1007
+	 * @throws InvalidDataTypeException
1008
+	 * @throws InvalidInterfaceException
1009
+	 */
1010
+	protected function getPaymentSettingsForm()
1011
+	{
1012
+		/**
1013
+		 * @var $reg_config EE_Registration_Config
1014
+		 */
1015
+		$reg_config = LoaderFactory::getLoader()->getShared('EE_Registration_Config');
1016
+		return new EE_Form_Section_Proper(
1017
+			array(
1018
+				'name' => 'payment-settings',
1019
+				'layout_strategy' => new EE_Admin_Two_Column_Layout(),
1020
+				'subsections' => array(
1021
+					'show_pending_payment_options' => new EE_Yes_No_Input(
1022
+						array(
1023
+							'html_name' => 'show_pending_payment_options',
1024
+							'default' => $reg_config->show_pending_payment_options,
1025
+							'html_help_text' => esc_html__(
1026
+								"If a payment is marked as 'Pending Payment', or if payment is deferred (ie, an offline gateway like Check, Bank, or Invoice is used), then give registrants the option to retry payment. ",
1027
+								'event_espresso'
1028
+							)
1029
+						)
1030
+					),
1031
+					'gateway_log_lifespan' => new EE_Select_Input(
1032
+						$reg_config->gatewayLogLifespanOptions(),
1033
+						array(
1034
+							'html_label_text' => esc_html__('Gateway Logs Lifespan', 'event_espresso'),
1035
+							'html_help_text' => esc_html__('If issues arise with payments being made through a payment gateway, it\'s helpful to log non-sensitive communications with the payment gateway. But it\'s a security responsibility, so it\'s a good idea to not keep them for any longer than necessary.', 'event_espresso'),
1036
+							'default' => $reg_config->gateway_log_lifespan,
1037
+						)
1038
+					)
1039
+				)
1040
+			)
1041
+		);
1042
+	}
1043
+
1044
+
1045
+	/**
1046
+	 * @throws EE_Error
1047
+	 */
1048
+	protected function _payment_log_overview_list_table()
1049
+	{
1050
+		$this->display_admin_list_table_page_with_sidebar();
1051
+	}
1052
+
1053
+
1054
+	protected function _set_list_table_views_payment_log()
1055
+	{
1056
+		$this->_views = array(
1057
+			'all' => array(
1058
+				'slug'  => 'all',
1059
+				'label' => esc_html__('View All Logs', 'event_espresso'),
1060
+				'count' => 0,
1061
+			),
1062
+		);
1063
+	}
1064
+
1065
+
1066
+	/**
1067
+	 * @param int  $per_page
1068
+	 * @param int  $current_page
1069
+	 * @param bool $count
1070
+	 * @return array|int
1071
+	 * @throws EE_Error
1072
+	 * @throws ReflectionException
1073
+	 */
1074
+	public function get_payment_logs($per_page = 50, $current_page = 0, $count = false)
1075
+	{
1076
+		EE_Registry::instance()->load_model('Change_Log');
1077
+		// we may need to do multiple queries (joining differently), so we actually want an array of query params
1078
+		$query_params = array(array('LOG_type' => EEM_Change_Log::type_gateway));
1079
+		// check if they've selected a specific payment method
1080
+		if (isset($this->_req_data['_payment_method']) && $this->_req_data['_payment_method'] !== 'all') {
1081
+			$query_params[0]['OR*pm_or_pay_pm'] = array(
1082
+				'Payment.Payment_Method.PMD_ID' => $this->_req_data['_payment_method'],
1083
+				'Payment_Method.PMD_ID'         => $this->_req_data['_payment_method'],
1084
+			);
1085
+		}
1086
+		// take into account search
1087
+		if (isset($this->_req_data['s']) && $this->_req_data['s']) {
1088
+			$similarity_string = array('LIKE', '%' . str_replace("", "%", $this->_req_data['s']) . '%');
1089
+			$query_params[0]['OR*s']['Payment.Transaction.Registration.Attendee.ATT_fname'] = $similarity_string;
1090
+			$query_params[0]['OR*s']['Payment.Transaction.Registration.Attendee.ATT_lname'] = $similarity_string;
1091
+			$query_params[0]['OR*s']['Payment.Transaction.Registration.Attendee.ATT_email'] = $similarity_string;
1092
+			$query_params[0]['OR*s']['Payment.Payment_Method.PMD_name'] = $similarity_string;
1093
+			$query_params[0]['OR*s']['Payment.Payment_Method.PMD_admin_name'] = $similarity_string;
1094
+			$query_params[0]['OR*s']['Payment.Payment_Method.PMD_type'] = $similarity_string;
1095
+			$query_params[0]['OR*s']['LOG_message'] = $similarity_string;
1096
+			$query_params[0]['OR*s']['Payment_Method.PMD_name'] = $similarity_string;
1097
+			$query_params[0]['OR*s']['Payment_Method.PMD_admin_name'] = $similarity_string;
1098
+			$query_params[0]['OR*s']['Payment_Method.PMD_type'] = $similarity_string;
1099
+			$query_params[0]['OR*s']['LOG_message'] = $similarity_string;
1100
+		}
1101
+		if (
1102
+			isset($this->_req_data['payment-filter-start-date'])
1103
+			&& isset($this->_req_data['payment-filter-end-date'])
1104
+		) {
1105
+			// add date
1106
+			$start_date = wp_strip_all_tags($this->_req_data['payment-filter-start-date']);
1107
+			$end_date = wp_strip_all_tags($this->_req_data['payment-filter-end-date']);
1108
+			// make sure our timestamps start and end right at the boundaries for each day
1109
+			$start_date = date('Y-m-d', strtotime($start_date)) . ' 00:00:00';
1110
+			$end_date = date('Y-m-d', strtotime($end_date)) . ' 23:59:59';
1111
+			// convert to timestamps
1112
+			$start_date = strtotime($start_date);
1113
+			$end_date = strtotime($end_date);
1114
+			// makes sure start date is the lowest value and vice versa
1115
+			$start_date = min($start_date, $end_date);
1116
+			$end_date = max($start_date, $end_date);
1117
+			// convert for query
1118
+			$start_date = EEM_Change_Log::instance()->convert_datetime_for_query(
1119
+				'LOG_time',
1120
+				date('Y-m-d H:i:s', $start_date),
1121
+				'Y-m-d H:i:s'
1122
+			);
1123
+			$end_date   = EEM_Change_Log::instance()->convert_datetime_for_query(
1124
+				'LOG_time',
1125
+				date('Y-m-d H:i:s', $end_date),
1126
+				'Y-m-d H:i:s'
1127
+			);
1128
+			$query_params[0]['LOG_time'] = array('BETWEEN', array($start_date, $end_date));
1129
+		}
1130
+		if ($count) {
1131
+			return EEM_Change_Log::instance()->count($query_params);
1132
+		}
1133
+		if (isset($this->_req_data['order'])) {
1134
+			$sort = (isset($this->_req_data['order']) && ! empty($this->_req_data['order']))
1135
+				? $this->_req_data['order']
1136
+				: 'DESC';
1137
+			$query_params['order_by'] = array('LOG_time' => $sort);
1138
+		} else {
1139
+			$query_params['order_by'] = array('LOG_time' => 'DESC');
1140
+		}
1141
+		$offset = ($current_page - 1) * $per_page;
1142
+		if (! isset($this->_req_data['download_results'])) {
1143
+			$query_params['limit'] = array($offset, $per_page);
1144
+		}
1145
+		// now they've requested to instead just download the file instead of viewing it.
1146
+		if (isset($this->_req_data['download_results'])) {
1147
+			$wpdb_results = EEM_Change_Log::instance()->get_all_efficiently($query_params);
1148
+			header('Content-Disposition: attachment');
1149
+			header("Content-Disposition: attachment; filename=ee_payment_logs_for_" . sanitize_key(site_url()));
1150
+			echo '<h1> '
1151
+				. sprintf(
1152
+					esc_html__('Payment Logs for %1$s', 'event_espresso'),
1153
+					esc_url_raw(site_url())
1154
+				)
1155
+				. '</h1 >';
1156
+			echo '<h3>' . esc_html__('Query:', 'event_espresso') . '</h3>';
1157
+			echo esc_html(var_export($query_params, true));
1158
+			echo '<h3>' . esc_html__('Results:', 'event_espresso') . '</h3>';
1159
+			echo esc_html(var_export($wpdb_results, true));
1160
+			die;
1161
+		}
1162
+		return EEM_Change_Log::instance()->get_all($query_params);
1163
+	}
1164
+
1165
+
1166
+	/**
1167
+	 * Used by usort to RE-sort log query results, because we lose the ordering
1168
+	 * because we're possibly combining the results from two queries
1169
+	 *
1170
+	 * @param EE_Change_Log $logA
1171
+	 * @param EE_Change_Log $logB
1172
+	 * @return int
1173
+	 * @throws EE_Error
1174
+	 * @throws ReflectionException
1175
+	 */
1176
+	protected function _sort_logs_again($logA, $logB)
1177
+	{
1178
+		$timeA = $logA->get_raw('LOG_time');
1179
+		$timeB = $logB->get_raw('LOG_time');
1180
+		if ($timeA == $timeB) {
1181
+			return 0;
1182
+		}
1183
+		$comparison = $timeA < $timeB ? -1 : 1;
1184
+		if (strtoupper($this->_sort_logs_again_direction) == 'DESC') {
1185
+			return $comparison * -1;
1186
+		}
1187
+		return $comparison;
1188
+	}
1189
+
1190
+
1191
+	/**
1192
+	 * @throws EE_Error
1193
+	 * @throws ReflectionException
1194
+	 */
1195
+	protected function _payment_log_details()
1196
+	{
1197
+		EE_Registry::instance()->load_model('Change_Log');
1198
+		/** @var $payment_log EE_Change_Log */
1199
+		$payment_log = EEM_Change_Log::instance()->get_one_by_ID($this->_req_data['ID']);
1200
+		$payment_method = null;
1201
+		$transaction = null;
1202
+		if ($payment_log instanceof EE_Change_Log) {
1203
+			if ($payment_log->object() instanceof EE_Payment) {
1204
+				$payment_method = $payment_log->object()->payment_method();
1205
+				$transaction = $payment_log->object()->transaction();
1206
+			} elseif ($payment_log->object() instanceof EE_Payment_Method) {
1207
+				$payment_method = $payment_log->object();
1208
+			} elseif ($payment_log->object() instanceof EE_Transaction) {
1209
+				$transaction = $payment_log->object();
1210
+				$payment_method = $transaction->payment_method();
1211
+			}
1212
+		}
1213
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
1214
+			EE_PAYMENTS_TEMPLATE_PATH . 'payment_log_details.template.php',
1215
+			array(
1216
+				'payment_log'    => $payment_log,
1217
+				'payment_method' => $payment_method,
1218
+				'transaction'    => $transaction,
1219
+			),
1220
+			true
1221
+		);
1222
+		$this->display_admin_page_with_no_sidebar();
1223
+	}
1224 1224
 }
Please login to merge, or discard this patch.
admin_pages/about/About_Admin_Page.core.php 1 patch
Indentation   +278 added lines, -278 removed lines patch added patch discarded remove patch
@@ -15,132 +15,132 @@  discard block
 block discarded – undo
15 15
  */
16 16
 class About_Admin_Page extends EE_Admin_Page
17 17
 {
18
-    protected function _init_page_props()
19
-    {
20
-        $this->page_slug = EE_ABOUT_PG_SLUG;
21
-        $this->page_label = esc_html__('About Event Espresso', 'event_espresso');
22
-        $this->_admin_base_url = EE_ABOUT_ADMIN_URL;
23
-        $this->_admin_base_path = EE_ABOUT_ADMIN;
24
-    }
25
-
26
-
27
-    protected function _ajax_hooks()
28
-    {
29
-        // todo: all hooks for ajax goes here.
30
-    }
31
-
32
-
33
-    protected function _define_page_props()
34
-    {
35
-        $this->_labels = array();
36
-        $this->_admin_page_title = $this->page_label;
37
-    }
38
-
39
-
40
-    protected function _set_page_routes()
41
-    {
42
-        $this->_page_routes = array(
43
-            'default' => array(
44
-                'func'       => '_overview',
45
-                'capability' => 'manage_options',
46
-            ),
47
-            // 'overview' => '_overview',
48
-            // 'func' => '_overview',
49
-            // 'capability' => 'ee_read_ee'
50
-            // ),
51
-            'credits' => array(
52
-                'func'       => '_credits',
53
-                'capability' => 'manage_options',
54
-            ),
55
-
56
-            'decafvpro' => array(
57
-                'func'       => '_decafvpro',
58
-                'capability' => 'manage_options',
59
-            ),
60
-            'reviews'   => array(
61
-                'func'       => '_reviews',
62
-                'capability' => 'manage_options',
63
-            ),
64
-        );
65
-    }
66
-
67
-
68
-    protected function _set_page_config()
69
-    {
70
-        $this->_page_config = array(
71
-            /*'default' => array(
18
+	protected function _init_page_props()
19
+	{
20
+		$this->page_slug = EE_ABOUT_PG_SLUG;
21
+		$this->page_label = esc_html__('About Event Espresso', 'event_espresso');
22
+		$this->_admin_base_url = EE_ABOUT_ADMIN_URL;
23
+		$this->_admin_base_path = EE_ABOUT_ADMIN;
24
+	}
25
+
26
+
27
+	protected function _ajax_hooks()
28
+	{
29
+		// todo: all hooks for ajax goes here.
30
+	}
31
+
32
+
33
+	protected function _define_page_props()
34
+	{
35
+		$this->_labels = array();
36
+		$this->_admin_page_title = $this->page_label;
37
+	}
38
+
39
+
40
+	protected function _set_page_routes()
41
+	{
42
+		$this->_page_routes = array(
43
+			'default' => array(
44
+				'func'       => '_overview',
45
+				'capability' => 'manage_options',
46
+			),
47
+			// 'overview' => '_overview',
48
+			// 'func' => '_overview',
49
+			// 'capability' => 'ee_read_ee'
50
+			// ),
51
+			'credits' => array(
52
+				'func'       => '_credits',
53
+				'capability' => 'manage_options',
54
+			),
55
+
56
+			'decafvpro' => array(
57
+				'func'       => '_decafvpro',
58
+				'capability' => 'manage_options',
59
+			),
60
+			'reviews'   => array(
61
+				'func'       => '_reviews',
62
+				'capability' => 'manage_options',
63
+			),
64
+		);
65
+	}
66
+
67
+
68
+	protected function _set_page_config()
69
+	{
70
+		$this->_page_config = array(
71
+			/*'default' => array(
72 72
                 'nav' => array(
73 73
                     'label' => esc_html__('What\'s New', 'event_espresso'),
74 74
                     'order' => 10),
75 75
                 'require_nonce' => FALSE
76 76
                 ),*/
77
-            // 'overview' => array(
78
-            'default' => array(
79
-                'nav'           => array(
80
-                    'label' => esc_html__('About', 'event_espresso'),
81
-                    'icon' => 'dashicons-welcome-learn-more',
82
-                    'order' => 20,
83
-                ),
84
-                'require_nonce' => false,
85
-            ),
86
-            'credits' => array(
87
-                'nav'           => array(
88
-                    'label' => esc_html__('Credits', 'event_espresso'),
89
-                    'icon' => 'dashicons-thumbs-up',
90
-                    'order' => 30,
91
-                ),
92
-                'require_nonce' => false,
93
-            ),
94
-
95
-            'decafvpro' => array(
96
-                'nav'           => array(
97
-                    'label' => esc_html__('Decaf vs Regular', 'event_espresso'),
98
-                    'icon' => 'dashicons-editor-code',
99
-                    'order' => 40,
100
-                ),
101
-                'require_nonce' => false,
102
-            ),
103
-            'reviews'   => array(
104
-                'nav'           => array(
105
-                    'label' => esc_html__('Reviews', 'event_espresso'),
106
-                    'icon' => 'dashicons-star-filled',
107
-                    'order' => 50,
108
-                ),
109
-                'require_nonce' => false,
110
-            ),
111
-        );
112
-    }
113
-
114
-
115
-    // none of the below group are currently used for Support pages
116
-    protected function _add_screen_options()
117
-    {
118
-    }
119
-
120
-    protected function _add_feature_pointers()
121
-    {
122
-    }
123
-
124
-    public function admin_init()
125
-    {
126
-    }
127
-
128
-    public function admin_notices()
129
-    {
130
-    }
131
-
132
-    public function admin_footer_scripts()
133
-    {
134
-    }
135
-
136
-    public function load_scripts_styles()
137
-    {
138
-    }
139
-
140
-
141
-    protected function _whats_new()
142
-    {
143
-        /*$steps = EE_Maintenance_Mode::instance()->level() != EE_Maintenance_Mode::level_2_complete_maintenance ? $this->_get_started_steps() : FALSE;
77
+			// 'overview' => array(
78
+			'default' => array(
79
+				'nav'           => array(
80
+					'label' => esc_html__('About', 'event_espresso'),
81
+					'icon' => 'dashicons-welcome-learn-more',
82
+					'order' => 20,
83
+				),
84
+				'require_nonce' => false,
85
+			),
86
+			'credits' => array(
87
+				'nav'           => array(
88
+					'label' => esc_html__('Credits', 'event_espresso'),
89
+					'icon' => 'dashicons-thumbs-up',
90
+					'order' => 30,
91
+				),
92
+				'require_nonce' => false,
93
+			),
94
+
95
+			'decafvpro' => array(
96
+				'nav'           => array(
97
+					'label' => esc_html__('Decaf vs Regular', 'event_espresso'),
98
+					'icon' => 'dashicons-editor-code',
99
+					'order' => 40,
100
+				),
101
+				'require_nonce' => false,
102
+			),
103
+			'reviews'   => array(
104
+				'nav'           => array(
105
+					'label' => esc_html__('Reviews', 'event_espresso'),
106
+					'icon' => 'dashicons-star-filled',
107
+					'order' => 50,
108
+				),
109
+				'require_nonce' => false,
110
+			),
111
+		);
112
+	}
113
+
114
+
115
+	// none of the below group are currently used for Support pages
116
+	protected function _add_screen_options()
117
+	{
118
+	}
119
+
120
+	protected function _add_feature_pointers()
121
+	{
122
+	}
123
+
124
+	public function admin_init()
125
+	{
126
+	}
127
+
128
+	public function admin_notices()
129
+	{
130
+	}
131
+
132
+	public function admin_footer_scripts()
133
+	{
134
+	}
135
+
136
+	public function load_scripts_styles()
137
+	{
138
+	}
139
+
140
+
141
+	protected function _whats_new()
142
+	{
143
+		/*$steps = EE_Maintenance_Mode::instance()->level() != EE_Maintenance_Mode::level_2_complete_maintenance ? $this->_get_started_steps() : FALSE;
144 144
         $steps = $steps !== FALSE ? $steps : '';
145 145
         $this->_admin_page_title = sprintf( esc_html__('Welcome to Event Espresso %s', 'event_espresso'), EVENT_ESPRESSO_VERSION );
146 146
         $settings_message = $steps;
@@ -148,168 +148,168 @@  discard block
 block discarded – undo
148 148
         $template = EE_ABOUT_TEMPLATE_PATH . 'whats_new.template.php';
149 149
         $this->_template_args['about_admin_page_content'] = EEH_Template::display_template( $template, $this->_template_args, TRUE );
150 150
         $this->display_about_admin_page();*/
151
-    }
151
+	}
152 152
 
153 153
 
154
-    protected function _overview()
155
-    {
156
-        /*$this->_template_args['admin_page_title'] = esc_html__('About Event Espresso', 'event_espresso');
154
+	protected function _overview()
155
+	{
156
+		/*$this->_template_args['admin_page_title'] = esc_html__('About Event Espresso', 'event_espresso');
157 157
         $this->_template_args['admin_page_subtitle'] = esc_html__('Thank you for choosing Event Espresso Decaf, the most powerful, and free, Event Management plugin for WordPress.', 'event_espresso');
158 158
         $template = EE_ABOUT_TEMPLATE_PATH . 'ee4-overview.template.php';
159 159
         $this->_template_args['about_admin_page_content'] = EEH_Template::display_template( $template, $this->_template_args, TRUE );
160 160
         $this->display_about_admin_page();*/
161 161
 
162
-        // Copied from _whats_new()
163
-        $steps = EE_Maintenance_Mode::instance()->level() != EE_Maintenance_Mode::level_2_complete_maintenance
164
-            ? $this->_get_started_steps() : false;
165
-        $steps = $steps !== false ? $steps : '';
166
-        $this->_admin_page_title = sprintf(
167
-            esc_html__('Welcome to Event Espresso %s', 'event_espresso'),
168
-            EVENT_ESPRESSO_VERSION
169
-        );
170
-        $settings_message = $steps;
171
-        $this->_template_args['admin_page_subtitle'] = esc_html__(
172
-            'Thank you for choosing Event Espresso, the most powerful, and free, Event Management plugin for WordPress.',
173
-            'event_espresso'
174
-        ) . $settings_message;
175
-        $template = EE_ABOUT_TEMPLATE_PATH . 'ee4-overview.template.php';
176
-        $this->_template_args['about_admin_page_content'] = EEH_Template::display_template(
177
-            $template,
178
-            $this->_template_args,
179
-            true
180
-        );
181
-        $this->display_about_admin_page();
182
-    }
183
-
184
-
185
-    protected function _get_started_steps()
186
-    {
187
-        $steps = '<h2>' . esc_html__('Getting Started', 'event_espresso') . '</h2>';
188
-        $step_one = '<p>'
189
-                    . sprintf(
190
-                        esc_html__(
191
-                            '%sStep 1%s: Visit your %sOrganization Settings%s and add/update your details.',
192
-                            'event_espresso'
193
-                        ),
194
-                        '<strong>',
195
-                        '</strong>',
196
-                        '<a href="admin.php?page=espresso_general_settings">',
197
-                        '</a>'
198
-                    ) . '</strong></p>';
199
-        $step_two = '<p>'
200
-                    . sprintf(
201
-                        esc_html__('%sStep 2%s: Setup your %sPayment Methods%s.', 'event_espresso'),
202
-                        '<strong>',
203
-                        '</strong>',
204
-                        '<a href="admin.php?page=espresso_payment_settings">',
205
-                        '</a>'
206
-                    ) . '</strong></p>';
207
-        $step_three = '<p>'
208
-                      . sprintf(
209
-                          esc_html__('%sStep 3%s: Create your %sFirst Event%s.', 'event_espresso'),
210
-                          '<strong>',
211
-                          '</strong>',
212
-                          '<a href="admin.php?page=espresso_events&action=create_new">',
213
-                          '</a>'
214
-                      ) . '</strong></p>';
215
-
216
-        // done?
217
-        $done_step_one = EE_Registry::instance()->CFG->organization->address_1 == '123 Onna Road' ? false : true;
218
-        $active_invoice_pm = EEM_Payment_Method::instance()->get_one_active(
219
-            EEM_Payment_Method::scope_cart,
220
-            array(array('PMD_type' => 'Invoice'))
221
-        );
222
-        $active_pms_count = EEM_Payment_Method::instance()->count_active(EEM_Payment_Method::scope_cart);
223
-        // done step two if a non-invoice paymetn method is active; or there is more than one PM active, or
224
-        // if only the invoice is active but it's clearly been updated
225
-        $done_step_two = $active_pms_count > 1 ||
226
-                         ($active_pms_count === 1 && ! $active_invoice_pm) ||
227
-                         ($active_invoice_pm instanceof EE_Payment_Method && (
228
-                                 $active_invoice_pm->get_extra_meta('pdf_payee_name', true, '') ||
229
-                                 $active_invoice_pm->get_extra_meta('pdf_payee_email', true, '') ||
230
-                                 $active_invoice_pm->get_extra_meta('pdf_payee_tax_number', true, '') ||
231
-                                 $active_invoice_pm->get_extra_meta('pdf_payee_address', true, '') ||
232
-                                 $active_invoice_pm->get_extra_meta('page_extra_info', true, '')
233
-                             )
234
-                         );
235
-        $done_step_three = EE_Registry::instance()->load_model('Event')->count() > 0 ? true : false;
236
-
237
-        // if ALL steps are done, let's just return FALSE so we don't display anything
238
-        if ($done_step_one && $done_step_two && $done_step_three) {
239
-            return false;
240
-        }
241
-
242
-        // now let's put it together
243
-        $steps .= sprintf('%s' . $step_one . '%s', $done_step_one ? '<strike>' : '', $done_step_one ? '</strike>' : '');
244
-        $steps .= sprintf('%s' . $step_two . '%s', $done_step_two ? '<strike>' : '', $done_step_two ? '</strike>' : '');
245
-        $steps .= sprintf(
246
-            '%s' . $step_three . '%s',
247
-            $done_step_three ? '<strike>' : '',
248
-            $done_step_three ? '</strike>' : ''
249
-        );
250
-
251
-        return $steps;
252
-    }
253
-
254
-
255
-    protected function _credits()
256
-    {
257
-        $this->_template_args['admin_page_title'] = sprintf(
258
-            esc_html__('Welcome to Event Espresso %s', 'event_espresso'),
259
-            EVENT_ESPRESSO_VERSION
260
-        );
261
-        $this->_template_args['admin_page_subtitle'] = esc_html__(
262
-            'Thank you for choosing Event Espresso Decaf, the most powerful, and free, Event Management plugin for WordPress.',
263
-            'event_espresso'
264
-        );
265
-        $template = EE_ABOUT_TEMPLATE_PATH . 'credits.template.php';
266
-        $this->_template_args['about_admin_page_content'] = EEH_Template::display_template(
267
-            $template,
268
-            $this->_template_args,
269
-            true
270
-        );
271
-        $this->display_about_admin_page();
272
-    }
273
-
274
-
275
-    protected function _decafvpro()
276
-    {
277
-        $this->_template_args['admin_page_title'] = sprintf(
278
-            esc_html__('Welcome to Event Espresso %s', 'event_espresso'),
279
-            EVENT_ESPRESSO_VERSION
280
-        );
281
-        $this->_template_args['admin_page_subtitle'] = sprintf(
282
-            esc_html__(
283
-                'Event Espresso lets you focus on doing %swhat you love%s — %sorganizing your events%s',
284
-                'event_espresso'
285
-            ),
286
-            '<em>',
287
-            '</em>',
288
-            '<strong>',
289
-            '</strong>'
290
-        );
291
-        $template = EE_ABOUT_TEMPLATE_PATH . 'decafvpro.template.php';
292
-        $this->_template_args['about_admin_page_content'] = EEH_Template::display_template(
293
-            $template,
294
-            $this->_template_args,
295
-            true
296
-        );
297
-        $this->display_about_admin_page();
298
-    }
299
-
300
-    protected function _reviews()
301
-    {
302
-        $this->_template_args['admin_page_title'] = esc_html__('Rave Reviews About Event Espresso 4', 'event_espresso');
303
-        $this->_template_args['admin_page_subtitle'] = esc_html__(
304
-            'At Event Espresso, customer satisfaction is our ultimate goal.',
305
-            'event_espresso'
306
-        );
307
-        $template = EE_ABOUT_TEMPLATE_PATH . 'reviews.template.php';
308
-        $this->_template_args['about_admin_page_content'] = EEH_Template::display_template(
309
-            $template,
310
-            $this->_template_args,
311
-            true
312
-        );
313
-        $this->display_about_admin_page();
314
-    }
162
+		// Copied from _whats_new()
163
+		$steps = EE_Maintenance_Mode::instance()->level() != EE_Maintenance_Mode::level_2_complete_maintenance
164
+			? $this->_get_started_steps() : false;
165
+		$steps = $steps !== false ? $steps : '';
166
+		$this->_admin_page_title = sprintf(
167
+			esc_html__('Welcome to Event Espresso %s', 'event_espresso'),
168
+			EVENT_ESPRESSO_VERSION
169
+		);
170
+		$settings_message = $steps;
171
+		$this->_template_args['admin_page_subtitle'] = esc_html__(
172
+			'Thank you for choosing Event Espresso, the most powerful, and free, Event Management plugin for WordPress.',
173
+			'event_espresso'
174
+		) . $settings_message;
175
+		$template = EE_ABOUT_TEMPLATE_PATH . 'ee4-overview.template.php';
176
+		$this->_template_args['about_admin_page_content'] = EEH_Template::display_template(
177
+			$template,
178
+			$this->_template_args,
179
+			true
180
+		);
181
+		$this->display_about_admin_page();
182
+	}
183
+
184
+
185
+	protected function _get_started_steps()
186
+	{
187
+		$steps = '<h2>' . esc_html__('Getting Started', 'event_espresso') . '</h2>';
188
+		$step_one = '<p>'
189
+					. sprintf(
190
+						esc_html__(
191
+							'%sStep 1%s: Visit your %sOrganization Settings%s and add/update your details.',
192
+							'event_espresso'
193
+						),
194
+						'<strong>',
195
+						'</strong>',
196
+						'<a href="admin.php?page=espresso_general_settings">',
197
+						'</a>'
198
+					) . '</strong></p>';
199
+		$step_two = '<p>'
200
+					. sprintf(
201
+						esc_html__('%sStep 2%s: Setup your %sPayment Methods%s.', 'event_espresso'),
202
+						'<strong>',
203
+						'</strong>',
204
+						'<a href="admin.php?page=espresso_payment_settings">',
205
+						'</a>'
206
+					) . '</strong></p>';
207
+		$step_three = '<p>'
208
+					  . sprintf(
209
+						  esc_html__('%sStep 3%s: Create your %sFirst Event%s.', 'event_espresso'),
210
+						  '<strong>',
211
+						  '</strong>',
212
+						  '<a href="admin.php?page=espresso_events&action=create_new">',
213
+						  '</a>'
214
+					  ) . '</strong></p>';
215
+
216
+		// done?
217
+		$done_step_one = EE_Registry::instance()->CFG->organization->address_1 == '123 Onna Road' ? false : true;
218
+		$active_invoice_pm = EEM_Payment_Method::instance()->get_one_active(
219
+			EEM_Payment_Method::scope_cart,
220
+			array(array('PMD_type' => 'Invoice'))
221
+		);
222
+		$active_pms_count = EEM_Payment_Method::instance()->count_active(EEM_Payment_Method::scope_cart);
223
+		// done step two if a non-invoice paymetn method is active; or there is more than one PM active, or
224
+		// if only the invoice is active but it's clearly been updated
225
+		$done_step_two = $active_pms_count > 1 ||
226
+						 ($active_pms_count === 1 && ! $active_invoice_pm) ||
227
+						 ($active_invoice_pm instanceof EE_Payment_Method && (
228
+								 $active_invoice_pm->get_extra_meta('pdf_payee_name', true, '') ||
229
+								 $active_invoice_pm->get_extra_meta('pdf_payee_email', true, '') ||
230
+								 $active_invoice_pm->get_extra_meta('pdf_payee_tax_number', true, '') ||
231
+								 $active_invoice_pm->get_extra_meta('pdf_payee_address', true, '') ||
232
+								 $active_invoice_pm->get_extra_meta('page_extra_info', true, '')
233
+							 )
234
+						 );
235
+		$done_step_three = EE_Registry::instance()->load_model('Event')->count() > 0 ? true : false;
236
+
237
+		// if ALL steps are done, let's just return FALSE so we don't display anything
238
+		if ($done_step_one && $done_step_two && $done_step_three) {
239
+			return false;
240
+		}
241
+
242
+		// now let's put it together
243
+		$steps .= sprintf('%s' . $step_one . '%s', $done_step_one ? '<strike>' : '', $done_step_one ? '</strike>' : '');
244
+		$steps .= sprintf('%s' . $step_two . '%s', $done_step_two ? '<strike>' : '', $done_step_two ? '</strike>' : '');
245
+		$steps .= sprintf(
246
+			'%s' . $step_three . '%s',
247
+			$done_step_three ? '<strike>' : '',
248
+			$done_step_three ? '</strike>' : ''
249
+		);
250
+
251
+		return $steps;
252
+	}
253
+
254
+
255
+	protected function _credits()
256
+	{
257
+		$this->_template_args['admin_page_title'] = sprintf(
258
+			esc_html__('Welcome to Event Espresso %s', 'event_espresso'),
259
+			EVENT_ESPRESSO_VERSION
260
+		);
261
+		$this->_template_args['admin_page_subtitle'] = esc_html__(
262
+			'Thank you for choosing Event Espresso Decaf, the most powerful, and free, Event Management plugin for WordPress.',
263
+			'event_espresso'
264
+		);
265
+		$template = EE_ABOUT_TEMPLATE_PATH . 'credits.template.php';
266
+		$this->_template_args['about_admin_page_content'] = EEH_Template::display_template(
267
+			$template,
268
+			$this->_template_args,
269
+			true
270
+		);
271
+		$this->display_about_admin_page();
272
+	}
273
+
274
+
275
+	protected function _decafvpro()
276
+	{
277
+		$this->_template_args['admin_page_title'] = sprintf(
278
+			esc_html__('Welcome to Event Espresso %s', 'event_espresso'),
279
+			EVENT_ESPRESSO_VERSION
280
+		);
281
+		$this->_template_args['admin_page_subtitle'] = sprintf(
282
+			esc_html__(
283
+				'Event Espresso lets you focus on doing %swhat you love%s — %sorganizing your events%s',
284
+				'event_espresso'
285
+			),
286
+			'<em>',
287
+			'</em>',
288
+			'<strong>',
289
+			'</strong>'
290
+		);
291
+		$template = EE_ABOUT_TEMPLATE_PATH . 'decafvpro.template.php';
292
+		$this->_template_args['about_admin_page_content'] = EEH_Template::display_template(
293
+			$template,
294
+			$this->_template_args,
295
+			true
296
+		);
297
+		$this->display_about_admin_page();
298
+	}
299
+
300
+	protected function _reviews()
301
+	{
302
+		$this->_template_args['admin_page_title'] = esc_html__('Rave Reviews About Event Espresso 4', 'event_espresso');
303
+		$this->_template_args['admin_page_subtitle'] = esc_html__(
304
+			'At Event Espresso, customer satisfaction is our ultimate goal.',
305
+			'event_espresso'
306
+		);
307
+		$template = EE_ABOUT_TEMPLATE_PATH . 'reviews.template.php';
308
+		$this->_template_args['about_admin_page_content'] = EEH_Template::display_template(
309
+			$template,
310
+			$this->_template_args,
311
+			true
312
+		);
313
+		$this->display_about_admin_page();
314
+	}
315 315
 }
Please login to merge, or discard this patch.
admin_pages/about/templates/credits.template.php 2 patches
Indentation   +86 added lines, -86 removed lines patch added patch discarded remove patch
@@ -1,61 +1,61 @@  discard block
 block discarded – undo
1 1
 <?php
2 2
 $tEEm_members = [
3
-    esc_html__('Founders', 'event_espresso') => [
4
-        'garth-koyle' => [
5
-            'email' => '[email protected]',
6
-            'name'  => 'Garth Koyle',
7
-            'desc'  => esc_html__('Co-Founder', 'event_espresso'),
8
-        ],
9
-    ],
10
-    esc_html__('Core Developers', 'event_espresso') => [
11
-        'brent-christensen' => [
12
-            'email' => '[email protected]',
13
-            'name'  => 'Brent Christensen',
14
-            'desc'  => esc_html__('Lead Developer', 'event_espresso'),
15
-        ],
16
-        'nazar-kolivoshka' => [
17
-            'email' => '[email protected]',
18
-            'name'  => 'Nazar Kolivoshka',
19
-            'desc'  => esc_html__('Core Developer', 'event_espresso'),
20
-        ],
21
-        'marlon-hario' => [
22
-            'email' => '[email protected]',
23
-            'name'  => 'Marlon Hario',
24
-            'desc'  => esc_html__('Core Developer', 'event_espresso'),
25
-        ],
26
-        'hossein-rafiei' => [
27
-            'email' => '[email protected]',
28
-            'name'  => 'Hossein Rafiei',
29
-            'desc'  => esc_html__('Core Developer', 'event_espresso'),
30
-        ],
31
-    ],
32
-    esc_html__('Support Staff', 'event_espresso') => [
33
-        'tony-warwick' => [
34
-            'email' => '[email protected]',
35
-            'name'  => 'Tony Warwick',
36
-            'desc'  => esc_html__('Support', 'event_espresso'),
37
-        ],
38
-        'lorenzo-caum' => [
39
-            'email' => '[email protected]',
40
-            'name'  => 'Lorenzo Caum',
41
-            'desc'  => esc_html__('Sales & Support', 'event_espresso'),
42
-        ],
43
-        'janice-gutierrez' => [
44
-            'email' => '[email protected]',
45
-            'name'  => 'Janice Gutierrez',
46
-            'desc'  => esc_html__('Support', 'event_espresso'),
47
-        ],
48
-        'chinny-love-verana' => [
49
-            'email' => '[email protected]',
50
-            'name'  => 'Chinny Love Verana',
51
-            'desc'  => esc_html__('Sales & Support', 'event_espresso'),
52
-        ],
53
-    ],
3
+	esc_html__('Founders', 'event_espresso') => [
4
+		'garth-koyle' => [
5
+			'email' => '[email protected]',
6
+			'name'  => 'Garth Koyle',
7
+			'desc'  => esc_html__('Co-Founder', 'event_espresso'),
8
+		],
9
+	],
10
+	esc_html__('Core Developers', 'event_espresso') => [
11
+		'brent-christensen' => [
12
+			'email' => '[email protected]',
13
+			'name'  => 'Brent Christensen',
14
+			'desc'  => esc_html__('Lead Developer', 'event_espresso'),
15
+		],
16
+		'nazar-kolivoshka' => [
17
+			'email' => '[email protected]',
18
+			'name'  => 'Nazar Kolivoshka',
19
+			'desc'  => esc_html__('Core Developer', 'event_espresso'),
20
+		],
21
+		'marlon-hario' => [
22
+			'email' => '[email protected]',
23
+			'name'  => 'Marlon Hario',
24
+			'desc'  => esc_html__('Core Developer', 'event_espresso'),
25
+		],
26
+		'hossein-rafiei' => [
27
+			'email' => '[email protected]',
28
+			'name'  => 'Hossein Rafiei',
29
+			'desc'  => esc_html__('Core Developer', 'event_espresso'),
30
+		],
31
+	],
32
+	esc_html__('Support Staff', 'event_espresso') => [
33
+		'tony-warwick' => [
34
+			'email' => '[email protected]',
35
+			'name'  => 'Tony Warwick',
36
+			'desc'  => esc_html__('Support', 'event_espresso'),
37
+		],
38
+		'lorenzo-caum' => [
39
+			'email' => '[email protected]',
40
+			'name'  => 'Lorenzo Caum',
41
+			'desc'  => esc_html__('Sales & Support', 'event_espresso'),
42
+		],
43
+		'janice-gutierrez' => [
44
+			'email' => '[email protected]',
45
+			'name'  => 'Janice Gutierrez',
46
+			'desc'  => esc_html__('Support', 'event_espresso'),
47
+		],
48
+		'chinny-love-verana' => [
49
+			'email' => '[email protected]',
50
+			'name'  => 'Chinny Love Verana',
51
+			'desc'  => esc_html__('Sales & Support', 'event_espresso'),
52
+		],
53
+	],
54 54
 ];
55 55
 
56 56
 function espressoPerson($id, $email, $name, $desc): string
57 57
 {
58
-    return '
58
+	return '
59 59
     <li class="ee-card ee-credits-person" id="ee-person-' . $id . '">
60 60
         <a href="' . esp_gravatar_profile($email) . '" target="_blank">
61 61
             ' . esp_gravatar_image($email, $name) . '
@@ -69,15 +69,15 @@  discard block
 block discarded – undo
69 69
 
70 70
 function esp_gravatar_profile($email)
71 71
 {
72
-    return esc_url_raw('https://www.gravatar.com/' . md5($email));
72
+	return esc_url_raw('https://www.gravatar.com/' . md5($email));
73 73
 }
74 74
 
75 75
 function esp_gravatar_image($email, $name)
76 76
 {
77
-    $email = md5($email);
78
-    $name  = esc_attr($name);
79
-    $url   = esc_url_raw("https://0.gravatar.com/avatar/{$email}?s=60");
80
-    return "<img src='{$url}' class='gravatar' alt='{$name}'/>";
77
+	$email = md5($email);
78
+	$name  = esc_attr($name);
79
+	$url   = esc_url_raw("https://0.gravatar.com/avatar/{$email}?s=60");
80
+	return "<img src='{$url}' class='gravatar' alt='{$name}'/>";
81 81
 }
82 82
 
83 83
 ?>
@@ -87,38 +87,38 @@  discard block
 block discarded – undo
87 87
 
88 88
         <h4>
89 89
             <?php esc_html_e(
90
-                'Event Espresso is created by an international team of passionate individuals with a drive to empower your events!',
91
-                'event_espresso'
92
-            ); ?>
90
+				'Event Espresso is created by an international team of passionate individuals with a drive to empower your events!',
91
+				'event_espresso'
92
+			); ?>
93 93
         </h4>
94 94
 
95 95
         <div class='ee-credits-tEEm'>
96 96
             <?php
97
-            foreach ($tEEm_members as $tEEm => $members) {
98
-                echo '
97
+			foreach ($tEEm_members as $tEEm => $members) {
98
+				echo '
99 99
             <h3 class="wp-people-group">' . $tEEm . '</h3>
100 100
             <ul class="ee-card-grid ee-card-grid-4-cols" id="' . sanitize_key($tEEm) . '">';
101
-                foreach ($members as $id => $person) {
102
-                    echo espressoPerson($id, $person['email'], $person['name'], $person['desc']);
103
-                }
104
-                echo '
101
+				foreach ($members as $id => $person) {
102
+					echo espressoPerson($id, $person['email'], $person['name'], $person['desc']);
103
+				}
104
+				echo '
105 105
             </ul>';
106
-            }
107
-            ?>
106
+			}
107
+			?>
108 108
         </div>
109 109
 
110 110
         <h3 class="wp-people-group"><?php esc_html_e('Contributor Recognition', 'event_espresso'); ?></h3>
111 111
         <p class="description">
112 112
             <?php
113
-            printf(
114
-                esc_html__(
115
-                    'For every major release we want to recognize the people who contributed to the release via a GitHub pull request. Want to see your name listed here? %sWhen you submit a pull request that gets included in a major release%s, we\'ll add your name here linked to your GitHub profile.',
116
-                    'event_espresso'
117
-                ),
118
-                '<a href="https://github.com/eventespresso/event-espresso-core" title="Contribute to Event Espresso by making a pull request via GitHub" target="_blank">',
119
-                '</a>'
120
-            );
121
-            ?>
113
+			printf(
114
+				esc_html__(
115
+					'For every major release we want to recognize the people who contributed to the release via a GitHub pull request. Want to see your name listed here? %sWhen you submit a pull request that gets included in a major release%s, we\'ll add your name here linked to your GitHub profile.',
116
+					'event_espresso'
117
+				),
118
+				'<a href="https://github.com/eventespresso/event-espresso-core" title="Contribute to Event Espresso by making a pull request via GitHub" target="_blank">',
119
+				'</a>'
120
+			);
121
+			?>
122 122
         </p>
123 123
         <p class="wp-credits-list">
124 124
         <ul>
@@ -133,15 +133,15 @@  discard block
 block discarded – undo
133 133
         <h3 class="wp-people-group"><?php esc_html_e('External Libraries', 'event_espresso'); ?></h3>
134 134
         <p class="description">
135 135
             <?php
136
-            printf(
137
-                esc_html__(
138
-                    'Along with the libraries %sincluded with WordPress%s, Event Espresso utilizes the following third party libraries:',
139
-                    'event_espresso'
140
-                ),
141
-                '<a href="credits.php">',
142
-                '</a>'
143
-            );
144
-            ?>
136
+			printf(
137
+				esc_html__(
138
+					'Along with the libraries %sincluded with WordPress%s, Event Espresso utilizes the following third party libraries:',
139
+					'event_espresso'
140
+				),
141
+				'<a href="credits.php">',
142
+				'</a>'
143
+			);
144
+			?>
145 145
         </p>
146 146
         <p class="wp-credits-list">
147 147
             <a href="https://openexchangerates.github.io/accounting.js/" target='_blank'>accounting.js</a>,
Please login to merge, or discard this patch.
Spacing   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -56,20 +56,20 @@  discard block
 block discarded – undo
56 56
 function espressoPerson($id, $email, $name, $desc): string
57 57
 {
58 58
     return '
59
-    <li class="ee-card ee-credits-person" id="ee-person-' . $id . '">
60
-        <a href="' . esp_gravatar_profile($email) . '" target="_blank">
61
-            ' . esp_gravatar_image($email, $name) . '
59
+    <li class="ee-card ee-credits-person" id="ee-person-' . $id.'">
60
+        <a href="' . esp_gravatar_profile($email).'" target="_blank">
61
+            ' . esp_gravatar_image($email, $name).'
62 62
         </a>
63 63
         <p>
64
-            <a class="web" href="' . esp_gravatar_profile($email) . '" target="_blank">' . $name . '</a>
65
-            <span class="title">' . $desc . '</span>
64
+            <a class="web" href="' . esp_gravatar_profile($email).'" target="_blank">'.$name.'</a>
65
+            <span class="title">' . $desc.'</span>
66 66
         </p>
67 67
     </li>';
68 68
 }
69 69
 
70 70
 function esp_gravatar_profile($email)
71 71
 {
72
-    return esc_url_raw('https://www.gravatar.com/' . md5($email));
72
+    return esc_url_raw('https://www.gravatar.com/'.md5($email));
73 73
 }
74 74
 
75 75
 function esp_gravatar_image($email, $name)
@@ -96,8 +96,8 @@  discard block
 block discarded – undo
96 96
             <?php
97 97
             foreach ($tEEm_members as $tEEm => $members) {
98 98
                 echo '
99
-            <h3 class="wp-people-group">' . $tEEm . '</h3>
100
-            <ul class="ee-card-grid ee-card-grid-4-cols" id="' . sanitize_key($tEEm) . '">';
99
+            <h3 class="wp-people-group">' . $tEEm.'</h3>
100
+            <ul class="ee-card-grid ee-card-grid-4-cols" id="' . sanitize_key($tEEm).'">';
101 101
                 foreach ($members as $id => $person) {
102 102
                     echo espressoPerson($id, $person['email'], $person['name'], $person['desc']);
103 103
                 }
Please login to merge, or discard this patch.
admin_pages/maintenance/Maintenance_Admin_Page.core.php 1 patch
Indentation   +952 added lines, -952 removed lines patch added patch discarded remove patch
@@ -14,956 +14,956 @@
 block discarded – undo
14 14
  */
15 15
 class Maintenance_Admin_Page extends EE_Admin_Page
16 16
 {
17
-    /**
18
-     * @var EE_Data_Migration_Manager
19
-     */
20
-    protected $migration_manager;
21
-
22
-    /**
23
-     * @var EE_Maintenance_Mode
24
-     */
25
-    protected $maintenance_mode;
26
-
27
-    /**
28
-     * @var EE_Form_Section_Proper
29
-     */
30
-    protected $datetime_fix_offset_form;
31
-
32
-
33
-    /**
34
-     * @param bool $routing
35
-     * @throws EE_Error
36
-     * @throws ReflectionException
37
-     */
38
-    public function __construct($routing = true)
39
-    {
40
-        $this->migration_manager = EE_Data_Migration_Manager::instance();
41
-        $this->maintenance_mode  = EE_Maintenance_Mode::instance();
42
-        parent::__construct($routing);
43
-    }
44
-
45
-
46
-    protected function _init_page_props()
47
-    {
48
-        $this->page_slug        = EE_MAINTENANCE_PG_SLUG;
49
-        $this->page_label       = EE_MAINTENANCE_LABEL;
50
-        $this->_admin_base_url  = EE_MAINTENANCE_ADMIN_URL;
51
-        $this->_admin_base_path = EE_MAINTENANCE_ADMIN;
52
-    }
53
-
54
-
55
-    protected function _ajax_hooks()
56
-    {
57
-        add_action('wp_ajax_migration_step', [$this, 'migration_step']);
58
-        add_action('wp_ajax_add_error_to_migrations_ran', [$this, 'add_error_to_migrations_ran']);
59
-    }
60
-
61
-
62
-    protected function _define_page_props()
63
-    {
64
-        $this->_admin_page_title = EE_MAINTENANCE_LABEL;
65
-        $this->_labels           = [
66
-            'buttons' => [
67
-                'reset_reservations' => esc_html__('Reset Ticket and Datetime Reserved Counts', 'event_espresso'),
68
-                'reset_capabilities' => esc_html__('Reset Event Espresso Capabilities', 'event_espresso'),
69
-            ],
70
-        ];
71
-    }
72
-
73
-
74
-    protected function _set_page_routes()
75
-    {
76
-        $this->_page_routes = [
77
-            'default'                             => [
78
-                'func'       => '_maintenance',
79
-                'capability' => 'manage_options',
80
-            ],
81
-            'change_maintenance_level'            => [
82
-                'func'       => '_change_maintenance_level',
83
-                'capability' => 'manage_options',
84
-                'noheader'   => true,
85
-            ],
86
-            'system_status'                       => [
87
-                'func'       => '_system_status',
88
-                'capability' => 'manage_options',
89
-            ],
90
-            'download_system_status'              => [
91
-                'func'       => '_download_system_status',
92
-                'capability' => 'manage_options',
93
-                'noheader'   => true,
94
-            ],
95
-            'send_migration_crash_report'         => [
96
-                'func'       => '_send_migration_crash_report',
97
-                'capability' => 'manage_options',
98
-                'noheader'   => true,
99
-            ],
100
-            'confirm_migration_crash_report_sent' => [
101
-                'func'       => '_confirm_migration_crash_report_sent',
102
-                'capability' => 'manage_options',
103
-            ],
104
-            'data_reset'                          => [
105
-                'func'       => '_data_reset_and_delete',
106
-                'capability' => 'manage_options',
107
-            ],
108
-            'reset_db'                            => [
109
-                'func'       => '_reset_db',
110
-                'capability' => 'manage_options',
111
-                'noheader'   => true,
112
-                'args'       => ['nuke_old_ee4_data' => true],
113
-            ],
114
-            'start_with_fresh_ee4_db'             => [
115
-                'func'       => '_reset_db',
116
-                'capability' => 'manage_options',
117
-                'noheader'   => true,
118
-                'args'       => ['nuke_old_ee4_data' => false],
119
-            ],
120
-            'delete_db'                           => [
121
-                'func'       => '_delete_db',
122
-                'capability' => 'manage_options',
123
-                'noheader'   => true,
124
-            ],
125
-            'rerun_migration_from_ee3'            => [
126
-                'func'       => '_rerun_migration_from_ee3',
127
-                'capability' => 'manage_options',
128
-                'noheader'   => true,
129
-            ],
130
-            'reset_reservations'                  => [
131
-                'func'       => '_reset_reservations',
132
-                'capability' => 'manage_options',
133
-                'noheader'   => true,
134
-            ],
135
-            'reset_capabilities'                  => [
136
-                'func'       => '_reset_capabilities',
137
-                'capability' => 'manage_options',
138
-                'noheader'   => true,
139
-            ],
140
-            'reattempt_migration'                 => [
141
-                'func'       => '_reattempt_migration',
142
-                'capability' => 'manage_options',
143
-                'noheader'   => true,
144
-            ],
145
-            'datetime_tools'                      => [
146
-                'func'       => '_datetime_tools',
147
-                'capability' => 'manage_options',
148
-            ],
149
-            'run_datetime_offset_fix'             => [
150
-                'func'               => '_apply_datetime_offset',
151
-                'noheader'           => true,
152
-                'headers_sent_route' => 'datetime_tools',
153
-                'capability'         => 'manage_options',
154
-            ],
155
-        ];
156
-    }
157
-
158
-
159
-    protected function _set_page_config()
160
-    {
161
-        $this->_page_config = [
162
-            'default'        => [
163
-                'nav'           => [
164
-                    'label' => esc_html__('Maintenance', 'event_espresso'),
165
-                    'icon' => 'dashicons-admin-tools',
166
-                    'order' => 10,
167
-                ],
168
-                'require_nonce' => false,
169
-            ],
170
-            'data_reset'     => [
171
-                'nav'           => [
172
-                    'label' => esc_html__('Reset/Delete Data', 'event_espresso'),
173
-                    'icon' => 'dashicons-trash',
174
-                    'order' => 20,
175
-                ],
176
-                'require_nonce' => false,
177
-            ],
178
-            'datetime_tools' => [
179
-                'nav'           => [
180
-                    'label' => esc_html__('Datetime Utilities', 'event_espresso'),
181
-                    'icon' => 'dashicons-calendar-alt',
182
-                    'order' => 25,
183
-                ],
184
-                'require_nonce' => false,
185
-            ],
186
-            'system_status'  => [
187
-                'nav'           => [
188
-                    'label' => esc_html__("System Information", "event_espresso"),
189
-                    'icon' => 'dashicons-info',
190
-                    'order' => 30,
191
-                ],
192
-                'require_nonce' => false,
193
-            ],
194
-        ];
195
-    }
196
-
197
-
198
-    /**
199
-     * default maintenance page.
200
-     * If we're in maintenance mode level 2, then we need to show the migration scripts and all that UI.
201
-     *
202
-     * @throws EE_Error
203
-     */
204
-    public function _maintenance()
205
-    {
206
-        $show_maintenance_switch         = true;
207
-        $show_backup_db_text             = false;
208
-        $show_migration_progress         = false;
209
-        $script_names                    = [];
210
-        $addons_should_be_upgraded_first = false;
211
-        // it all depends on if we're in maintenance model level 1 (frontend-only) or
212
-        // level 2 (everything except maintenance page)
213
-        try {
214
-            // get the current maintenance level and check if
215
-            // we are removed
216
-            $mMode_level  = $this->maintenance_mode->level();
217
-            $placed_in_mm = $this->maintenance_mode->set_maintenance_mode_if_db_old();
218
-            if ($mMode_level == EE_Maintenance_Mode::level_2_complete_maintenance && ! $placed_in_mm) {
219
-                // we just took the site out of maintenance mode, so notify the user.
220
-                // unfortunately this message appears to be echoed on the NEXT page load...
221
-                // oh well, we should really be checking for this on addon deactivation anyways
222
-                EE_Error::add_attention(
223
-                    esc_html__(
224
-                        'Site taken out of maintenance mode because no data migration scripts are required',
225
-                        'event_espresso'
226
-                    )
227
-                );
228
-                $this->_process_notices(['page' => 'espresso_maintenance_settings']);
229
-            }
230
-            // in case an exception is thrown while trying to handle migrations
231
-            if ($mMode_level === EE_Maintenance_Mode::level_2_complete_maintenance) {
232
-                $show_maintenance_switch = false;
233
-                $show_migration_progress = true;
234
-                if (isset($this->_req_data['continue_migration'])) {
235
-                    $show_backup_db_text = false;
236
-                } else {
237
-                    $show_backup_db_text = true;
238
-                }
239
-                $scripts_needing_to_run          =
240
-                    $this->migration_manager->check_for_applicable_data_migration_scripts();
241
-                $addons_should_be_upgraded_first = $this->migration_manager->addons_need_updating();
242
-                $script_names                    = [];
243
-                $current_script                  = null;
244
-                foreach ($scripts_needing_to_run as $script) {
245
-                    if ($script instanceof EE_Data_Migration_Script_Base) {
246
-                        if (! $current_script) {
247
-                            $current_script = $script;
248
-                            $current_script->migration_page_hooks();
249
-                        }
250
-                        $script_names[] = $script->pretty_name();
251
-                    }
252
-                }
253
-            }
254
-            $most_recent_migration = $this->migration_manager->get_last_ran_script(true);
255
-            $exception_thrown      = false;
256
-        } catch (EE_Error $e) {
257
-            $this->migration_manager->add_error_to_migrations_ran($e->getMessage());
258
-            // now, just so we can display the page correctly, make an error migration script stage object
259
-            // and also put the error on it. It only persists for the duration of this request
260
-            $most_recent_migration = new EE_DMS_Unknown_1_0_0();
261
-            $most_recent_migration->add_error($e->getMessage());
262
-            $exception_thrown = true;
263
-        }
264
-        $current_db_state = $this->migration_manager->ensure_current_database_state_is_set();
265
-        $current_db_state = str_replace('.decaf', '', $current_db_state);
266
-        if (
267
-            $exception_thrown
268
-            || (
269
-                $most_recent_migration instanceof EE_Data_Migration_Script_Base
270
-                && $most_recent_migration->is_broken()
271
-            )
272
-        ) {
273
-            $this->_template_path                =
274
-                EE_MAINTENANCE_TEMPLATE_PATH . 'ee_migration_was_borked_page.template.php';
275
-            $this->_template_args['support_url'] = 'https://eventespresso.com/support/forums/';
276
-            $this->_template_args['next_url']    = EEH_URL::add_query_args_and_nonce(
277
-                [
278
-                    'action'  => 'confirm_migration_crash_report_sent',
279
-                    'success' => '0',
280
-                ],
281
-                EE_MAINTENANCE_ADMIN_URL
282
-            );
283
-        } elseif ($addons_should_be_upgraded_first) {
284
-            $this->_template_path = EE_MAINTENANCE_TEMPLATE_PATH . 'ee_upgrade_addons_before_migrating.template.php';
285
-        } else {
286
-            if (
287
-                $most_recent_migration instanceof EE_Data_Migration_Script_Base
288
-                && $most_recent_migration->can_continue()
289
-            ) {
290
-                $show_backup_db_text                    = false;
291
-                $show_continue_current_migration_script = true;
292
-                $show_most_recent_migration             = true;
293
-            } elseif (isset($this->_req_data['continue_migration'])) {
294
-                $show_most_recent_migration             = true;
295
-                $show_continue_current_migration_script = false;
296
-            } else {
297
-                $show_most_recent_migration             = false;
298
-                $show_continue_current_migration_script = false;
299
-            }
300
-            if (isset($current_script)) {
301
-                $migrates_to          = $current_script->migrates_to_version();
302
-                $plugin_slug          = $migrates_to['slug'];
303
-                $new_version          = $migrates_to['version'];
304
-                $this->_template_args = array_merge(
305
-                    $this->_template_args,
306
-                    [
307
-                        'current_db_state' => sprintf(
308
-                            esc_html__("EE%s (%s)", "event_espresso"),
309
-                            isset($current_db_state[ $plugin_slug ]) ? $current_db_state[ $plugin_slug ] : 3,
310
-                            $plugin_slug
311
-                        ),
312
-                        'next_db_state'    => sprintf(
313
-                            esc_html__("EE%s (%s)", 'event_espresso'),
314
-                            $new_version,
315
-                            $plugin_slug
316
-                        ),
317
-                    ]
318
-                );
319
-            } else {
320
-                $this->_template_args['current_db_state'] = null;
321
-                $this->_template_args['next_db_state']    = null;
322
-            }
323
-            $this->_template_path = EE_MAINTENANCE_TEMPLATE_PATH . 'ee_migration_page.template.php';
324
-            $this->_template_args = array_merge(
325
-                $this->_template_args,
326
-                [
327
-                    'show_most_recent_migration'             => $show_most_recent_migration,
328
-                    // flag for showing the most recent migration's status and/or errors
329
-                    'show_migration_progress'                => $show_migration_progress,
330
-                    // flag for showing the option to run migrations and see their progress
331
-                    'show_backup_db_text'                    => $show_backup_db_text,
332
-                    // flag for showing text telling the user to back up their DB
333
-                    'show_maintenance_switch'                => $show_maintenance_switch,
334
-                    // flag for showing the option to change maintenance mode between levels 0 and 1
335
-                    'script_names'                           => $script_names,
336
-                    // array of names of scripts that have run
337
-                    'show_continue_current_migration_script' => $show_continue_current_migration_script,
338
-                    // flag to change wording to indicating that we're only CONTINUING a migration script (somehow it got interrupted0
339
-                    'reset_db_page_link'                     => EE_Admin_Page::add_query_args_and_nonce(
340
-                        ['action' => 'reset_db'],
341
-                        EE_MAINTENANCE_ADMIN_URL
342
-                    ),
343
-                    'data_reset_page'                        => EE_Admin_Page::add_query_args_and_nonce(
344
-                        ['action' => 'data_reset'],
345
-                        EE_MAINTENANCE_ADMIN_URL
346
-                    ),
347
-                    'update_migration_script_page_link'      => EE_Admin_Page::add_query_args_and_nonce(
348
-                        ['action' => 'change_maintenance_level'],
349
-                        EE_MAINTENANCE_ADMIN_URL
350
-                    ),
351
-                    'ultimate_db_state'                      => sprintf(
352
-                        esc_html__("EE%s", 'event_espresso'),
353
-                        espresso_version()
354
-                    ),
355
-                ]
356
-            );
357
-        }
358
-        $this->_template_args['most_recent_migration'] =
359
-            $most_recent_migration;// the actual most recently ran migration
360
-        // now render the migration options part, and put it in a variable
361
-        $migration_options_template_file                = apply_filters(
362
-            'FHEE__ee_migration_page__migration_options_template',
363
-            EE_MAINTENANCE_TEMPLATE_PATH . 'migration_options_from_ee4.template.php'
364
-        );
365
-        $migration_options_html                         = EEH_Template::display_template(
366
-            $migration_options_template_file,
367
-            $this->_template_args,
368
-            true
369
-        );
370
-        $this->_template_args['migration_options_html'] = $migration_options_html;
371
-        $this->_template_args['admin_page_content']     = EEH_Template::display_template(
372
-            $this->_template_path,
373
-            $this->_template_args,
374
-            true
375
-        );
376
-        $this->display_admin_page_with_sidebar();
377
-    }
378
-
379
-
380
-    /**
381
-     * returns JSON and executes another step of the currently-executing data migration (called via ajax)
382
-     *
383
-     * @throws EE_Error
384
-     */
385
-    public function migration_step()
386
-    {
387
-        $this->_template_args['data'] = $this->migration_manager->response_to_migration_ajax_request();
388
-        $this->_return_json();
389
-    }
390
-
391
-
392
-    /**
393
-     * Can be used by js when it notices a response with HTML in it in order
394
-     * to log the malformed response
395
-     *
396
-     * @throws EE_Error
397
-     */
398
-    public function add_error_to_migrations_ran()
399
-    {
400
-        $this->migration_manager->add_error_to_migrations_ran($this->_req_data['message']);
401
-        $this->_template_args['data'] = ['ok' => true];
402
-        $this->_return_json();
403
-    }
404
-
405
-
406
-    /**
407
-     * changes the maintenance level, provided there are still no migration scripts that should run
408
-     *
409
-     * @throws EE_Error
410
-     */
411
-    public function _change_maintenance_level()
412
-    {
413
-        $new_level = absint($this->_req_data['maintenance_mode_level']);
414
-        if (! $this->migration_manager->check_for_applicable_data_migration_scripts()) {
415
-            $this->maintenance_mode->set_maintenance_level($new_level);
416
-            $success = true;
417
-        } else {
418
-            $this->maintenance_mode->set_maintenance_mode_if_db_old();
419
-            $success = false;
420
-        }
421
-        $this->_redirect_after_action($success, 'Maintenance Mode', esc_html__("Updated", "event_espresso"));
422
-    }
423
-
424
-
425
-    /**
426
-     * a tab with options for resetting and/or deleting EE data
427
-     *
428
-     * @throws EE_Error
429
-     * @throws DomainException
430
-     */
431
-    public function _data_reset_and_delete()
432
-    {
433
-        $this->_template_path                              =
434
-            EE_MAINTENANCE_TEMPLATE_PATH . 'ee_data_reset_and_delete.template.php';
435
-        $this->_template_args['reset_reservations_button'] = $this->get_action_link_or_button(
436
-            'reset_reservations',
437
-            'reset_reservations',
438
-            [],
439
-            'button button--caution ee-confirm'
440
-        );
441
-        $this->_template_args['reset_capabilities_button'] = $this->get_action_link_or_button(
442
-            'reset_capabilities',
443
-            'reset_capabilities',
444
-            [],
445
-            'button button--caution ee-confirm'
446
-        );
447
-        $this->_template_args['delete_db_url']             = EE_Admin_Page::add_query_args_and_nonce(
448
-            ['action' => 'delete_db'],
449
-            EE_MAINTENANCE_ADMIN_URL
450
-        );
451
-        $this->_template_args['reset_db_url']              = EE_Admin_Page::add_query_args_and_nonce(
452
-            ['action' => 'reset_db'],
453
-            EE_MAINTENANCE_ADMIN_URL
454
-        );
455
-        $this->_template_args['admin_page_content']        = EEH_Template::display_template(
456
-            $this->_template_path,
457
-            $this->_template_args,
458
-            true
459
-        );
460
-        $this->display_admin_page_with_no_sidebar();
461
-    }
462
-
463
-
464
-    /**
465
-     * @throws EE_Error
466
-     * @throws ReflectionException
467
-     */
468
-    protected function _reset_reservations()
469
-    {
470
-        if (EED_Ticket_Sales_Monitor::reset_reservation_counts()) {
471
-            EE_Error::add_success(
472
-                esc_html__(
473
-                    'Ticket and datetime reserved counts have been successfully reset.',
474
-                    'event_espresso'
475
-                )
476
-            );
477
-        } else {
478
-            EE_Error::add_success(
479
-                esc_html__(
480
-                    'Ticket and datetime reserved counts were correct and did not need resetting.',
481
-                    'event_espresso'
482
-                )
483
-            );
484
-        }
485
-        $this->_redirect_after_action(true, '', '', ['action' => 'data_reset'], true);
486
-    }
487
-
488
-
489
-    /**
490
-     * @throws EE_Error
491
-     */
492
-    protected function _reset_capabilities()
493
-    {
494
-        EE_Registry::instance()->CAP->init_caps(true);
495
-        EE_Error::add_success(
496
-            esc_html__(
497
-                'Default Event Espresso capabilities have been restored for all current roles.',
498
-                'event_espresso'
499
-            )
500
-        );
501
-        $this->_redirect_after_action(false, '', '', ['action' => 'data_reset'], true);
502
-    }
503
-
504
-
505
-    /**
506
-     * resets the DMSs, so we can attempt to continue migrating after a fatal error
507
-     * (only a good idea when someone has somehow tried ot fix whatever caused
508
-     * the fatal error in teh first place)
509
-     *
510
-     * @throws EE_Error
511
-     */
512
-    protected function _reattempt_migration()
513
-    {
514
-        $this->migration_manager->reattempt();
515
-        $this->_redirect_after_action(false, '', '', ['action' => 'default'], true);
516
-    }
517
-
518
-
519
-    /**
520
-     * shows the big ol' System Information page
521
-     *
522
-     * @throws EE_Error
523
-     */
524
-    public function _system_status()
525
-    {
526
-        $this->_template_path = EE_MAINTENANCE_TEMPLATE_PATH . 'ee_system_stati_page.template.php';
527
-        $this->_template_args['system_stati']               = EEM_System_Status::instance()->get_system_stati();
528
-        $this->_template_args['download_system_status_url'] = EE_Admin_Page::add_query_args_and_nonce(
529
-            [
530
-                'action' => 'download_system_status',
531
-            ],
532
-            EE_MAINTENANCE_ADMIN_URL
533
-        );
534
-        $this->_template_args['admin_page_content']         = EEH_Template::display_template(
535
-            $this->_template_path,
536
-            $this->_template_args,
537
-            true
538
-        );
539
-        $this->display_admin_page_with_no_sidebar();
540
-    }
541
-
542
-
543
-    /**
544
-     * Downloads an HTML file of the system status that can be easily stored or emailed
545
-     */
546
-    public function _download_system_status()
547
-    {
548
-        $status_info = EEM_System_Status::instance()->get_system_stati();
549
-        header('Content-Disposition: attachment');
550
-        header("Content-Disposition: attachment; filename=system_status_" . sanitize_key(site_url()) . ".html");
551
-        $output = '<style>table{border:1px solid darkgrey;}td{vertical-align:top}</style>';
552
-        $output .= '<h1>' . sprintf(
553
-            __('System Information for %1$s', 'event_espresso'),
554
-            esc_url_raw(site_url())
555
-        ) . '</h1>';
556
-        $output .= EEH_Template::layout_array_as_table($status_info);
557
-        echo esc_html($output);
558
-        die;
559
-    }
560
-
561
-
562
-    /**
563
-     * @throws EE_Error
564
-     */
565
-    public function _send_migration_crash_report()
566
-    {
567
-        $from      = $this->_req_data['from'];
568
-        $from_name = $this->_req_data['from_name'];
569
-        $body      = $this->_req_data['body'];
570
-        try {
571
-            $success = wp_mail(
572
-                EE_SUPPORT_EMAIL,
573
-                'Migration Crash Report',
574
-                $body . "/r/n<br>" . print_r(EEM_System_Status::instance()->get_system_stati(), true),
575
-                [
576
-                    "from:$from_name<$from>",
577
-                ]
578
-            );
579
-        } catch (Exception $e) {
580
-            $success = false;
581
-        }
582
-        $this->_redirect_after_action(
583
-            $success,
584
-            esc_html__("Migration Crash Report", "event_espresso"),
585
-            esc_html__("sent", "event_espresso"),
586
-            ['success' => $success, 'action' => 'confirm_migration_crash_report_sent']
587
-        );
588
-    }
589
-
590
-
591
-    /**
592
-     * @throws EE_Error
593
-     */
594
-    public function _confirm_migration_crash_report_sent()
595
-    {
596
-        try {
597
-            $most_recent_migration = $this->migration_manager->get_last_ran_script(true);
598
-        } catch (EE_Error $e) {
599
-            $this->migration_manager->add_error_to_migrations_ran($e->getMessage());
600
-            // now, just so we can display the page correctly, make an error migration script stage object
601
-            // and also put the error on it. It only persists for the duration of this request
602
-            $most_recent_migration = new EE_DMS_Unknown_1_0_0();
603
-            $most_recent_migration->add_error($e->getMessage());
604
-        }
605
-        $success                                       = $this->_req_data['success'] === '1';
606
-        $this->_template_args['success']               = $success;
607
-        $this->_template_args['most_recent_migration'] = $most_recent_migration;
608
-        $this->_template_args['reset_db_action_url']   = EE_Admin_Page::add_query_args_and_nonce(
609
-            ['action' => 'reset_db'],
610
-            EE_MAINTENANCE_ADMIN_URL
611
-        );
612
-        $this->_template_args['reset_db_page_url']     = EE_Admin_Page::add_query_args_and_nonce(
613
-            ['action' => 'data_reset'],
614
-            EE_MAINTENANCE_ADMIN_URL
615
-        );
616
-        $this->_template_args['reattempt_action_url']  = EE_Admin_Page::add_query_args_and_nonce(
617
-            ['action' => 'reattempt_migration'],
618
-            EE_MAINTENANCE_ADMIN_URL
619
-        );
620
-        $this->_template_path                          =
621
-            EE_MAINTENANCE_TEMPLATE_PATH . 'ee_confirm_migration_crash_report_sent.template.php';
622
-        $this->_template_args['admin_page_content']    = EEH_Template::display_template(
623
-            $this->_template_path,
624
-            $this->_template_args,
625
-            true
626
-        );
627
-        $this->display_admin_page_with_sidebar();
628
-    }
629
-
630
-
631
-    /**
632
-     * Resets the entire EE4 database.
633
-     * only sets up ee4 database for a fresh install-
634
-     * doesn't actually clean out the old wp options, or cpts
635
-     * (although it does erase old ee table data)
636
-     *
637
-     * @param boolean $nuke_old_ee4_data controls whether we destroy the old ee4 data,
638
-     *                                   or just try initializing ee4 default data
639
-     * @throws EE_Error
640
-     * @throws ReflectionException
641
-     */
642
-    public function _reset_db($nuke_old_ee4_data = true)
643
-    {
644
-        $this->maintenance_mode->set_maintenance_level(EE_Maintenance_Mode::level_0_not_in_maintenance);
645
-        if ($nuke_old_ee4_data) {
646
-            EEH_Activation::delete_all_espresso_cpt_data();
647
-            EEH_Activation::delete_all_espresso_tables_and_data(false);
648
-            EEH_Activation::remove_cron_tasks();
649
-        }
650
-        // make sure when we reset the registry's config that it
651
-        // switches to using the new singleton
652
-        EE_Registry::instance()->CFG = EE_Registry::instance()->CFG->reset(true);
653
-        EE_System::instance()->initialize_db_if_no_migrations_required(true);
654
-        EE_System::instance()->redirect_to_about_ee();
655
-    }
656
-
657
-
658
-    /**
659
-     * Deletes ALL EE tables, Records, and Options from the database.
660
-     *
661
-     * @throws EE_Error
662
-     * @throws ReflectionException
663
-     */
664
-    public function _delete_db()
665
-    {
666
-        $this->maintenance_mode->set_maintenance_level(EE_Maintenance_Mode::level_0_not_in_maintenance);
667
-        EEH_Activation::delete_all_espresso_cpt_data();
668
-        EEH_Activation::delete_all_espresso_tables_and_data();
669
-        EEH_Activation::remove_cron_tasks();
670
-        EEH_Activation::deactivate_event_espresso();
671
-        wp_safe_redirect(admin_url('plugins.php'));
672
-        exit;
673
-    }
674
-
675
-
676
-    /**
677
-     * sets up EE4 to rerun the migrations from ee3 to ee4
678
-     *
679
-     * @throws EE_Error
680
-     * @throws ReflectionException
681
-     */
682
-    public function _rerun_migration_from_ee3()
683
-    {
684
-        $this->maintenance_mode->set_maintenance_level(EE_Maintenance_Mode::level_0_not_in_maintenance);
685
-        EEH_Activation::delete_all_espresso_cpt_data();
686
-        EEH_Activation::delete_all_espresso_tables_and_data(false);
687
-        // set the db state to something that will require migrations
688
-        update_option(EE_Data_Migration_Manager::current_database_state, '3.1.36.0');
689
-        $this->maintenance_mode->set_maintenance_level(EE_Maintenance_Mode::level_2_complete_maintenance);
690
-        $this->_redirect_after_action(
691
-            true,
692
-            esc_html__("Database", 'event_espresso'),
693
-            esc_html__("reset", 'event_espresso')
694
-        );
695
-    }
696
-
697
-
698
-    // none of the below group are currently used for Gateway Settings
699
-    protected function _add_screen_options()
700
-    {
701
-    }
702
-
703
-
704
-    protected function _add_feature_pointers()
705
-    {
706
-    }
707
-
708
-
709
-    public function admin_init()
710
-    {
711
-    }
712
-
713
-
714
-    public function admin_notices()
715
-    {
716
-    }
717
-
718
-
719
-    public function admin_footer_scripts()
720
-    {
721
-    }
722
-
723
-
724
-    public function load_scripts_styles()
725
-    {
726
-        wp_enqueue_script('ee_admin_js');
727
-        wp_enqueue_script(
728
-            'ee-maintenance',
729
-            EE_MAINTENANCE_ASSETS_URL . 'ee-maintenance.js',
730
-            ['jquery'],
731
-            EVENT_ESPRESSO_VERSION,
732
-            true
733
-        );
734
-        wp_register_style(
735
-            'espresso_maintenance',
736
-            EE_MAINTENANCE_ASSETS_URL . 'ee-maintenance.css',
737
-            [],
738
-            EVENT_ESPRESSO_VERSION
739
-        );
740
-        wp_enqueue_style('espresso_maintenance');
741
-        // localize script stuff
742
-        wp_localize_script(
743
-            'ee-maintenance',
744
-            'ee_maintenance',
745
-            [
746
-                'migrating'                        => wp_strip_all_tags(__("Updating Database...", "event_espresso")),
747
-                'next'                             => wp_strip_all_tags(__("Next", "event_espresso")),
748
-                'fatal_error'                      => wp_strip_all_tags(__(
749
-                    "A Fatal Error Has Occurred",
750
-                    "event_espresso"
751
-                )),
752
-                'click_next_when_ready'            => wp_strip_all_tags(
753
-                    __(
754
-                        "The current Database Update has ended. Click 'next' when ready to proceed",
755
-                        "event_espresso"
756
-                    )
757
-                ),
758
-                'status_no_more_migration_scripts' => EE_Data_Migration_Manager::status_no_more_migration_scripts,
759
-                'status_fatal_error'               => EE_Data_Migration_Manager::status_fatal_error,
760
-                'status_completed'                 => EE_Data_Migration_Manager::status_completed,
761
-                'confirm'                          => wp_strip_all_tags(
762
-                    __(
763
-                        'Are you sure you want to do this? It CANNOT be undone!',
764
-                        'event_espresso'
765
-                    )
766
-                ),
767
-                'confirm_skip_migration'           => wp_strip_all_tags(
768
-                    __(
769
-                        'You have chosen to NOT migrate your existing data. Are you sure you want to continue?',
770
-                        'event_espresso'
771
-                    )
772
-                ),
773
-            ]
774
-        );
775
-    }
776
-
777
-
778
-    public function load_scripts_styles_default()
779
-    {
780
-    }
781
-
782
-
783
-    /**
784
-     * Enqueue scripts and styles for the datetime tools page.
785
-     */
786
-    public function load_scripts_styles_datetime_tools()
787
-    {
788
-        EE_Datepicker_Input::enqueue_styles_and_scripts();
789
-    }
790
-
791
-
792
-    /**
793
-     * @throws EE_Error
794
-     */
795
-    protected function _datetime_tools()
796
-    {
797
-        $form_action                                = EE_Admin_Page::add_query_args_and_nonce(
798
-            [
799
-                'action'        => 'run_datetime_offset_fix',
800
-                'return_action' => $this->_req_action,
801
-            ],
802
-            EE_MAINTENANCE_ADMIN_URL
803
-        );
804
-        $form                                       = $this->_get_datetime_offset_fix_form();
805
-        $this->_admin_page_title                    = esc_html__('Datetime Utilities', 'event_espresso');
806
-        $this->_template_args['admin_page_content'] = $form->form_open($form_action, 'post')
807
-                                                      . $form->get_html_and_js()
808
-                                                      . $form->form_close();
809
-        $this->display_admin_page_with_sidebar();
810
-    }
811
-
812
-
813
-    /**
814
-     * @throws EE_Error
815
-     */
816
-    protected function _get_datetime_offset_fix_form()
817
-    {
818
-        if (! $this->datetime_fix_offset_form instanceof EE_Form_Section_Proper) {
819
-            $this->datetime_fix_offset_form = new EE_Form_Section_Proper(
820
-                [
821
-                    'name'            => 'datetime_offset_fix_option',
822
-                    'layout_strategy' => new EE_Admin_Two_Column_Layout(),
823
-                    'subsections'     => [
824
-                        'title'                  => new EE_Form_Section_HTML(
825
-                            EEH_HTML::h2(
826
-                                esc_html__('Datetime Offset Tool', 'event_espresso')
827
-                            )
828
-                        ),
829
-                        'explanation'            => new EE_Form_Section_HTML(
830
-                            EEH_HTML::p(
831
-                                esc_html__(
832
-                                    'Use this tool to automatically apply the provided offset to all Event Espresso records in your database that involve dates and times.',
833
-                                    'event_espresso'
834
-                                )
835
-                            )
836
-                            . EEH_HTML::p(
837
-                                esc_html__(
838
-                                    'Note: If you enter 1.25, that will result in the offset of 1 hour 15 minutes being applied.  Decimals represent the fraction of hours, not minutes.',
839
-                                    'event_espresso'
840
-                                )
841
-                            )
842
-                        ),
843
-                        'offset_input'           => new EE_Float_Input(
844
-                            [
845
-                                'html_name'       => 'offset_for_datetimes',
846
-                                'html_label_text' => esc_html__(
847
-                                    'Offset to apply (in hours):',
848
-                                    'event_espresso'
849
-                                ),
850
-                                'min_value'       => '-12',
851
-                                'max_value'       => '14',
852
-                                'step_value'      => '.25',
853
-                                'default'         => DatetimeOffsetFix::getOffset(),
854
-                            ]
855
-                        ),
856
-                        'date_range_explanation' => new EE_Form_Section_HTML(
857
-                            EEH_HTML::p(
858
-                                esc_html__(
859
-                                    'Leave the following fields blank if you want the offset to be applied to all dates. If however, you want to just apply the offset to a specific range of dates you can restrict the offset application using these fields.',
860
-                                    'event_espresso'
861
-                                )
862
-                            )
863
-                            . EEH_HTML::p(
864
-                                EEH_HTML::strong(
865
-                                    sprintf(
866
-                                        esc_html__(
867
-                                            'Note: please enter the dates in UTC (You can use %1$sthis online tool%2$s to assist with conversions).',
868
-                                            'event_espresso'
869
-                                        ),
870
-                                        '<a href="https://www.timeanddate.com/worldclock/converter.html">',
871
-                                        '</a>'
872
-                                    )
873
-                                )
874
-                            )
875
-                        ),
876
-                        'date_range_start_date'  => new EE_Datepicker_Input(
877
-                            [
878
-                                'html_name'       => 'offset_date_start_range',
879
-                                'html_label_text' => esc_html__(
880
-                                    'Start Date for dates the offset applied to:',
881
-                                    'event_espresso'
882
-                                ),
883
-                            ]
884
-                        ),
885
-                        'date_range_end_date'    => new EE_Datepicker_Input(
886
-                            [
887
-                                'html_name'       => 'offset_date_end_range',
888
-                                'html_label_text' => esc_html__(
889
-                                    'End Date for dates the offset is applied to:',
890
-                                    'event_espresso'
891
-                                ),
892
-                            ]
893
-                        ),
894
-                        'submit'                 => new EE_Submit_Input(
895
-                            [
896
-                                'html_label_text' => '',
897
-                                'default'         => esc_html__('Apply Offset', 'event_espresso'),
898
-                            ]
899
-                        ),
900
-                    ],
901
-                ]
902
-            );
903
-        }
904
-        return $this->datetime_fix_offset_form;
905
-    }
906
-
907
-
908
-    /**
909
-     * Callback for the run_datetime_offset_fix route.
910
-     *
911
-     * @throws EE_Error
912
-     */
913
-    protected function _apply_datetime_offset()
914
-    {
915
-        if ($_SERVER['REQUEST_METHOD'] === 'POST') {
916
-            $form = $this->_get_datetime_offset_fix_form();
917
-            $form->receive_form_submission($this->_req_data);
918
-            if ($form->is_valid()) {
919
-                // save offset data so batch processor can get it.
920
-                DatetimeOffsetFix::updateOffset($form->get_input_value('offset_input'));
921
-                $utc_timezone          = new DateTimeZone('UTC');
922
-                $date_range_start_date = DateTime::createFromFormat(
923
-                    'm/d/Y H:i:s',
924
-                    $form->get_input_value('date_range_start_date') . ' 00:00:00',
925
-                    $utc_timezone
926
-                );
927
-                $date_range_end_date   = DateTime::createFromFormat(
928
-                    'm/d/Y H:i:s',
929
-                    $form->get_input_value('date_range_end_date') . ' 23:59:59',
930
-                    $utc_timezone
931
-                );
932
-                if ($date_range_start_date instanceof DateTime) {
933
-                    DatetimeOffsetFix::updateStartDateRange(DbSafeDateTime::createFromDateTime($date_range_start_date));
934
-                }
935
-                if ($date_range_end_date instanceof DateTime) {
936
-                    DatetimeOffsetFix::updateEndDateRange(DbSafeDateTime::createFromDateTime($date_range_end_date));
937
-                }
938
-                // redirect to batch tool
939
-                wp_redirect(
940
-                    EE_Admin_Page::add_query_args_and_nonce(
941
-                        [
942
-                            'page'        => EED_Batch::PAGE_SLUG,
943
-                            'batch'       => EED_Batch::batch_job,
944
-                            'label'       => esc_html__('Applying Offset', 'event_espresso'),
945
-                            'job_handler' => urlencode('EventEspressoBatchRequest\JobHandlers\DatetimeOffsetFix'),
946
-                            'return_url'  => urlencode(
947
-                                add_query_arg(
948
-                                    [
949
-                                        'action' => 'datetime_tools',
950
-                                    ],
951
-                                    EEH_URL::current_url_without_query_paramaters(
952
-                                        [
953
-                                            'return_action',
954
-                                            'run_datetime_offset_fix_nonce',
955
-                                            'return',
956
-                                            'datetime_tools_nonce',
957
-                                        ]
958
-                                    )
959
-                                )
960
-                            ),
961
-                        ],
962
-                        admin_url()
963
-                    )
964
-                );
965
-                exit;
966
-            }
967
-        }
968
-    }
17
+	/**
18
+	 * @var EE_Data_Migration_Manager
19
+	 */
20
+	protected $migration_manager;
21
+
22
+	/**
23
+	 * @var EE_Maintenance_Mode
24
+	 */
25
+	protected $maintenance_mode;
26
+
27
+	/**
28
+	 * @var EE_Form_Section_Proper
29
+	 */
30
+	protected $datetime_fix_offset_form;
31
+
32
+
33
+	/**
34
+	 * @param bool $routing
35
+	 * @throws EE_Error
36
+	 * @throws ReflectionException
37
+	 */
38
+	public function __construct($routing = true)
39
+	{
40
+		$this->migration_manager = EE_Data_Migration_Manager::instance();
41
+		$this->maintenance_mode  = EE_Maintenance_Mode::instance();
42
+		parent::__construct($routing);
43
+	}
44
+
45
+
46
+	protected function _init_page_props()
47
+	{
48
+		$this->page_slug        = EE_MAINTENANCE_PG_SLUG;
49
+		$this->page_label       = EE_MAINTENANCE_LABEL;
50
+		$this->_admin_base_url  = EE_MAINTENANCE_ADMIN_URL;
51
+		$this->_admin_base_path = EE_MAINTENANCE_ADMIN;
52
+	}
53
+
54
+
55
+	protected function _ajax_hooks()
56
+	{
57
+		add_action('wp_ajax_migration_step', [$this, 'migration_step']);
58
+		add_action('wp_ajax_add_error_to_migrations_ran', [$this, 'add_error_to_migrations_ran']);
59
+	}
60
+
61
+
62
+	protected function _define_page_props()
63
+	{
64
+		$this->_admin_page_title = EE_MAINTENANCE_LABEL;
65
+		$this->_labels           = [
66
+			'buttons' => [
67
+				'reset_reservations' => esc_html__('Reset Ticket and Datetime Reserved Counts', 'event_espresso'),
68
+				'reset_capabilities' => esc_html__('Reset Event Espresso Capabilities', 'event_espresso'),
69
+			],
70
+		];
71
+	}
72
+
73
+
74
+	protected function _set_page_routes()
75
+	{
76
+		$this->_page_routes = [
77
+			'default'                             => [
78
+				'func'       => '_maintenance',
79
+				'capability' => 'manage_options',
80
+			],
81
+			'change_maintenance_level'            => [
82
+				'func'       => '_change_maintenance_level',
83
+				'capability' => 'manage_options',
84
+				'noheader'   => true,
85
+			],
86
+			'system_status'                       => [
87
+				'func'       => '_system_status',
88
+				'capability' => 'manage_options',
89
+			],
90
+			'download_system_status'              => [
91
+				'func'       => '_download_system_status',
92
+				'capability' => 'manage_options',
93
+				'noheader'   => true,
94
+			],
95
+			'send_migration_crash_report'         => [
96
+				'func'       => '_send_migration_crash_report',
97
+				'capability' => 'manage_options',
98
+				'noheader'   => true,
99
+			],
100
+			'confirm_migration_crash_report_sent' => [
101
+				'func'       => '_confirm_migration_crash_report_sent',
102
+				'capability' => 'manage_options',
103
+			],
104
+			'data_reset'                          => [
105
+				'func'       => '_data_reset_and_delete',
106
+				'capability' => 'manage_options',
107
+			],
108
+			'reset_db'                            => [
109
+				'func'       => '_reset_db',
110
+				'capability' => 'manage_options',
111
+				'noheader'   => true,
112
+				'args'       => ['nuke_old_ee4_data' => true],
113
+			],
114
+			'start_with_fresh_ee4_db'             => [
115
+				'func'       => '_reset_db',
116
+				'capability' => 'manage_options',
117
+				'noheader'   => true,
118
+				'args'       => ['nuke_old_ee4_data' => false],
119
+			],
120
+			'delete_db'                           => [
121
+				'func'       => '_delete_db',
122
+				'capability' => 'manage_options',
123
+				'noheader'   => true,
124
+			],
125
+			'rerun_migration_from_ee3'            => [
126
+				'func'       => '_rerun_migration_from_ee3',
127
+				'capability' => 'manage_options',
128
+				'noheader'   => true,
129
+			],
130
+			'reset_reservations'                  => [
131
+				'func'       => '_reset_reservations',
132
+				'capability' => 'manage_options',
133
+				'noheader'   => true,
134
+			],
135
+			'reset_capabilities'                  => [
136
+				'func'       => '_reset_capabilities',
137
+				'capability' => 'manage_options',
138
+				'noheader'   => true,
139
+			],
140
+			'reattempt_migration'                 => [
141
+				'func'       => '_reattempt_migration',
142
+				'capability' => 'manage_options',
143
+				'noheader'   => true,
144
+			],
145
+			'datetime_tools'                      => [
146
+				'func'       => '_datetime_tools',
147
+				'capability' => 'manage_options',
148
+			],
149
+			'run_datetime_offset_fix'             => [
150
+				'func'               => '_apply_datetime_offset',
151
+				'noheader'           => true,
152
+				'headers_sent_route' => 'datetime_tools',
153
+				'capability'         => 'manage_options',
154
+			],
155
+		];
156
+	}
157
+
158
+
159
+	protected function _set_page_config()
160
+	{
161
+		$this->_page_config = [
162
+			'default'        => [
163
+				'nav'           => [
164
+					'label' => esc_html__('Maintenance', 'event_espresso'),
165
+					'icon' => 'dashicons-admin-tools',
166
+					'order' => 10,
167
+				],
168
+				'require_nonce' => false,
169
+			],
170
+			'data_reset'     => [
171
+				'nav'           => [
172
+					'label' => esc_html__('Reset/Delete Data', 'event_espresso'),
173
+					'icon' => 'dashicons-trash',
174
+					'order' => 20,
175
+				],
176
+				'require_nonce' => false,
177
+			],
178
+			'datetime_tools' => [
179
+				'nav'           => [
180
+					'label' => esc_html__('Datetime Utilities', 'event_espresso'),
181
+					'icon' => 'dashicons-calendar-alt',
182
+					'order' => 25,
183
+				],
184
+				'require_nonce' => false,
185
+			],
186
+			'system_status'  => [
187
+				'nav'           => [
188
+					'label' => esc_html__("System Information", "event_espresso"),
189
+					'icon' => 'dashicons-info',
190
+					'order' => 30,
191
+				],
192
+				'require_nonce' => false,
193
+			],
194
+		];
195
+	}
196
+
197
+
198
+	/**
199
+	 * default maintenance page.
200
+	 * If we're in maintenance mode level 2, then we need to show the migration scripts and all that UI.
201
+	 *
202
+	 * @throws EE_Error
203
+	 */
204
+	public function _maintenance()
205
+	{
206
+		$show_maintenance_switch         = true;
207
+		$show_backup_db_text             = false;
208
+		$show_migration_progress         = false;
209
+		$script_names                    = [];
210
+		$addons_should_be_upgraded_first = false;
211
+		// it all depends on if we're in maintenance model level 1 (frontend-only) or
212
+		// level 2 (everything except maintenance page)
213
+		try {
214
+			// get the current maintenance level and check if
215
+			// we are removed
216
+			$mMode_level  = $this->maintenance_mode->level();
217
+			$placed_in_mm = $this->maintenance_mode->set_maintenance_mode_if_db_old();
218
+			if ($mMode_level == EE_Maintenance_Mode::level_2_complete_maintenance && ! $placed_in_mm) {
219
+				// we just took the site out of maintenance mode, so notify the user.
220
+				// unfortunately this message appears to be echoed on the NEXT page load...
221
+				// oh well, we should really be checking for this on addon deactivation anyways
222
+				EE_Error::add_attention(
223
+					esc_html__(
224
+						'Site taken out of maintenance mode because no data migration scripts are required',
225
+						'event_espresso'
226
+					)
227
+				);
228
+				$this->_process_notices(['page' => 'espresso_maintenance_settings']);
229
+			}
230
+			// in case an exception is thrown while trying to handle migrations
231
+			if ($mMode_level === EE_Maintenance_Mode::level_2_complete_maintenance) {
232
+				$show_maintenance_switch = false;
233
+				$show_migration_progress = true;
234
+				if (isset($this->_req_data['continue_migration'])) {
235
+					$show_backup_db_text = false;
236
+				} else {
237
+					$show_backup_db_text = true;
238
+				}
239
+				$scripts_needing_to_run          =
240
+					$this->migration_manager->check_for_applicable_data_migration_scripts();
241
+				$addons_should_be_upgraded_first = $this->migration_manager->addons_need_updating();
242
+				$script_names                    = [];
243
+				$current_script                  = null;
244
+				foreach ($scripts_needing_to_run as $script) {
245
+					if ($script instanceof EE_Data_Migration_Script_Base) {
246
+						if (! $current_script) {
247
+							$current_script = $script;
248
+							$current_script->migration_page_hooks();
249
+						}
250
+						$script_names[] = $script->pretty_name();
251
+					}
252
+				}
253
+			}
254
+			$most_recent_migration = $this->migration_manager->get_last_ran_script(true);
255
+			$exception_thrown      = false;
256
+		} catch (EE_Error $e) {
257
+			$this->migration_manager->add_error_to_migrations_ran($e->getMessage());
258
+			// now, just so we can display the page correctly, make an error migration script stage object
259
+			// and also put the error on it. It only persists for the duration of this request
260
+			$most_recent_migration = new EE_DMS_Unknown_1_0_0();
261
+			$most_recent_migration->add_error($e->getMessage());
262
+			$exception_thrown = true;
263
+		}
264
+		$current_db_state = $this->migration_manager->ensure_current_database_state_is_set();
265
+		$current_db_state = str_replace('.decaf', '', $current_db_state);
266
+		if (
267
+			$exception_thrown
268
+			|| (
269
+				$most_recent_migration instanceof EE_Data_Migration_Script_Base
270
+				&& $most_recent_migration->is_broken()
271
+			)
272
+		) {
273
+			$this->_template_path                =
274
+				EE_MAINTENANCE_TEMPLATE_PATH . 'ee_migration_was_borked_page.template.php';
275
+			$this->_template_args['support_url'] = 'https://eventespresso.com/support/forums/';
276
+			$this->_template_args['next_url']    = EEH_URL::add_query_args_and_nonce(
277
+				[
278
+					'action'  => 'confirm_migration_crash_report_sent',
279
+					'success' => '0',
280
+				],
281
+				EE_MAINTENANCE_ADMIN_URL
282
+			);
283
+		} elseif ($addons_should_be_upgraded_first) {
284
+			$this->_template_path = EE_MAINTENANCE_TEMPLATE_PATH . 'ee_upgrade_addons_before_migrating.template.php';
285
+		} else {
286
+			if (
287
+				$most_recent_migration instanceof EE_Data_Migration_Script_Base
288
+				&& $most_recent_migration->can_continue()
289
+			) {
290
+				$show_backup_db_text                    = false;
291
+				$show_continue_current_migration_script = true;
292
+				$show_most_recent_migration             = true;
293
+			} elseif (isset($this->_req_data['continue_migration'])) {
294
+				$show_most_recent_migration             = true;
295
+				$show_continue_current_migration_script = false;
296
+			} else {
297
+				$show_most_recent_migration             = false;
298
+				$show_continue_current_migration_script = false;
299
+			}
300
+			if (isset($current_script)) {
301
+				$migrates_to          = $current_script->migrates_to_version();
302
+				$plugin_slug          = $migrates_to['slug'];
303
+				$new_version          = $migrates_to['version'];
304
+				$this->_template_args = array_merge(
305
+					$this->_template_args,
306
+					[
307
+						'current_db_state' => sprintf(
308
+							esc_html__("EE%s (%s)", "event_espresso"),
309
+							isset($current_db_state[ $plugin_slug ]) ? $current_db_state[ $plugin_slug ] : 3,
310
+							$plugin_slug
311
+						),
312
+						'next_db_state'    => sprintf(
313
+							esc_html__("EE%s (%s)", 'event_espresso'),
314
+							$new_version,
315
+							$plugin_slug
316
+						),
317
+					]
318
+				);
319
+			} else {
320
+				$this->_template_args['current_db_state'] = null;
321
+				$this->_template_args['next_db_state']    = null;
322
+			}
323
+			$this->_template_path = EE_MAINTENANCE_TEMPLATE_PATH . 'ee_migration_page.template.php';
324
+			$this->_template_args = array_merge(
325
+				$this->_template_args,
326
+				[
327
+					'show_most_recent_migration'             => $show_most_recent_migration,
328
+					// flag for showing the most recent migration's status and/or errors
329
+					'show_migration_progress'                => $show_migration_progress,
330
+					// flag for showing the option to run migrations and see their progress
331
+					'show_backup_db_text'                    => $show_backup_db_text,
332
+					// flag for showing text telling the user to back up their DB
333
+					'show_maintenance_switch'                => $show_maintenance_switch,
334
+					// flag for showing the option to change maintenance mode between levels 0 and 1
335
+					'script_names'                           => $script_names,
336
+					// array of names of scripts that have run
337
+					'show_continue_current_migration_script' => $show_continue_current_migration_script,
338
+					// flag to change wording to indicating that we're only CONTINUING a migration script (somehow it got interrupted0
339
+					'reset_db_page_link'                     => EE_Admin_Page::add_query_args_and_nonce(
340
+						['action' => 'reset_db'],
341
+						EE_MAINTENANCE_ADMIN_URL
342
+					),
343
+					'data_reset_page'                        => EE_Admin_Page::add_query_args_and_nonce(
344
+						['action' => 'data_reset'],
345
+						EE_MAINTENANCE_ADMIN_URL
346
+					),
347
+					'update_migration_script_page_link'      => EE_Admin_Page::add_query_args_and_nonce(
348
+						['action' => 'change_maintenance_level'],
349
+						EE_MAINTENANCE_ADMIN_URL
350
+					),
351
+					'ultimate_db_state'                      => sprintf(
352
+						esc_html__("EE%s", 'event_espresso'),
353
+						espresso_version()
354
+					),
355
+				]
356
+			);
357
+		}
358
+		$this->_template_args['most_recent_migration'] =
359
+			$most_recent_migration;// the actual most recently ran migration
360
+		// now render the migration options part, and put it in a variable
361
+		$migration_options_template_file                = apply_filters(
362
+			'FHEE__ee_migration_page__migration_options_template',
363
+			EE_MAINTENANCE_TEMPLATE_PATH . 'migration_options_from_ee4.template.php'
364
+		);
365
+		$migration_options_html                         = EEH_Template::display_template(
366
+			$migration_options_template_file,
367
+			$this->_template_args,
368
+			true
369
+		);
370
+		$this->_template_args['migration_options_html'] = $migration_options_html;
371
+		$this->_template_args['admin_page_content']     = EEH_Template::display_template(
372
+			$this->_template_path,
373
+			$this->_template_args,
374
+			true
375
+		);
376
+		$this->display_admin_page_with_sidebar();
377
+	}
378
+
379
+
380
+	/**
381
+	 * returns JSON and executes another step of the currently-executing data migration (called via ajax)
382
+	 *
383
+	 * @throws EE_Error
384
+	 */
385
+	public function migration_step()
386
+	{
387
+		$this->_template_args['data'] = $this->migration_manager->response_to_migration_ajax_request();
388
+		$this->_return_json();
389
+	}
390
+
391
+
392
+	/**
393
+	 * Can be used by js when it notices a response with HTML in it in order
394
+	 * to log the malformed response
395
+	 *
396
+	 * @throws EE_Error
397
+	 */
398
+	public function add_error_to_migrations_ran()
399
+	{
400
+		$this->migration_manager->add_error_to_migrations_ran($this->_req_data['message']);
401
+		$this->_template_args['data'] = ['ok' => true];
402
+		$this->_return_json();
403
+	}
404
+
405
+
406
+	/**
407
+	 * changes the maintenance level, provided there are still no migration scripts that should run
408
+	 *
409
+	 * @throws EE_Error
410
+	 */
411
+	public function _change_maintenance_level()
412
+	{
413
+		$new_level = absint($this->_req_data['maintenance_mode_level']);
414
+		if (! $this->migration_manager->check_for_applicable_data_migration_scripts()) {
415
+			$this->maintenance_mode->set_maintenance_level($new_level);
416
+			$success = true;
417
+		} else {
418
+			$this->maintenance_mode->set_maintenance_mode_if_db_old();
419
+			$success = false;
420
+		}
421
+		$this->_redirect_after_action($success, 'Maintenance Mode', esc_html__("Updated", "event_espresso"));
422
+	}
423
+
424
+
425
+	/**
426
+	 * a tab with options for resetting and/or deleting EE data
427
+	 *
428
+	 * @throws EE_Error
429
+	 * @throws DomainException
430
+	 */
431
+	public function _data_reset_and_delete()
432
+	{
433
+		$this->_template_path                              =
434
+			EE_MAINTENANCE_TEMPLATE_PATH . 'ee_data_reset_and_delete.template.php';
435
+		$this->_template_args['reset_reservations_button'] = $this->get_action_link_or_button(
436
+			'reset_reservations',
437
+			'reset_reservations',
438
+			[],
439
+			'button button--caution ee-confirm'
440
+		);
441
+		$this->_template_args['reset_capabilities_button'] = $this->get_action_link_or_button(
442
+			'reset_capabilities',
443
+			'reset_capabilities',
444
+			[],
445
+			'button button--caution ee-confirm'
446
+		);
447
+		$this->_template_args['delete_db_url']             = EE_Admin_Page::add_query_args_and_nonce(
448
+			['action' => 'delete_db'],
449
+			EE_MAINTENANCE_ADMIN_URL
450
+		);
451
+		$this->_template_args['reset_db_url']              = EE_Admin_Page::add_query_args_and_nonce(
452
+			['action' => 'reset_db'],
453
+			EE_MAINTENANCE_ADMIN_URL
454
+		);
455
+		$this->_template_args['admin_page_content']        = EEH_Template::display_template(
456
+			$this->_template_path,
457
+			$this->_template_args,
458
+			true
459
+		);
460
+		$this->display_admin_page_with_no_sidebar();
461
+	}
462
+
463
+
464
+	/**
465
+	 * @throws EE_Error
466
+	 * @throws ReflectionException
467
+	 */
468
+	protected function _reset_reservations()
469
+	{
470
+		if (EED_Ticket_Sales_Monitor::reset_reservation_counts()) {
471
+			EE_Error::add_success(
472
+				esc_html__(
473
+					'Ticket and datetime reserved counts have been successfully reset.',
474
+					'event_espresso'
475
+				)
476
+			);
477
+		} else {
478
+			EE_Error::add_success(
479
+				esc_html__(
480
+					'Ticket and datetime reserved counts were correct and did not need resetting.',
481
+					'event_espresso'
482
+				)
483
+			);
484
+		}
485
+		$this->_redirect_after_action(true, '', '', ['action' => 'data_reset'], true);
486
+	}
487
+
488
+
489
+	/**
490
+	 * @throws EE_Error
491
+	 */
492
+	protected function _reset_capabilities()
493
+	{
494
+		EE_Registry::instance()->CAP->init_caps(true);
495
+		EE_Error::add_success(
496
+			esc_html__(
497
+				'Default Event Espresso capabilities have been restored for all current roles.',
498
+				'event_espresso'
499
+			)
500
+		);
501
+		$this->_redirect_after_action(false, '', '', ['action' => 'data_reset'], true);
502
+	}
503
+
504
+
505
+	/**
506
+	 * resets the DMSs, so we can attempt to continue migrating after a fatal error
507
+	 * (only a good idea when someone has somehow tried ot fix whatever caused
508
+	 * the fatal error in teh first place)
509
+	 *
510
+	 * @throws EE_Error
511
+	 */
512
+	protected function _reattempt_migration()
513
+	{
514
+		$this->migration_manager->reattempt();
515
+		$this->_redirect_after_action(false, '', '', ['action' => 'default'], true);
516
+	}
517
+
518
+
519
+	/**
520
+	 * shows the big ol' System Information page
521
+	 *
522
+	 * @throws EE_Error
523
+	 */
524
+	public function _system_status()
525
+	{
526
+		$this->_template_path = EE_MAINTENANCE_TEMPLATE_PATH . 'ee_system_stati_page.template.php';
527
+		$this->_template_args['system_stati']               = EEM_System_Status::instance()->get_system_stati();
528
+		$this->_template_args['download_system_status_url'] = EE_Admin_Page::add_query_args_and_nonce(
529
+			[
530
+				'action' => 'download_system_status',
531
+			],
532
+			EE_MAINTENANCE_ADMIN_URL
533
+		);
534
+		$this->_template_args['admin_page_content']         = EEH_Template::display_template(
535
+			$this->_template_path,
536
+			$this->_template_args,
537
+			true
538
+		);
539
+		$this->display_admin_page_with_no_sidebar();
540
+	}
541
+
542
+
543
+	/**
544
+	 * Downloads an HTML file of the system status that can be easily stored or emailed
545
+	 */
546
+	public function _download_system_status()
547
+	{
548
+		$status_info = EEM_System_Status::instance()->get_system_stati();
549
+		header('Content-Disposition: attachment');
550
+		header("Content-Disposition: attachment; filename=system_status_" . sanitize_key(site_url()) . ".html");
551
+		$output = '<style>table{border:1px solid darkgrey;}td{vertical-align:top}</style>';
552
+		$output .= '<h1>' . sprintf(
553
+			__('System Information for %1$s', 'event_espresso'),
554
+			esc_url_raw(site_url())
555
+		) . '</h1>';
556
+		$output .= EEH_Template::layout_array_as_table($status_info);
557
+		echo esc_html($output);
558
+		die;
559
+	}
560
+
561
+
562
+	/**
563
+	 * @throws EE_Error
564
+	 */
565
+	public function _send_migration_crash_report()
566
+	{
567
+		$from      = $this->_req_data['from'];
568
+		$from_name = $this->_req_data['from_name'];
569
+		$body      = $this->_req_data['body'];
570
+		try {
571
+			$success = wp_mail(
572
+				EE_SUPPORT_EMAIL,
573
+				'Migration Crash Report',
574
+				$body . "/r/n<br>" . print_r(EEM_System_Status::instance()->get_system_stati(), true),
575
+				[
576
+					"from:$from_name<$from>",
577
+				]
578
+			);
579
+		} catch (Exception $e) {
580
+			$success = false;
581
+		}
582
+		$this->_redirect_after_action(
583
+			$success,
584
+			esc_html__("Migration Crash Report", "event_espresso"),
585
+			esc_html__("sent", "event_espresso"),
586
+			['success' => $success, 'action' => 'confirm_migration_crash_report_sent']
587
+		);
588
+	}
589
+
590
+
591
+	/**
592
+	 * @throws EE_Error
593
+	 */
594
+	public function _confirm_migration_crash_report_sent()
595
+	{
596
+		try {
597
+			$most_recent_migration = $this->migration_manager->get_last_ran_script(true);
598
+		} catch (EE_Error $e) {
599
+			$this->migration_manager->add_error_to_migrations_ran($e->getMessage());
600
+			// now, just so we can display the page correctly, make an error migration script stage object
601
+			// and also put the error on it. It only persists for the duration of this request
602
+			$most_recent_migration = new EE_DMS_Unknown_1_0_0();
603
+			$most_recent_migration->add_error($e->getMessage());
604
+		}
605
+		$success                                       = $this->_req_data['success'] === '1';
606
+		$this->_template_args['success']               = $success;
607
+		$this->_template_args['most_recent_migration'] = $most_recent_migration;
608
+		$this->_template_args['reset_db_action_url']   = EE_Admin_Page::add_query_args_and_nonce(
609
+			['action' => 'reset_db'],
610
+			EE_MAINTENANCE_ADMIN_URL
611
+		);
612
+		$this->_template_args['reset_db_page_url']     = EE_Admin_Page::add_query_args_and_nonce(
613
+			['action' => 'data_reset'],
614
+			EE_MAINTENANCE_ADMIN_URL
615
+		);
616
+		$this->_template_args['reattempt_action_url']  = EE_Admin_Page::add_query_args_and_nonce(
617
+			['action' => 'reattempt_migration'],
618
+			EE_MAINTENANCE_ADMIN_URL
619
+		);
620
+		$this->_template_path                          =
621
+			EE_MAINTENANCE_TEMPLATE_PATH . 'ee_confirm_migration_crash_report_sent.template.php';
622
+		$this->_template_args['admin_page_content']    = EEH_Template::display_template(
623
+			$this->_template_path,
624
+			$this->_template_args,
625
+			true
626
+		);
627
+		$this->display_admin_page_with_sidebar();
628
+	}
629
+
630
+
631
+	/**
632
+	 * Resets the entire EE4 database.
633
+	 * only sets up ee4 database for a fresh install-
634
+	 * doesn't actually clean out the old wp options, or cpts
635
+	 * (although it does erase old ee table data)
636
+	 *
637
+	 * @param boolean $nuke_old_ee4_data controls whether we destroy the old ee4 data,
638
+	 *                                   or just try initializing ee4 default data
639
+	 * @throws EE_Error
640
+	 * @throws ReflectionException
641
+	 */
642
+	public function _reset_db($nuke_old_ee4_data = true)
643
+	{
644
+		$this->maintenance_mode->set_maintenance_level(EE_Maintenance_Mode::level_0_not_in_maintenance);
645
+		if ($nuke_old_ee4_data) {
646
+			EEH_Activation::delete_all_espresso_cpt_data();
647
+			EEH_Activation::delete_all_espresso_tables_and_data(false);
648
+			EEH_Activation::remove_cron_tasks();
649
+		}
650
+		// make sure when we reset the registry's config that it
651
+		// switches to using the new singleton
652
+		EE_Registry::instance()->CFG = EE_Registry::instance()->CFG->reset(true);
653
+		EE_System::instance()->initialize_db_if_no_migrations_required(true);
654
+		EE_System::instance()->redirect_to_about_ee();
655
+	}
656
+
657
+
658
+	/**
659
+	 * Deletes ALL EE tables, Records, and Options from the database.
660
+	 *
661
+	 * @throws EE_Error
662
+	 * @throws ReflectionException
663
+	 */
664
+	public function _delete_db()
665
+	{
666
+		$this->maintenance_mode->set_maintenance_level(EE_Maintenance_Mode::level_0_not_in_maintenance);
667
+		EEH_Activation::delete_all_espresso_cpt_data();
668
+		EEH_Activation::delete_all_espresso_tables_and_data();
669
+		EEH_Activation::remove_cron_tasks();
670
+		EEH_Activation::deactivate_event_espresso();
671
+		wp_safe_redirect(admin_url('plugins.php'));
672
+		exit;
673
+	}
674
+
675
+
676
+	/**
677
+	 * sets up EE4 to rerun the migrations from ee3 to ee4
678
+	 *
679
+	 * @throws EE_Error
680
+	 * @throws ReflectionException
681
+	 */
682
+	public function _rerun_migration_from_ee3()
683
+	{
684
+		$this->maintenance_mode->set_maintenance_level(EE_Maintenance_Mode::level_0_not_in_maintenance);
685
+		EEH_Activation::delete_all_espresso_cpt_data();
686
+		EEH_Activation::delete_all_espresso_tables_and_data(false);
687
+		// set the db state to something that will require migrations
688
+		update_option(EE_Data_Migration_Manager::current_database_state, '3.1.36.0');
689
+		$this->maintenance_mode->set_maintenance_level(EE_Maintenance_Mode::level_2_complete_maintenance);
690
+		$this->_redirect_after_action(
691
+			true,
692
+			esc_html__("Database", 'event_espresso'),
693
+			esc_html__("reset", 'event_espresso')
694
+		);
695
+	}
696
+
697
+
698
+	// none of the below group are currently used for Gateway Settings
699
+	protected function _add_screen_options()
700
+	{
701
+	}
702
+
703
+
704
+	protected function _add_feature_pointers()
705
+	{
706
+	}
707
+
708
+
709
+	public function admin_init()
710
+	{
711
+	}
712
+
713
+
714
+	public function admin_notices()
715
+	{
716
+	}
717
+
718
+
719
+	public function admin_footer_scripts()
720
+	{
721
+	}
722
+
723
+
724
+	public function load_scripts_styles()
725
+	{
726
+		wp_enqueue_script('ee_admin_js');
727
+		wp_enqueue_script(
728
+			'ee-maintenance',
729
+			EE_MAINTENANCE_ASSETS_URL . 'ee-maintenance.js',
730
+			['jquery'],
731
+			EVENT_ESPRESSO_VERSION,
732
+			true
733
+		);
734
+		wp_register_style(
735
+			'espresso_maintenance',
736
+			EE_MAINTENANCE_ASSETS_URL . 'ee-maintenance.css',
737
+			[],
738
+			EVENT_ESPRESSO_VERSION
739
+		);
740
+		wp_enqueue_style('espresso_maintenance');
741
+		// localize script stuff
742
+		wp_localize_script(
743
+			'ee-maintenance',
744
+			'ee_maintenance',
745
+			[
746
+				'migrating'                        => wp_strip_all_tags(__("Updating Database...", "event_espresso")),
747
+				'next'                             => wp_strip_all_tags(__("Next", "event_espresso")),
748
+				'fatal_error'                      => wp_strip_all_tags(__(
749
+					"A Fatal Error Has Occurred",
750
+					"event_espresso"
751
+				)),
752
+				'click_next_when_ready'            => wp_strip_all_tags(
753
+					__(
754
+						"The current Database Update has ended. Click 'next' when ready to proceed",
755
+						"event_espresso"
756
+					)
757
+				),
758
+				'status_no_more_migration_scripts' => EE_Data_Migration_Manager::status_no_more_migration_scripts,
759
+				'status_fatal_error'               => EE_Data_Migration_Manager::status_fatal_error,
760
+				'status_completed'                 => EE_Data_Migration_Manager::status_completed,
761
+				'confirm'                          => wp_strip_all_tags(
762
+					__(
763
+						'Are you sure you want to do this? It CANNOT be undone!',
764
+						'event_espresso'
765
+					)
766
+				),
767
+				'confirm_skip_migration'           => wp_strip_all_tags(
768
+					__(
769
+						'You have chosen to NOT migrate your existing data. Are you sure you want to continue?',
770
+						'event_espresso'
771
+					)
772
+				),
773
+			]
774
+		);
775
+	}
776
+
777
+
778
+	public function load_scripts_styles_default()
779
+	{
780
+	}
781
+
782
+
783
+	/**
784
+	 * Enqueue scripts and styles for the datetime tools page.
785
+	 */
786
+	public function load_scripts_styles_datetime_tools()
787
+	{
788
+		EE_Datepicker_Input::enqueue_styles_and_scripts();
789
+	}
790
+
791
+
792
+	/**
793
+	 * @throws EE_Error
794
+	 */
795
+	protected function _datetime_tools()
796
+	{
797
+		$form_action                                = EE_Admin_Page::add_query_args_and_nonce(
798
+			[
799
+				'action'        => 'run_datetime_offset_fix',
800
+				'return_action' => $this->_req_action,
801
+			],
802
+			EE_MAINTENANCE_ADMIN_URL
803
+		);
804
+		$form                                       = $this->_get_datetime_offset_fix_form();
805
+		$this->_admin_page_title                    = esc_html__('Datetime Utilities', 'event_espresso');
806
+		$this->_template_args['admin_page_content'] = $form->form_open($form_action, 'post')
807
+													  . $form->get_html_and_js()
808
+													  . $form->form_close();
809
+		$this->display_admin_page_with_sidebar();
810
+	}
811
+
812
+
813
+	/**
814
+	 * @throws EE_Error
815
+	 */
816
+	protected function _get_datetime_offset_fix_form()
817
+	{
818
+		if (! $this->datetime_fix_offset_form instanceof EE_Form_Section_Proper) {
819
+			$this->datetime_fix_offset_form = new EE_Form_Section_Proper(
820
+				[
821
+					'name'            => 'datetime_offset_fix_option',
822
+					'layout_strategy' => new EE_Admin_Two_Column_Layout(),
823
+					'subsections'     => [
824
+						'title'                  => new EE_Form_Section_HTML(
825
+							EEH_HTML::h2(
826
+								esc_html__('Datetime Offset Tool', 'event_espresso')
827
+							)
828
+						),
829
+						'explanation'            => new EE_Form_Section_HTML(
830
+							EEH_HTML::p(
831
+								esc_html__(
832
+									'Use this tool to automatically apply the provided offset to all Event Espresso records in your database that involve dates and times.',
833
+									'event_espresso'
834
+								)
835
+							)
836
+							. EEH_HTML::p(
837
+								esc_html__(
838
+									'Note: If you enter 1.25, that will result in the offset of 1 hour 15 minutes being applied.  Decimals represent the fraction of hours, not minutes.',
839
+									'event_espresso'
840
+								)
841
+							)
842
+						),
843
+						'offset_input'           => new EE_Float_Input(
844
+							[
845
+								'html_name'       => 'offset_for_datetimes',
846
+								'html_label_text' => esc_html__(
847
+									'Offset to apply (in hours):',
848
+									'event_espresso'
849
+								),
850
+								'min_value'       => '-12',
851
+								'max_value'       => '14',
852
+								'step_value'      => '.25',
853
+								'default'         => DatetimeOffsetFix::getOffset(),
854
+							]
855
+						),
856
+						'date_range_explanation' => new EE_Form_Section_HTML(
857
+							EEH_HTML::p(
858
+								esc_html__(
859
+									'Leave the following fields blank if you want the offset to be applied to all dates. If however, you want to just apply the offset to a specific range of dates you can restrict the offset application using these fields.',
860
+									'event_espresso'
861
+								)
862
+							)
863
+							. EEH_HTML::p(
864
+								EEH_HTML::strong(
865
+									sprintf(
866
+										esc_html__(
867
+											'Note: please enter the dates in UTC (You can use %1$sthis online tool%2$s to assist with conversions).',
868
+											'event_espresso'
869
+										),
870
+										'<a href="https://www.timeanddate.com/worldclock/converter.html">',
871
+										'</a>'
872
+									)
873
+								)
874
+							)
875
+						),
876
+						'date_range_start_date'  => new EE_Datepicker_Input(
877
+							[
878
+								'html_name'       => 'offset_date_start_range',
879
+								'html_label_text' => esc_html__(
880
+									'Start Date for dates the offset applied to:',
881
+									'event_espresso'
882
+								),
883
+							]
884
+						),
885
+						'date_range_end_date'    => new EE_Datepicker_Input(
886
+							[
887
+								'html_name'       => 'offset_date_end_range',
888
+								'html_label_text' => esc_html__(
889
+									'End Date for dates the offset is applied to:',
890
+									'event_espresso'
891
+								),
892
+							]
893
+						),
894
+						'submit'                 => new EE_Submit_Input(
895
+							[
896
+								'html_label_text' => '',
897
+								'default'         => esc_html__('Apply Offset', 'event_espresso'),
898
+							]
899
+						),
900
+					],
901
+				]
902
+			);
903
+		}
904
+		return $this->datetime_fix_offset_form;
905
+	}
906
+
907
+
908
+	/**
909
+	 * Callback for the run_datetime_offset_fix route.
910
+	 *
911
+	 * @throws EE_Error
912
+	 */
913
+	protected function _apply_datetime_offset()
914
+	{
915
+		if ($_SERVER['REQUEST_METHOD'] === 'POST') {
916
+			$form = $this->_get_datetime_offset_fix_form();
917
+			$form->receive_form_submission($this->_req_data);
918
+			if ($form->is_valid()) {
919
+				// save offset data so batch processor can get it.
920
+				DatetimeOffsetFix::updateOffset($form->get_input_value('offset_input'));
921
+				$utc_timezone          = new DateTimeZone('UTC');
922
+				$date_range_start_date = DateTime::createFromFormat(
923
+					'm/d/Y H:i:s',
924
+					$form->get_input_value('date_range_start_date') . ' 00:00:00',
925
+					$utc_timezone
926
+				);
927
+				$date_range_end_date   = DateTime::createFromFormat(
928
+					'm/d/Y H:i:s',
929
+					$form->get_input_value('date_range_end_date') . ' 23:59:59',
930
+					$utc_timezone
931
+				);
932
+				if ($date_range_start_date instanceof DateTime) {
933
+					DatetimeOffsetFix::updateStartDateRange(DbSafeDateTime::createFromDateTime($date_range_start_date));
934
+				}
935
+				if ($date_range_end_date instanceof DateTime) {
936
+					DatetimeOffsetFix::updateEndDateRange(DbSafeDateTime::createFromDateTime($date_range_end_date));
937
+				}
938
+				// redirect to batch tool
939
+				wp_redirect(
940
+					EE_Admin_Page::add_query_args_and_nonce(
941
+						[
942
+							'page'        => EED_Batch::PAGE_SLUG,
943
+							'batch'       => EED_Batch::batch_job,
944
+							'label'       => esc_html__('Applying Offset', 'event_espresso'),
945
+							'job_handler' => urlencode('EventEspressoBatchRequest\JobHandlers\DatetimeOffsetFix'),
946
+							'return_url'  => urlencode(
947
+								add_query_arg(
948
+									[
949
+										'action' => 'datetime_tools',
950
+									],
951
+									EEH_URL::current_url_without_query_paramaters(
952
+										[
953
+											'return_action',
954
+											'run_datetime_offset_fix_nonce',
955
+											'return',
956
+											'datetime_tools_nonce',
957
+										]
958
+									)
959
+								)
960
+							),
961
+						],
962
+						admin_url()
963
+					)
964
+				);
965
+				exit;
966
+			}
967
+		}
968
+	}
969 969
 }
Please login to merge, or discard this patch.