Completed
Branch master (5dc63c)
by
unknown
04:57
created
core/libraries/messages/messenger/EE_Html_messenger.class.php 2 patches
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -40,7 +40,7 @@  discard block
 block discarded – undo
40 40
             'This messenger outputs a message to a browser for display.',
41 41
             'event_espresso'
42 42
         );
43
-        $this->label               = [
43
+        $this->label = [
44 44
             'singular' => esc_html__('html', 'event_espresso'),
45 45
             'plural'   => esc_html__('html', 'event_espresso'),
46 46
         ];
@@ -312,7 +312,7 @@  discard block
 block discarded – undo
312 312
                     ],
313 313
                     'ticket_line_item_no_pms'       => [
314 314
                         'input'               => 'textarea',
315
-                        'label'               => '[TICKET_LINE_ITEM_LIST] <br>' . esc_html__(
315
+                        'label'               => '[TICKET_LINE_ITEM_LIST] <br>'.esc_html__(
316 316
                             'Ticket Line Item List with no Price Modifiers',
317 317
                             'event_espresso'
318 318
                         ),
@@ -326,7 +326,7 @@  discard block
 block discarded – undo
326 326
                     ],
327 327
                     'ticket_line_item_pms'          => [
328 328
                         'input'               => 'textarea',
329
-                        'label'               => '[TICKET_LINE_ITEM_LIST] <br>' . esc_html__(
329
+                        'label'               => '[TICKET_LINE_ITEM_LIST] <br>'.esc_html__(
330 330
                             'Ticket Line Item List with Price Modifiers',
331 331
                             'event_espresso'
332 332
                         ),
@@ -551,7 +551,7 @@  discard block
 block discarded – undo
551 551
                 'aln-cntr',
552 552
                 '',
553 553
                 ['utm_content' => 'messages_system']
554
-            ) . EEH_HTML::div(EEH_HTML::p('&nbsp;'));
554
+            ).EEH_HTML::div(EEH_HTML::p('&nbsp;'));
555 555
         }
556 556
         return $content;
557 557
     }
Please login to merge, or discard this patch.
Indentation   +546 added lines, -546 removed lines patch added patch discarded remove patch
@@ -12,550 +12,550 @@
 block discarded – undo
12 12
  */
13 13
 class EE_Html_messenger extends EE_messenger
14 14
 {
15
-    /**
16
-     * The following are the properties that this messenger requires for displaying the html
17
-     */
18
-    /**
19
-     * This is the html body generated by the template via the message type.
20
-     *
21
-     * @var string
22
-     */
23
-    protected $_content = '';
24
-
25
-    /**
26
-     * This is for the page title that gets displayed.  (Why use "subject"?  Because the "title" tag in html is
27
-     * equivalent to the "subject" of the page.
28
-     *
29
-     * @var string
30
-     */
31
-    protected $_subject = '';
32
-
33
-
34
-    /**
35
-     * EE_Html_messenger constructor.
36
-     */
37
-    public function __construct()
38
-    {
39
-        // set properties
40
-        $this->name                = 'html';
41
-        $this->description         = esc_html__(
42
-            'This messenger outputs a message to a browser for display.',
43
-            'event_espresso'
44
-        );
45
-        $this->label               = [
46
-            'singular' => esc_html__('html', 'event_espresso'),
47
-            'plural'   => esc_html__('html', 'event_espresso'),
48
-        ];
49
-        $this->activate_on_install = true;
50
-        // add the "powered by EE" credit link to the HTML receipt and invoice
51
-        add_filter(
52
-            'FHEE__EE_Html_messenger___send_message__main_body',
53
-            [$this, 'add_powered_by_credit_link_to_receipt_and_invoice'],
54
-            10,
55
-            3
56
-        );
57
-        parent::__construct();
58
-    }
59
-
60
-
61
-    /**
62
-     * HTML Messenger desires execution immediately.
63
-     *
64
-     * @return bool
65
-     * @since  4.9.0
66
-     * @see    parent::send_now() for documentation.
67
-     */
68
-    public function send_now(): bool
69
-    {
70
-        return true;
71
-    }
72
-
73
-
74
-    /**
75
-     * HTML Messenger allows an empty to field.
76
-     *
77
-     * @return bool
78
-     * @since  4.9.0
79
-     * @see    parent::allow_empty_to_field() for documentation
80
-     */
81
-    public function allow_empty_to_field(): bool
82
-    {
83
-        return true;
84
-    }
85
-
86
-
87
-    /**
88
-     * @see abstract declaration in EE_messenger for details.
89
-     */
90
-    protected function _set_admin_pages()
91
-    {
92
-        $this->admin_registered_pages = ['events_edit' => true];
93
-    }
94
-
95
-
96
-    /**
97
-     * @see abstract declaration in EE_messenger for details.
98
-     */
99
-    protected function _set_valid_shortcodes()
100
-    {
101
-        $this->_valid_shortcodes = [];
102
-    }
103
-
104
-
105
-    /**
106
-     * @see abstract declaration in EE_messenger for details.
107
-     */
108
-    protected function _set_validator_config()
109
-    {
110
-        $this->_validator_config = [
111
-            'subject'                       => [
112
-                'shortcodes' => ['organization', 'primary_registration_details', 'email', 'transaction'],
113
-            ],
114
-            'content'                       => [
115
-                'shortcodes' => [
116
-                    'organization',
117
-                    'primary_registration_list',
118
-                    'primary_registration_details',
119
-                    'email',
120
-                    'transaction',
121
-                    'event_list',
122
-                    'payment_list',
123
-                    'venue',
124
-                    'line_item_list',
125
-                    'messenger',
126
-                    'ticket_list',
127
-                ],
128
-            ],
129
-            'event_list'                    => [
130
-                'shortcodes' => [
131
-                    'event',
132
-                    'ticket_list',
133
-                    'venue',
134
-                    'primary_registration_details',
135
-                    'primary_registration_list',
136
-                    'event_author',
137
-                ],
138
-                'required'   => ['[EVENT_LIST]'],
139
-            ],
140
-            'ticket_list'                   => [
141
-                'shortcodes' => [
142
-                    'attendee_list',
143
-                    'ticket',
144
-                    'datetime_list',
145
-                    'primary_registration_details',
146
-                    'line_item_list',
147
-                    'venue',
148
-                ],
149
-                'required'   => ['[TICKET_LIST]'],
150
-            ],
151
-            'ticket_line_item_no_pms'       => [
152
-                'shortcodes' => ['line_item', 'ticket'],
153
-                'required'   => ['[TICKET_LINE_ITEM_LIST]'],
154
-            ],
155
-            'ticket_line_item_pms'          => [
156
-                'shortcodes' => ['line_item', 'ticket', 'line_item_list'],
157
-                'required'   => ['[TICKET_LINE_ITEM_LIST]'],
158
-            ],
159
-            'price_modifier_line_item_list' => [
160
-                'shortcodes' => ['line_item'],
161
-                'required'   => ['[PRICE_MODIFIER_LINE_ITEM_LIST]'],
162
-            ],
163
-            'datetime_list'                 => [
164
-                'shortcodes' => ['datetime'],
165
-                'required'   => ['[DATETIME_LIST]'],
166
-            ],
167
-            'attendee_list'                 => [
168
-                'shortcodes' => ['attendee'],
169
-                'required'   => ['[ATTENDEE_LIST]'],
170
-            ],
171
-            'tax_line_item_list'            => [
172
-                'shortcodes' => ['line_item'],
173
-                'required'   => ['[TAX_LINE_ITEM_LIST]'],
174
-            ],
175
-            'additional_line_item_list'     => [
176
-                'shortcodes' => ['line_item'],
177
-                'required'   => ['[ADDITIONAL_LINE_ITEM_LIST]'],
178
-            ],
179
-            'payment_list'                  => [
180
-                'shortcodes' => ['payment'],
181
-                'required'   => ['[PAYMENT_LIST_*]'],
182
-            ],
183
-        ];
184
-    }
185
-
186
-
187
-    /**
188
-     * This is a method called from EE_messages when this messenger is a generating messenger and the sending messenger
189
-     * is a different messenger.  Child messengers can set hooks for the sending messenger to callback on if necessary
190
-     * (i.e. swap out css files or something else).
191
-     *
192
-     * @param string $sending_messenger_name the name of the sending messenger so we only set the hooks needed.
193
-     * @return void
194
-     * @since 4.5.0
195
-     */
196
-    public function do_secondary_messenger_hooks($sending_messenger_name)
197
-    {
198
-        if ($sending_messenger_name === 'pdf') {
199
-            add_filter('EE_messenger__get_variation__variation', [$this, 'add_html_css'], 10, 8);
200
-        }
201
-    }
202
-
203
-
204
-    /**
205
-     * @param                            $variation_path
206
-     * @param EE_Messages_Template_Pack  $template_pack
207
-     * @param                            $messenger_name
208
-     * @param                            $message_type_name
209
-     * @param                            $url
210
-     * @param                            $type
211
-     * @param                            $variation
212
-     * @param                            $skip_filters
213
-     * @return string
214
-     */
215
-    public function add_html_css(
216
-        $variation_path,
217
-        EE_Messages_Template_Pack $template_pack,
218
-        $messenger_name,
219
-        $message_type_name,
220
-        $url,
221
-        $type,
222
-        $variation,
223
-        $skip_filters
224
-    ): string {
225
-        return $template_pack->get_variation(
226
-            $this->name,
227
-            $message_type_name,
228
-            $type,
229
-            $variation,
230
-            $url,
231
-            '.css',
232
-            $skip_filters
233
-        );
234
-    }
235
-
236
-
237
-    /**
238
-     * Takes care of enqueuing any necessary scripts or styles for the page.  A do_action() so message types using this
239
-     * messenger can add their own js.
240
-     *
241
-     * @return void.
242
-     */
243
-    public function enqueue_scripts_styles()
244
-    {
245
-        parent::enqueue_scripts_styles();
246
-        do_action('AHEE__EE_Html_messenger__enqueue_scripts_styles');
247
-    }
248
-
249
-
250
-    /**
251
-     * _set_template_fields
252
-     * This sets up the fields that a messenger requires for the message to go out.
253
-     *
254
-     * @access  protected
255
-     * @return void
256
-     */
257
-    protected function _set_template_fields()
258
-    {
259
-        // any extra template fields that are NOT used by the messenger
260
-        // but will get used by a messenger field for shortcode replacement
261
-        // get added to the 'extra' key in an associated array
262
-        // indexed by the messenger field they relate to.
263
-        // This is important for the Messages_admin to know what fields to display to the user.
264
-        // Also, notice that the "values" are equal to the field type
265
-        // that messages admin will use to know what kind of field to display.
266
-        // The values ALSO have one index labeled "shortcode".
267
-        // The values in that array indicate which ACTUAL SHORTCODE (i.e. [SHORTCODE])
268
-        // is required in order for this extra field to be displayed.
269
-        //  If the required shortcode isn't part of the shortcodes array
270
-        // then the field is not needed and will not be displayed/parsed.
271
-        $this->_template_fields = [
272
-            'subject' => [
273
-                'input'      => 'text',
274
-                'label'      => esc_html__('Page Title', 'event_espresso'),
275
-                'type'       => 'string',
276
-                'required'   => true,
277
-                'validation' => true,
278
-                'css_class'  => 'large-text',
279
-                'format'     => '%s',
280
-            ],
281
-            'content' => '',
282
-            // left empty b/c it is in the "extra array" but messenger still needs needs to know this is a field.
283
-            'extra'   => [
284
-                'content' => [
285
-                    'main'                          => [
286
-                        'input'      => 'wp_editor',
287
-                        'label'      => esc_html__('Main Content', 'event_espresso'),
288
-                        'type'       => 'string',
289
-                        'required'   => false,
290
-                        'validation' => true,
291
-                        'format'     => '%s',
292
-                        'rows'       => '15',
293
-                    ],
294
-                    'event_list'                    => [
295
-                        'input'               => 'wp_editor',
296
-                        'label'               => '[EVENT_LIST]',
297
-                        'type'                => 'string',
298
-                        'required'            => false,
299
-                        'validation'          => true,
300
-                        'format'              => '%s',
301
-                        'rows'                => '15',
302
-                        'shortcodes_required' => ['[EVENT_LIST]'],
303
-                    ],
304
-                    'ticket_list'                   => [
305
-                        'input'               => 'textarea',
306
-                        'label'               => '[TICKET_LIST]',
307
-                        'type'                => 'string',
308
-                        'required'            => false,
309
-                        'validation'          => true,
310
-                        'format'              => '%s',
311
-                        'css_class'           => 'large-text',
312
-                        'rows'                => '10',
313
-                        'shortcodes_required' => ['[TICKET_LIST]'],
314
-                    ],
315
-                    'ticket_line_item_no_pms'       => [
316
-                        'input'               => 'textarea',
317
-                        'label'               => '[TICKET_LINE_ITEM_LIST] <br>' . esc_html__(
318
-                            'Ticket Line Item List with no Price Modifiers',
319
-                            'event_espresso'
320
-                        ),
321
-                        'type'                => 'string',
322
-                        'required'            => false,
323
-                        'validation'          => true,
324
-                        'format'              => '%s',
325
-                        'css_class'           => 'large-text',
326
-                        'rows'                => '5',
327
-                        'shortcodes_required' => ['[TICKET_LINE_ITEM_LIST]'],
328
-                    ],
329
-                    'ticket_line_item_pms'          => [
330
-                        'input'               => 'textarea',
331
-                        'label'               => '[TICKET_LINE_ITEM_LIST] <br>' . esc_html__(
332
-                            'Ticket Line Item List with Price Modifiers',
333
-                            'event_espresso'
334
-                        ),
335
-                        'type'                => 'string',
336
-                        'required'            => false,
337
-                        'validation'          => true,
338
-                        'format'              => '%s',
339
-                        'css_class'           => 'large-text',
340
-                        'rows'                => '5',
341
-                        'shortcodes_required' => ['[TICKET_LINE_ITEM_LIST]'],
342
-                    ],
343
-                    'price_modifier_line_item_list' => [
344
-                        'input'               => 'textarea',
345
-                        'label'               => '[PRICE_MODIFIER_LINE_ITEM_LIST]',
346
-                        'type'                => 'string',
347
-                        'required'            => false,
348
-                        'validation'          => true,
349
-                        'format'              => '%s',
350
-                        'css_class'           => 'large-text',
351
-                        'rows'                => '5',
352
-                        'shortcodes_required' => ['[PRICE_MODIFIER_LINE_ITEM_LIST]'],
353
-                    ],
354
-                    'datetime_list'                 => [
355
-                        'input'               => 'textarea',
356
-                        'label'               => '[DATETIME_LIST]',
357
-                        'type'                => 'string',
358
-                        'required'            => false,
359
-                        'validation'          => true,
360
-                        'format'              => '%s',
361
-                        'css_class'           => 'large-text',
362
-                        'rows'                => '5',
363
-                        'shortcodes_required' => ['[DATETIME_LIST]'],
364
-                    ],
365
-                    'attendee_list'                 => [
366
-                        'input'               => 'textarea',
367
-                        'label'               => '[ATTENDEE_LIST]',
368
-                        'type'                => 'string',
369
-                        'required'            => false,
370
-                        'validation'          => true,
371
-                        'format'              => '%s',
372
-                        'css_class'           => 'large-text',
373
-                        'rows'                => '5',
374
-                        'shortcodes_required' => ['[ATTENDEE_LIST]'],
375
-                    ],
376
-                    'tax_line_item_list'            => [
377
-                        'input'               => 'textarea',
378
-                        'label'               => '[TAX_LINE_ITEM_LIST]',
379
-                        'type'                => 'string',
380
-                        'required'            => false,
381
-                        'validation'          => true,
382
-                        'format'              => '%s',
383
-                        'css_class'           => 'large-text',
384
-                        'rows'                => '5',
385
-                        'shortcodes_required' => ['[TAX_LINE_ITEM_LIST]'],
386
-                    ],
387
-                    'additional_line_item_list'     => [
388
-                        'input'               => 'textarea',
389
-                        'label'               => '[ADDITIONAL_LINE_ITEM_LIST]',
390
-                        'type'                => 'string',
391
-                        'required'            => false,
392
-                        'validation'          => true,
393
-                        'format'              => '%s',
394
-                        'css_class'           => 'large-text',
395
-                        'rows'                => '5',
396
-                        'shortcodes_required' => ['[ADDITIONAL_LINE_ITEM_LIST]'],
397
-                    ],
398
-                    'payment_list'                  => [
399
-                        'input'               => 'textarea',
400
-                        'label'               => '[PAYMENT_LIST]',
401
-                        'type'                => 'string',
402
-                        'required'            => false,
403
-                        'validation'          => true,
404
-                        'format'              => '%s',
405
-                        'css_class'           => 'large-text',
406
-                        'rows'                => '5',
407
-                        'shortcodes_required' => ['[PAYMENT_LIST_*]'],
408
-                    ],
409
-                ],
410
-            ],
411
-        ];
412
-    }
413
-
414
-
415
-    /**
416
-     * @see   definition of this method in parent
417
-     * @since 4.5.0
418
-     */
419
-    protected function _set_default_message_types()
420
-    {
421
-        $this->_default_message_types = ['receipt', 'invoice'];
422
-    }
423
-
424
-
425
-    /**
426
-     * @see   definition of this method in parent
427
-     * @since 4.5.0
428
-     */
429
-    protected function _set_valid_message_types()
430
-    {
431
-        $this->_valid_message_types = ['receipt', 'invoice'];
432
-    }
433
-
434
-
435
-    /**
436
-     * Displays the message in the browser.
437
-     *
438
-     * @return void.
439
-     * @since 4.5.0
440
-     */
441
-    protected function _send_message()
442
-    {
443
-        $this->_template_args = [
444
-            'page_title' => $this->_subject,
445
-            'base_css'   => $this->get_variation(
446
-                $this->_tmp_pack,
447
-                $this->_incoming_message_type->name,
448
-                true,
449
-                'base',
450
-                $this->_variation
451
-            ),
452
-            'print_css'  => $this->get_variation(
453
-                $this->_tmp_pack,
454
-                $this->_incoming_message_type->name,
455
-                true,
456
-                'print',
457
-                $this->_variation
458
-            ),
459
-            'main_css'   => $this->get_variation(
460
-                $this->_tmp_pack,
461
-                $this->_incoming_message_type->name,
462
-                true,
463
-                'main',
464
-                $this->_variation
465
-            ),
466
-            'main_body' => wpautop(
467
-                apply_filters(
468
-                    'FHEE__EE_Html_messenger___send_message__main_body',
469
-                    (string) $this->_content,
470
-                    (string) $this->_content,
471
-                    $this->_incoming_message_type
472
-                ),
473
-                false
474
-            ),
475
-        ];
476
-        $this->_deregister_wp_hooks();
477
-        add_action('wp_enqueue_scripts', [$this, 'enqueue_scripts_styles']);
478
-        echo ($this->_get_main_template());
479
-        exit();
480
-    }
481
-
482
-
483
-    /**
484
-     * The purpose of this function is to de register all actions hooked into wp_head and wp_footer so that it doesn't
485
-     * interfere with our templates.  If users want to add any custom styles or scripts they must use the
486
-     * AHEE__EE_Html_messenger__enqueue_scripts_styles hook.
487
-     *
488
-     * @return void
489
-     * @since 4.5.0
490
-     */
491
-    protected function _deregister_wp_hooks()
492
-    {
493
-        remove_all_actions('wp_head');
494
-        remove_all_actions('wp_footer');
495
-        remove_all_actions('wp_print_footer_scripts');
496
-        remove_all_actions('wp_enqueue_scripts');
497
-        global $wp_scripts, $wp_styles;
498
-        $wp_scripts = $wp_styles = [];
499
-        // just add back in wp_enqueue_scripts and wp_print_footer_scripts cause that's all we want to load.
500
-        add_action('wp_footer', 'wp_print_footer_scripts');
501
-        add_action('wp_print_footer_scripts', '_wp_footer_scripts');
502
-        add_action('wp_head', 'wp_enqueue_scripts');
503
-    }
504
-
505
-
506
-    /**
507
-     * Overwrite parent _get_main_template for display_html purposes.
508
-     *
509
-     * @param bool $preview
510
-     * @return string
511
-     * @since  4.5.0
512
-     */
513
-    protected function _get_main_template($preview = false): string
514
-    {
515
-        $wrapper_template = $this->_tmp_pack->get_wrapper($this->name);
516
-        // include message type as a template arg
517
-        $this->_template_args['message_type'] = $this->_incoming_message_type;
518
-        return EEH_Template::display_template($wrapper_template, $this->_template_args, true);
519
-    }
520
-
521
-
522
-    /**
523
-     * @return void
524
-     */
525
-    protected function _preview()
526
-    {
527
-        $this->_send_message();
528
-    }
529
-
530
-
531
-    protected function _set_admin_settings_fields()
532
-    {
533
-    }
534
-
535
-
536
-    /**
537
-     * add the "powered by EE" credit link to the HTML receipt and invoice
538
-     *
539
-     * @param string|null     $content
540
-     * @param string|null     $content_again
541
-     * @param EE_message_type $incoming_message_type
542
-     * @return string
543
-     */
544
-    public function add_powered_by_credit_link_to_receipt_and_invoice(
545
-        ?string $content,
546
-        ?string $content_again,
547
-        EE_message_type $incoming_message_type
548
-    ): string {
549
-        if (
550
-            ($incoming_message_type->name === 'invoice' || $incoming_message_type->name === 'receipt')
551
-            && apply_filters('FHEE_EE_Html_messenger__add_powered_by_credit_link_to_receipt_and_invoice', true)
552
-        ) {
553
-            $content .= EEH_Template::powered_by_event_espresso(
554
-                'aln-cntr',
555
-                '',
556
-                ['utm_content' => 'messages_system']
557
-            ) . EEH_HTML::div(EEH_HTML::p('&nbsp;'));
558
-        }
559
-        return $content;
560
-    }
15
+	/**
16
+	 * The following are the properties that this messenger requires for displaying the html
17
+	 */
18
+	/**
19
+	 * This is the html body generated by the template via the message type.
20
+	 *
21
+	 * @var string
22
+	 */
23
+	protected $_content = '';
24
+
25
+	/**
26
+	 * This is for the page title that gets displayed.  (Why use "subject"?  Because the "title" tag in html is
27
+	 * equivalent to the "subject" of the page.
28
+	 *
29
+	 * @var string
30
+	 */
31
+	protected $_subject = '';
32
+
33
+
34
+	/**
35
+	 * EE_Html_messenger constructor.
36
+	 */
37
+	public function __construct()
38
+	{
39
+		// set properties
40
+		$this->name                = 'html';
41
+		$this->description         = esc_html__(
42
+			'This messenger outputs a message to a browser for display.',
43
+			'event_espresso'
44
+		);
45
+		$this->label               = [
46
+			'singular' => esc_html__('html', 'event_espresso'),
47
+			'plural'   => esc_html__('html', 'event_espresso'),
48
+		];
49
+		$this->activate_on_install = true;
50
+		// add the "powered by EE" credit link to the HTML receipt and invoice
51
+		add_filter(
52
+			'FHEE__EE_Html_messenger___send_message__main_body',
53
+			[$this, 'add_powered_by_credit_link_to_receipt_and_invoice'],
54
+			10,
55
+			3
56
+		);
57
+		parent::__construct();
58
+	}
59
+
60
+
61
+	/**
62
+	 * HTML Messenger desires execution immediately.
63
+	 *
64
+	 * @return bool
65
+	 * @since  4.9.0
66
+	 * @see    parent::send_now() for documentation.
67
+	 */
68
+	public function send_now(): bool
69
+	{
70
+		return true;
71
+	}
72
+
73
+
74
+	/**
75
+	 * HTML Messenger allows an empty to field.
76
+	 *
77
+	 * @return bool
78
+	 * @since  4.9.0
79
+	 * @see    parent::allow_empty_to_field() for documentation
80
+	 */
81
+	public function allow_empty_to_field(): bool
82
+	{
83
+		return true;
84
+	}
85
+
86
+
87
+	/**
88
+	 * @see abstract declaration in EE_messenger for details.
89
+	 */
90
+	protected function _set_admin_pages()
91
+	{
92
+		$this->admin_registered_pages = ['events_edit' => true];
93
+	}
94
+
95
+
96
+	/**
97
+	 * @see abstract declaration in EE_messenger for details.
98
+	 */
99
+	protected function _set_valid_shortcodes()
100
+	{
101
+		$this->_valid_shortcodes = [];
102
+	}
103
+
104
+
105
+	/**
106
+	 * @see abstract declaration in EE_messenger for details.
107
+	 */
108
+	protected function _set_validator_config()
109
+	{
110
+		$this->_validator_config = [
111
+			'subject'                       => [
112
+				'shortcodes' => ['organization', 'primary_registration_details', 'email', 'transaction'],
113
+			],
114
+			'content'                       => [
115
+				'shortcodes' => [
116
+					'organization',
117
+					'primary_registration_list',
118
+					'primary_registration_details',
119
+					'email',
120
+					'transaction',
121
+					'event_list',
122
+					'payment_list',
123
+					'venue',
124
+					'line_item_list',
125
+					'messenger',
126
+					'ticket_list',
127
+				],
128
+			],
129
+			'event_list'                    => [
130
+				'shortcodes' => [
131
+					'event',
132
+					'ticket_list',
133
+					'venue',
134
+					'primary_registration_details',
135
+					'primary_registration_list',
136
+					'event_author',
137
+				],
138
+				'required'   => ['[EVENT_LIST]'],
139
+			],
140
+			'ticket_list'                   => [
141
+				'shortcodes' => [
142
+					'attendee_list',
143
+					'ticket',
144
+					'datetime_list',
145
+					'primary_registration_details',
146
+					'line_item_list',
147
+					'venue',
148
+				],
149
+				'required'   => ['[TICKET_LIST]'],
150
+			],
151
+			'ticket_line_item_no_pms'       => [
152
+				'shortcodes' => ['line_item', 'ticket'],
153
+				'required'   => ['[TICKET_LINE_ITEM_LIST]'],
154
+			],
155
+			'ticket_line_item_pms'          => [
156
+				'shortcodes' => ['line_item', 'ticket', 'line_item_list'],
157
+				'required'   => ['[TICKET_LINE_ITEM_LIST]'],
158
+			],
159
+			'price_modifier_line_item_list' => [
160
+				'shortcodes' => ['line_item'],
161
+				'required'   => ['[PRICE_MODIFIER_LINE_ITEM_LIST]'],
162
+			],
163
+			'datetime_list'                 => [
164
+				'shortcodes' => ['datetime'],
165
+				'required'   => ['[DATETIME_LIST]'],
166
+			],
167
+			'attendee_list'                 => [
168
+				'shortcodes' => ['attendee'],
169
+				'required'   => ['[ATTENDEE_LIST]'],
170
+			],
171
+			'tax_line_item_list'            => [
172
+				'shortcodes' => ['line_item'],
173
+				'required'   => ['[TAX_LINE_ITEM_LIST]'],
174
+			],
175
+			'additional_line_item_list'     => [
176
+				'shortcodes' => ['line_item'],
177
+				'required'   => ['[ADDITIONAL_LINE_ITEM_LIST]'],
178
+			],
179
+			'payment_list'                  => [
180
+				'shortcodes' => ['payment'],
181
+				'required'   => ['[PAYMENT_LIST_*]'],
182
+			],
183
+		];
184
+	}
185
+
186
+
187
+	/**
188
+	 * This is a method called from EE_messages when this messenger is a generating messenger and the sending messenger
189
+	 * is a different messenger.  Child messengers can set hooks for the sending messenger to callback on if necessary
190
+	 * (i.e. swap out css files or something else).
191
+	 *
192
+	 * @param string $sending_messenger_name the name of the sending messenger so we only set the hooks needed.
193
+	 * @return void
194
+	 * @since 4.5.0
195
+	 */
196
+	public function do_secondary_messenger_hooks($sending_messenger_name)
197
+	{
198
+		if ($sending_messenger_name === 'pdf') {
199
+			add_filter('EE_messenger__get_variation__variation', [$this, 'add_html_css'], 10, 8);
200
+		}
201
+	}
202
+
203
+
204
+	/**
205
+	 * @param                            $variation_path
206
+	 * @param EE_Messages_Template_Pack  $template_pack
207
+	 * @param                            $messenger_name
208
+	 * @param                            $message_type_name
209
+	 * @param                            $url
210
+	 * @param                            $type
211
+	 * @param                            $variation
212
+	 * @param                            $skip_filters
213
+	 * @return string
214
+	 */
215
+	public function add_html_css(
216
+		$variation_path,
217
+		EE_Messages_Template_Pack $template_pack,
218
+		$messenger_name,
219
+		$message_type_name,
220
+		$url,
221
+		$type,
222
+		$variation,
223
+		$skip_filters
224
+	): string {
225
+		return $template_pack->get_variation(
226
+			$this->name,
227
+			$message_type_name,
228
+			$type,
229
+			$variation,
230
+			$url,
231
+			'.css',
232
+			$skip_filters
233
+		);
234
+	}
235
+
236
+
237
+	/**
238
+	 * Takes care of enqueuing any necessary scripts or styles for the page.  A do_action() so message types using this
239
+	 * messenger can add their own js.
240
+	 *
241
+	 * @return void.
242
+	 */
243
+	public function enqueue_scripts_styles()
244
+	{
245
+		parent::enqueue_scripts_styles();
246
+		do_action('AHEE__EE_Html_messenger__enqueue_scripts_styles');
247
+	}
248
+
249
+
250
+	/**
251
+	 * _set_template_fields
252
+	 * This sets up the fields that a messenger requires for the message to go out.
253
+	 *
254
+	 * @access  protected
255
+	 * @return void
256
+	 */
257
+	protected function _set_template_fields()
258
+	{
259
+		// any extra template fields that are NOT used by the messenger
260
+		// but will get used by a messenger field for shortcode replacement
261
+		// get added to the 'extra' key in an associated array
262
+		// indexed by the messenger field they relate to.
263
+		// This is important for the Messages_admin to know what fields to display to the user.
264
+		// Also, notice that the "values" are equal to the field type
265
+		// that messages admin will use to know what kind of field to display.
266
+		// The values ALSO have one index labeled "shortcode".
267
+		// The values in that array indicate which ACTUAL SHORTCODE (i.e. [SHORTCODE])
268
+		// is required in order for this extra field to be displayed.
269
+		//  If the required shortcode isn't part of the shortcodes array
270
+		// then the field is not needed and will not be displayed/parsed.
271
+		$this->_template_fields = [
272
+			'subject' => [
273
+				'input'      => 'text',
274
+				'label'      => esc_html__('Page Title', 'event_espresso'),
275
+				'type'       => 'string',
276
+				'required'   => true,
277
+				'validation' => true,
278
+				'css_class'  => 'large-text',
279
+				'format'     => '%s',
280
+			],
281
+			'content' => '',
282
+			// left empty b/c it is in the "extra array" but messenger still needs needs to know this is a field.
283
+			'extra'   => [
284
+				'content' => [
285
+					'main'                          => [
286
+						'input'      => 'wp_editor',
287
+						'label'      => esc_html__('Main Content', 'event_espresso'),
288
+						'type'       => 'string',
289
+						'required'   => false,
290
+						'validation' => true,
291
+						'format'     => '%s',
292
+						'rows'       => '15',
293
+					],
294
+					'event_list'                    => [
295
+						'input'               => 'wp_editor',
296
+						'label'               => '[EVENT_LIST]',
297
+						'type'                => 'string',
298
+						'required'            => false,
299
+						'validation'          => true,
300
+						'format'              => '%s',
301
+						'rows'                => '15',
302
+						'shortcodes_required' => ['[EVENT_LIST]'],
303
+					],
304
+					'ticket_list'                   => [
305
+						'input'               => 'textarea',
306
+						'label'               => '[TICKET_LIST]',
307
+						'type'                => 'string',
308
+						'required'            => false,
309
+						'validation'          => true,
310
+						'format'              => '%s',
311
+						'css_class'           => 'large-text',
312
+						'rows'                => '10',
313
+						'shortcodes_required' => ['[TICKET_LIST]'],
314
+					],
315
+					'ticket_line_item_no_pms'       => [
316
+						'input'               => 'textarea',
317
+						'label'               => '[TICKET_LINE_ITEM_LIST] <br>' . esc_html__(
318
+							'Ticket Line Item List with no Price Modifiers',
319
+							'event_espresso'
320
+						),
321
+						'type'                => 'string',
322
+						'required'            => false,
323
+						'validation'          => true,
324
+						'format'              => '%s',
325
+						'css_class'           => 'large-text',
326
+						'rows'                => '5',
327
+						'shortcodes_required' => ['[TICKET_LINE_ITEM_LIST]'],
328
+					],
329
+					'ticket_line_item_pms'          => [
330
+						'input'               => 'textarea',
331
+						'label'               => '[TICKET_LINE_ITEM_LIST] <br>' . esc_html__(
332
+							'Ticket Line Item List with Price Modifiers',
333
+							'event_espresso'
334
+						),
335
+						'type'                => 'string',
336
+						'required'            => false,
337
+						'validation'          => true,
338
+						'format'              => '%s',
339
+						'css_class'           => 'large-text',
340
+						'rows'                => '5',
341
+						'shortcodes_required' => ['[TICKET_LINE_ITEM_LIST]'],
342
+					],
343
+					'price_modifier_line_item_list' => [
344
+						'input'               => 'textarea',
345
+						'label'               => '[PRICE_MODIFIER_LINE_ITEM_LIST]',
346
+						'type'                => 'string',
347
+						'required'            => false,
348
+						'validation'          => true,
349
+						'format'              => '%s',
350
+						'css_class'           => 'large-text',
351
+						'rows'                => '5',
352
+						'shortcodes_required' => ['[PRICE_MODIFIER_LINE_ITEM_LIST]'],
353
+					],
354
+					'datetime_list'                 => [
355
+						'input'               => 'textarea',
356
+						'label'               => '[DATETIME_LIST]',
357
+						'type'                => 'string',
358
+						'required'            => false,
359
+						'validation'          => true,
360
+						'format'              => '%s',
361
+						'css_class'           => 'large-text',
362
+						'rows'                => '5',
363
+						'shortcodes_required' => ['[DATETIME_LIST]'],
364
+					],
365
+					'attendee_list'                 => [
366
+						'input'               => 'textarea',
367
+						'label'               => '[ATTENDEE_LIST]',
368
+						'type'                => 'string',
369
+						'required'            => false,
370
+						'validation'          => true,
371
+						'format'              => '%s',
372
+						'css_class'           => 'large-text',
373
+						'rows'                => '5',
374
+						'shortcodes_required' => ['[ATTENDEE_LIST]'],
375
+					],
376
+					'tax_line_item_list'            => [
377
+						'input'               => 'textarea',
378
+						'label'               => '[TAX_LINE_ITEM_LIST]',
379
+						'type'                => 'string',
380
+						'required'            => false,
381
+						'validation'          => true,
382
+						'format'              => '%s',
383
+						'css_class'           => 'large-text',
384
+						'rows'                => '5',
385
+						'shortcodes_required' => ['[TAX_LINE_ITEM_LIST]'],
386
+					],
387
+					'additional_line_item_list'     => [
388
+						'input'               => 'textarea',
389
+						'label'               => '[ADDITIONAL_LINE_ITEM_LIST]',
390
+						'type'                => 'string',
391
+						'required'            => false,
392
+						'validation'          => true,
393
+						'format'              => '%s',
394
+						'css_class'           => 'large-text',
395
+						'rows'                => '5',
396
+						'shortcodes_required' => ['[ADDITIONAL_LINE_ITEM_LIST]'],
397
+					],
398
+					'payment_list'                  => [
399
+						'input'               => 'textarea',
400
+						'label'               => '[PAYMENT_LIST]',
401
+						'type'                => 'string',
402
+						'required'            => false,
403
+						'validation'          => true,
404
+						'format'              => '%s',
405
+						'css_class'           => 'large-text',
406
+						'rows'                => '5',
407
+						'shortcodes_required' => ['[PAYMENT_LIST_*]'],
408
+					],
409
+				],
410
+			],
411
+		];
412
+	}
413
+
414
+
415
+	/**
416
+	 * @see   definition of this method in parent
417
+	 * @since 4.5.0
418
+	 */
419
+	protected function _set_default_message_types()
420
+	{
421
+		$this->_default_message_types = ['receipt', 'invoice'];
422
+	}
423
+
424
+
425
+	/**
426
+	 * @see   definition of this method in parent
427
+	 * @since 4.5.0
428
+	 */
429
+	protected function _set_valid_message_types()
430
+	{
431
+		$this->_valid_message_types = ['receipt', 'invoice'];
432
+	}
433
+
434
+
435
+	/**
436
+	 * Displays the message in the browser.
437
+	 *
438
+	 * @return void.
439
+	 * @since 4.5.0
440
+	 */
441
+	protected function _send_message()
442
+	{
443
+		$this->_template_args = [
444
+			'page_title' => $this->_subject,
445
+			'base_css'   => $this->get_variation(
446
+				$this->_tmp_pack,
447
+				$this->_incoming_message_type->name,
448
+				true,
449
+				'base',
450
+				$this->_variation
451
+			),
452
+			'print_css'  => $this->get_variation(
453
+				$this->_tmp_pack,
454
+				$this->_incoming_message_type->name,
455
+				true,
456
+				'print',
457
+				$this->_variation
458
+			),
459
+			'main_css'   => $this->get_variation(
460
+				$this->_tmp_pack,
461
+				$this->_incoming_message_type->name,
462
+				true,
463
+				'main',
464
+				$this->_variation
465
+			),
466
+			'main_body' => wpautop(
467
+				apply_filters(
468
+					'FHEE__EE_Html_messenger___send_message__main_body',
469
+					(string) $this->_content,
470
+					(string) $this->_content,
471
+					$this->_incoming_message_type
472
+				),
473
+				false
474
+			),
475
+		];
476
+		$this->_deregister_wp_hooks();
477
+		add_action('wp_enqueue_scripts', [$this, 'enqueue_scripts_styles']);
478
+		echo ($this->_get_main_template());
479
+		exit();
480
+	}
481
+
482
+
483
+	/**
484
+	 * The purpose of this function is to de register all actions hooked into wp_head and wp_footer so that it doesn't
485
+	 * interfere with our templates.  If users want to add any custom styles or scripts they must use the
486
+	 * AHEE__EE_Html_messenger__enqueue_scripts_styles hook.
487
+	 *
488
+	 * @return void
489
+	 * @since 4.5.0
490
+	 */
491
+	protected function _deregister_wp_hooks()
492
+	{
493
+		remove_all_actions('wp_head');
494
+		remove_all_actions('wp_footer');
495
+		remove_all_actions('wp_print_footer_scripts');
496
+		remove_all_actions('wp_enqueue_scripts');
497
+		global $wp_scripts, $wp_styles;
498
+		$wp_scripts = $wp_styles = [];
499
+		// just add back in wp_enqueue_scripts and wp_print_footer_scripts cause that's all we want to load.
500
+		add_action('wp_footer', 'wp_print_footer_scripts');
501
+		add_action('wp_print_footer_scripts', '_wp_footer_scripts');
502
+		add_action('wp_head', 'wp_enqueue_scripts');
503
+	}
504
+
505
+
506
+	/**
507
+	 * Overwrite parent _get_main_template for display_html purposes.
508
+	 *
509
+	 * @param bool $preview
510
+	 * @return string
511
+	 * @since  4.5.0
512
+	 */
513
+	protected function _get_main_template($preview = false): string
514
+	{
515
+		$wrapper_template = $this->_tmp_pack->get_wrapper($this->name);
516
+		// include message type as a template arg
517
+		$this->_template_args['message_type'] = $this->_incoming_message_type;
518
+		return EEH_Template::display_template($wrapper_template, $this->_template_args, true);
519
+	}
520
+
521
+
522
+	/**
523
+	 * @return void
524
+	 */
525
+	protected function _preview()
526
+	{
527
+		$this->_send_message();
528
+	}
529
+
530
+
531
+	protected function _set_admin_settings_fields()
532
+	{
533
+	}
534
+
535
+
536
+	/**
537
+	 * add the "powered by EE" credit link to the HTML receipt and invoice
538
+	 *
539
+	 * @param string|null     $content
540
+	 * @param string|null     $content_again
541
+	 * @param EE_message_type $incoming_message_type
542
+	 * @return string
543
+	 */
544
+	public function add_powered_by_credit_link_to_receipt_and_invoice(
545
+		?string $content,
546
+		?string $content_again,
547
+		EE_message_type $incoming_message_type
548
+	): string {
549
+		if (
550
+			($incoming_message_type->name === 'invoice' || $incoming_message_type->name === 'receipt')
551
+			&& apply_filters('FHEE_EE_Html_messenger__add_powered_by_credit_link_to_receipt_and_invoice', true)
552
+		) {
553
+			$content .= EEH_Template::powered_by_event_espresso(
554
+				'aln-cntr',
555
+				'',
556
+				['utm_content' => 'messages_system']
557
+			) . EEH_HTML::div(EEH_HTML::p('&nbsp;'));
558
+		}
559
+		return $content;
560
+	}
561 561
 }
Please login to merge, or discard this patch.
modules/batch/EED_Batch.module.php 1 patch
Indentation   +434 added lines, -434 removed lines patch added patch discarded remove patch
@@ -29,438 +29,438 @@
 block discarded – undo
29 29
  */
30 30
 class EED_Batch extends EED_Module
31 31
 {
32
-    public const PAGE_SLUG = 'espresso_batch';
33
-
34
-    /**
35
-     * Possibly value for $_REQUEST[ 'batch' ]. Indicates to run a job that
36
-     * processes data only
37
-     */
38
-    const batch_job = 'job';
39
-
40
-    /**
41
-     * Possibly value for $_REQUEST[ 'batch' ]. Indicates to run a job that
42
-     * produces a file for download
43
-     */
44
-    const batch_file_job = 'file';
45
-
46
-    /**
47
-     * Possibly value for $_REQUEST[ 'batch' ]. Indicates this request is NOT
48
-     * for a batch job. It's the same as not providing the $_REQUEST[ 'batch' ]
49
-     * at all
50
-     */
51
-    const batch_not_job = 'none';
52
-
53
-    /**
54
-     *
55
-     * @var string 'file', or 'job', or false to indicate its not a batch request at all
56
-     */
57
-    protected $_batch_request_type = '';
58
-
59
-    /**
60
-     * Because we want to use the response in both the localized JS and in the body
61
-     * we need to make this response available between method calls
62
-     *
63
-     * @var JobStepResponse|null
64
-     */
65
-    protected $_job_step_response = null;
66
-
67
-    /**
68
-     * @var LoaderInterface|null
69
-     */
70
-    protected $loader = null;
71
-
72
-
73
-    /**
74
-     * Gets the batch instance
75
-     *
76
-     * @return  EED_Module|EED_Batch
77
-     * @throws EE_Error
78
-     * @throws ReflectionException
79
-     */
80
-    public static function instance(): EED_Batch
81
-    {
82
-        return parent::get_instance(__CLASS__);
83
-    }
84
-
85
-
86
-    /**
87
-     * Sets hooks to enable batch jobs on the frontend. Disabled by default
88
-     * because it's an attack vector and there are currently no implementations
89
-     *
90
-     * @throws EE_Error
91
-     * @throws ReflectionException
92
-     */
93
-    public static function set_hooks()
94
-    {
95
-        // because this is a possible attack vector, let's have this disabled until
96
-        // we at least have a real use for it on the frontend
97
-        if (apply_filters('FHEE__EED_Batch__set_hooks__enable_frontend_batch', false)) {
98
-            add_action('wp_enqueue_scripts', [self::instance(), 'enqueue_scripts']);
99
-            add_filter('template_include', [self::instance(), 'override_template'], 99);
100
-        }
101
-    }
102
-
103
-
104
-    /**
105
-     * Initializes some hooks for the admin in order to run batch jobs
106
-     *
107
-     * @throws EE_Error
108
-     * @throws ReflectionException
109
-     */
110
-    public static function set_hooks_admin()
111
-    {
112
-        add_action('admin_menu', [self::instance(), 'register_admin_pages']);
113
-        add_action('admin_enqueue_scripts', [self::instance(), 'enqueue_scripts']);
114
-
115
-        // ajax
116
-        add_action('wp_ajax_espresso_batch_continue', [self::instance(), 'continueBatchJob']);
117
-        add_action('wp_ajax_espresso_batch_advance', [self::instance(), 'advanceBatchJob']);
118
-        add_action('wp_ajax_espresso_batch_cleanup', [self::instance(), 'cleanupBatchJob']);
119
-        add_action('wp_ajax_nopriv_espresso_batch_continue', [self::instance(), 'continueBatchJob']);
120
-        add_action('wp_ajax_nopriv_espresso_batch_advance', [self::instance(), 'advanceBatchJob']);
121
-        add_action('wp_ajax_nopriv_espresso_batch_cleanup', [self::instance(), 'cleanupBatchJob']);
122
-    }
123
-
124
-
125
-    /**
126
-     * @return LoaderInterface
127
-     * @throws InvalidArgumentException
128
-     * @throws InvalidDataTypeException
129
-     * @throws InvalidInterfaceException
130
-     * @since 4.9.80.p
131
-     */
132
-    protected function getLoader(): LoaderInterface
133
-    {
134
-        if (! $this->loader instanceof LoaderInterface) {
135
-            $this->loader = LoaderFactory::getLoader();
136
-        }
137
-        return $this->loader;
138
-    }
139
-
140
-
141
-    /**
142
-     * Enqueues batch scripts on the frontend or admin, and creates a job
143
-     */
144
-    public function enqueue_scripts()
145
-    {
146
-        $request = EED_Batch::getRequest();
147
-        if (
148
-            $request->getRequestParam(EED_Batch::PAGE_SLUG)
149
-            || $request->getRequestParam('page') === EED_Batch::PAGE_SLUG
150
-        ) {
151
-            if (
152
-                ! $request->requestParamIsSet('default_nonce')
153
-                || ! wp_verify_nonce($request->getRequestParam('default_nonce'), 'default_nonce')
154
-            ) {
155
-                wp_die(
156
-                    esc_html__(
157
-                        'The link you clicked to start the batch job has expired. Please go back and refresh the previous page.',
158
-                        'event_espresso'
159
-                    )
160
-                );
161
-            }
162
-            switch ($this->batch_request_type()) {
163
-                case self::batch_job:
164
-                    $this->enqueue_scripts_styles_batch_create();
165
-                    break;
166
-                case self::batch_file_job:
167
-                    $this->enqueue_scripts_styles_batch_file_create();
168
-                    break;
169
-            }
170
-        }
171
-    }
172
-
173
-
174
-    /**
175
-     * Create a batch job, enqueues a script to run it, and localizes some data for it
176
-     */
177
-    public function enqueue_scripts_styles_batch_create()
178
-    {
179
-        $job_response = $this->_enqueue_batch_job_scripts_and_styles_and_start_job();
180
-        wp_enqueue_script(
181
-            'batch_runner_init',
182
-            BATCH_URL . 'assets/batch_runner_init.js',
183
-            ['batch_runner'],
184
-            date('Y-m-d-H:i', time()),
185
-            true
186
-        );
187
-        wp_localize_script('batch_runner_init', 'ee_job_response', $job_response->to_array());
188
-        wp_localize_script('batch_runner_init', 'eei18n', EE_Registry::$i18n_js_strings);
189
-
190
-        $return_url = EED_Batch::getRequest()->getRequestParam('return_url', '', DataType::URL);
191
-        if ($return_url) {
192
-            wp_localize_script(
193
-                'batch_runner_init',
194
-                'ee_job_i18n',
195
-                [
196
-                    'return_url'                => $return_url,
197
-                    'auto_redirect_on_complete' => EED_Batch::getRequest()->getRequestParam(
198
-                        'auto_redirect_on_complete'
199
-                    ),
200
-                    'user_message'              => EED_Batch::getRequest()->getRequestParam('assessment_notice')
201
-                        ?: EED_Batch::getRequest()->getRequestParam('job_start_notice'),
202
-                ]
203
-            );
204
-        }
205
-    }
206
-
207
-
208
-    /**
209
-     * Creates a batch job which will download a file, enqueues a script to run the job, and localizes some data for it
210
-     */
211
-    public function enqueue_scripts_styles_batch_file_create()
212
-    {
213
-        // creates a job based on the request variable
214
-        $job_response = $this->_enqueue_batch_job_scripts_and_styles_and_start_job();
215
-        wp_enqueue_script(
216
-            'batch_file_runner_init',
217
-            BATCH_URL . 'assets/batch_file_runner_init.js',
218
-            ['batch_runner'],
219
-            date('Y-m-d-H:i', time()),
220
-            true
221
-        );
222
-        wp_localize_script('batch_file_runner_init', 'ee_job_response', $job_response->to_array());
223
-        wp_localize_script('batch_file_runner_init', 'eei18n', EE_Registry::$i18n_js_strings);
224
-
225
-        $return_url = EED_Batch::getRequest()->getRequestParam('return_url', '', DataType::URL);
226
-        if ($return_url) {
227
-            wp_localize_script(
228
-                'batch_file_runner_init',
229
-                'ee_job_i18n',
230
-                ['return_url' => $return_url]
231
-            );
232
-        }
233
-    }
234
-
235
-
236
-    /**
237
-     * Enqueues scripts and styles common to any batch job, and creates
238
-     * a job from the request data, and stores the response in the
239
-     * $this->_job_step_response property
240
-     *
241
-     * @return JobStepResponse
242
-     */
243
-    protected function _enqueue_batch_job_scripts_and_styles_and_start_job(): JobStepResponse
244
-    {
245
-        // just copy the bits of EE admin's eei18n that we need in the JS
246
-        EE_Registry::$i18n_js_strings['batchJobError'] = __(
247
-            'An error occurred and the job has been stopped. Please refresh the page to try again.',
248
-            'event_espresso'
249
-        );
250
-        EE_Registry::$i18n_js_strings['is_admin']      = is_admin();
251
-        wp_enqueue_style(
252
-            EspressoLegacyAdminAssetManager::CSS_HANDLE_EE_ADMIN,
253
-            EE_ADMIN_URL . 'assets/ee-admin-page.css',
254
-            ['espresso_admin_base'],
255
-            EVENT_ESPRESSO_VERSION
256
-        );
257
-        wp_enqueue_style(
258
-            'batch_runner',
259
-            BATCH_URL . 'assets/batch_runner.css',
260
-            [EspressoLegacyAdminAssetManager::CSS_HANDLE_EE_ADMIN],
261
-            date('Y-m-d-H:i', time())
262
-        );
263
-        wp_register_script(
264
-            'progress_bar',
265
-            EE_PLUGIN_DIR_URL . 'core/libraries/batch/Assets/progress_bar.js',
266
-            ['jquery'],
267
-            date('Y-m-d-H:i', time()),
268
-            true
269
-        );
270
-        wp_enqueue_style(
271
-            'progress_bar',
272
-            EE_PLUGIN_DIR_URL . 'core/libraries/batch/Assets/progress_bar.css',
273
-            [],
274
-            date('Y-m-d-H:i', time())
275
-        );
276
-        wp_enqueue_script(
277
-            'batch_runner',
278
-            EE_PLUGIN_DIR_URL . 'core/libraries/batch/Assets/batch_runner.js',
279
-            ['progress_bar', CoreAssetManager::JS_HANDLE_CORE],
280
-            date('Y-m-d-H:i', time()),
281
-            true
282
-        );
283
-        /** @var BatchRequestProcessor $batch_runner */
284
-        $batch_runner = $this->getLoader()->getShared('EventEspresso\core\libraries\batch\BatchRequestProcessor');
285
-        // eg 'EventEspresso\core\libraries\batch\JobHandlers\RegistrationsReport'
286
-        // remember the response for later. We need it to display the page body
287
-        $this->_job_step_response = $batch_runner->createJob();
288
-        return $this->_job_step_response;
289
-    }
290
-
291
-
292
-    /**
293
-     * If we are doing a frontend batch job, this makes it so WP shows our template's HTML
294
-     *
295
-     * @param string $template
296
-     * @return string
297
-     */
298
-    public function override_template(string $template): string
299
-    {
300
-        $request = EED_Batch::getRequest();
301
-        if ($request->requestParamIsSet('batch') && $request->requestParamIsSet(EED_Batch::PAGE_SLUG)) {
302
-            return EE_MODULES . 'batch/templates/batch_frontend_wrapper.template.php';
303
-        }
304
-        return $template;
305
-    }
306
-
307
-
308
-    /**
309
-     * Adds an admin page which doesn't appear in the admin menu
310
-     *
311
-     * @throws EE_Error
312
-     * @throws ReflectionException
313
-     */
314
-    public function register_admin_pages()
315
-    {
316
-        add_submenu_page(
317
-            '',
318
-            // parent slug. we don't want this to actually appear in the menu
319
-            esc_html__('Batch Job', 'event_espresso'),
320
-            // page title
321
-            'n/a',
322
-            // menu title
323
-            'read',
324
-            // we want this page to actually be accessible to anyone,
325
-            EED_Batch::PAGE_SLUG,
326
-            // menu slug
327
-            [self::instance(), 'show_admin_page']
328
-        );
329
-    }
330
-
331
-
332
-    /**
333
-     * Renders the admin page, after most of the work was already done during enqueuing scripts
334
-     * of creating the job and localizing some data
335
-     */
336
-    public function show_admin_page()
337
-    {
338
-        echo EEH_Template::locate_template(
339
-            EE_MODULES . 'batch/templates/batch_wrapper.template.php',
340
-            [
341
-                'batch_request_type'        => $this->batch_request_type(),
342
-                'auto_redirect_on_complete' => EED_Batch::getRequest()->getRequestParam('auto_redirect_on_complete'),
343
-                'user_message'              => EED_Batch::getRequest()->getRequestParam('assessment_notice')
344
-                    ?: EED_Batch::getRequest()->getRequestParam('job_start_notice'),
345
-            ]
346
-        );
347
-    }
348
-
349
-
350
-    private function runBatchRunnerJob(string $job)
351
-    {
352
-        $job_id = EED_Batch::getRequest()->getRequestParam('job_id');
353
-        /** @var BatchRequestProcessor $batch_runner */
354
-        $batch_runner = $this->getLoader()->getShared('EventEspresso\core\libraries\batch\BatchRequestProcessor');
355
-        $job_response = $batch_runner->{$job}($job_id);
356
-        $this->_return_json($job_response->to_array());
357
-    }
358
-
359
-
360
-    /**
361
-     * Receives ajax calls for continuing a job
362
-     */
363
-    public function continueBatchJob()
364
-    {
365
-        $this->runBatchRunnerJob('continueJob');
366
-    }
367
-
368
-
369
-    /**
370
-     * Receives ajax calls for continuing a job
371
-     */
372
-    public function advanceBatchJob()
373
-    {
374
-        $this->runBatchRunnerJob('advanceJob');
375
-    }
376
-
377
-
378
-    /**
379
-     * Receives the ajax call to cleanup a job
380
-     *
381
-     * @return void
382
-     */
383
-    public function cleanupBatchJob()
384
-    {
385
-        $this->runBatchRunnerJob('cleanupJob');
386
-    }
387
-
388
-
389
-    /**
390
-     * Returns a json response
391
-     *
392
-     * @param array $data The data we want to send echo via in the JSON response's "data" element
393
-     *
394
-     * The returned json object is created from an array in the following format:
395
-     * array(
396
-     *    'notices' => '', // - contains any EE_Error formatted notices
397
-     *    'data' => array() //this can be any key/value pairs that a method returns for later json parsing by the js.
398
-     *    We're also going to include the template args with every package (so js can pick out any specific template
399
-     *    args that might be included in here)
400
-     *    'isEEajax' => true,//indicates this is a response from EE
401
-     * )
402
-     */
403
-    protected function _return_json(array $data)
404
-    {
405
-        $json = [
406
-            'data'     => $data,
407
-            'isEEajax' => true,
408
-            // special flag so any ajax.Success methods in js can identify this return package as a EEajax package.
409
-        ];
410
-
411
-        // make sure there are no php errors or headers_sent.  Then we can set correct json header.
412
-        if (error_get_last() === null || ! headers_sent()) {
413
-            $notices = EE_Error::get_notices(false);
414
-            header('Content-Type: application/json; charset=UTF-8');
415
-            echo wp_json_encode($json + $notices);
416
-            exit();
417
-        }
418
-    }
419
-
420
-
421
-    /**
422
-     * Gets the job step response which was done during the enqueuing of scripts
423
-     *
424
-     * @return JobStepResponse
425
-     */
426
-    public function job_step_response(): JobStepResponse
427
-    {
428
-        return $this->_job_step_response;
429
-    }
430
-
431
-
432
-    /**
433
-     * Gets the batch request type indicated in the current request
434
-     *
435
-     * @return string: EED_Batch::batch_job, EED_Batch::batch_file_job, EED_Batch::batch_not_job
436
-     */
437
-    public function batch_request_type(): string
438
-    {
439
-        if (! $this->_batch_request_type) {
440
-            $request = EED_Batch::getRequest();
441
-            $batch   = $request->getRequestParam('batch');
442
-            switch ($batch) {
443
-                case self::batch_job:
444
-                    $this->_batch_request_type = self::batch_job;
445
-                    break;
446
-                case self::batch_file_job:
447
-                    $this->_batch_request_type = self::batch_file_job;
448
-                    break;
449
-                default:
450
-                    // if we didn't find that it was a batch request, indicate it wasn't
451
-                    $this->_batch_request_type = self::batch_not_job;
452
-            }
453
-        }
454
-        return $this->_batch_request_type;
455
-    }
456
-
457
-
458
-    /**
459
-     * Unnecessary
460
-     *
461
-     * @param WP $WP
462
-     */
463
-    public function run($WP)
464
-    {
465
-    }
32
+	public const PAGE_SLUG = 'espresso_batch';
33
+
34
+	/**
35
+	 * Possibly value for $_REQUEST[ 'batch' ]. Indicates to run a job that
36
+	 * processes data only
37
+	 */
38
+	const batch_job = 'job';
39
+
40
+	/**
41
+	 * Possibly value for $_REQUEST[ 'batch' ]. Indicates to run a job that
42
+	 * produces a file for download
43
+	 */
44
+	const batch_file_job = 'file';
45
+
46
+	/**
47
+	 * Possibly value for $_REQUEST[ 'batch' ]. Indicates this request is NOT
48
+	 * for a batch job. It's the same as not providing the $_REQUEST[ 'batch' ]
49
+	 * at all
50
+	 */
51
+	const batch_not_job = 'none';
52
+
53
+	/**
54
+	 *
55
+	 * @var string 'file', or 'job', or false to indicate its not a batch request at all
56
+	 */
57
+	protected $_batch_request_type = '';
58
+
59
+	/**
60
+	 * Because we want to use the response in both the localized JS and in the body
61
+	 * we need to make this response available between method calls
62
+	 *
63
+	 * @var JobStepResponse|null
64
+	 */
65
+	protected $_job_step_response = null;
66
+
67
+	/**
68
+	 * @var LoaderInterface|null
69
+	 */
70
+	protected $loader = null;
71
+
72
+
73
+	/**
74
+	 * Gets the batch instance
75
+	 *
76
+	 * @return  EED_Module|EED_Batch
77
+	 * @throws EE_Error
78
+	 * @throws ReflectionException
79
+	 */
80
+	public static function instance(): EED_Batch
81
+	{
82
+		return parent::get_instance(__CLASS__);
83
+	}
84
+
85
+
86
+	/**
87
+	 * Sets hooks to enable batch jobs on the frontend. Disabled by default
88
+	 * because it's an attack vector and there are currently no implementations
89
+	 *
90
+	 * @throws EE_Error
91
+	 * @throws ReflectionException
92
+	 */
93
+	public static function set_hooks()
94
+	{
95
+		// because this is a possible attack vector, let's have this disabled until
96
+		// we at least have a real use for it on the frontend
97
+		if (apply_filters('FHEE__EED_Batch__set_hooks__enable_frontend_batch', false)) {
98
+			add_action('wp_enqueue_scripts', [self::instance(), 'enqueue_scripts']);
99
+			add_filter('template_include', [self::instance(), 'override_template'], 99);
100
+		}
101
+	}
102
+
103
+
104
+	/**
105
+	 * Initializes some hooks for the admin in order to run batch jobs
106
+	 *
107
+	 * @throws EE_Error
108
+	 * @throws ReflectionException
109
+	 */
110
+	public static function set_hooks_admin()
111
+	{
112
+		add_action('admin_menu', [self::instance(), 'register_admin_pages']);
113
+		add_action('admin_enqueue_scripts', [self::instance(), 'enqueue_scripts']);
114
+
115
+		// ajax
116
+		add_action('wp_ajax_espresso_batch_continue', [self::instance(), 'continueBatchJob']);
117
+		add_action('wp_ajax_espresso_batch_advance', [self::instance(), 'advanceBatchJob']);
118
+		add_action('wp_ajax_espresso_batch_cleanup', [self::instance(), 'cleanupBatchJob']);
119
+		add_action('wp_ajax_nopriv_espresso_batch_continue', [self::instance(), 'continueBatchJob']);
120
+		add_action('wp_ajax_nopriv_espresso_batch_advance', [self::instance(), 'advanceBatchJob']);
121
+		add_action('wp_ajax_nopriv_espresso_batch_cleanup', [self::instance(), 'cleanupBatchJob']);
122
+	}
123
+
124
+
125
+	/**
126
+	 * @return LoaderInterface
127
+	 * @throws InvalidArgumentException
128
+	 * @throws InvalidDataTypeException
129
+	 * @throws InvalidInterfaceException
130
+	 * @since 4.9.80.p
131
+	 */
132
+	protected function getLoader(): LoaderInterface
133
+	{
134
+		if (! $this->loader instanceof LoaderInterface) {
135
+			$this->loader = LoaderFactory::getLoader();
136
+		}
137
+		return $this->loader;
138
+	}
139
+
140
+
141
+	/**
142
+	 * Enqueues batch scripts on the frontend or admin, and creates a job
143
+	 */
144
+	public function enqueue_scripts()
145
+	{
146
+		$request = EED_Batch::getRequest();
147
+		if (
148
+			$request->getRequestParam(EED_Batch::PAGE_SLUG)
149
+			|| $request->getRequestParam('page') === EED_Batch::PAGE_SLUG
150
+		) {
151
+			if (
152
+				! $request->requestParamIsSet('default_nonce')
153
+				|| ! wp_verify_nonce($request->getRequestParam('default_nonce'), 'default_nonce')
154
+			) {
155
+				wp_die(
156
+					esc_html__(
157
+						'The link you clicked to start the batch job has expired. Please go back and refresh the previous page.',
158
+						'event_espresso'
159
+					)
160
+				);
161
+			}
162
+			switch ($this->batch_request_type()) {
163
+				case self::batch_job:
164
+					$this->enqueue_scripts_styles_batch_create();
165
+					break;
166
+				case self::batch_file_job:
167
+					$this->enqueue_scripts_styles_batch_file_create();
168
+					break;
169
+			}
170
+		}
171
+	}
172
+
173
+
174
+	/**
175
+	 * Create a batch job, enqueues a script to run it, and localizes some data for it
176
+	 */
177
+	public function enqueue_scripts_styles_batch_create()
178
+	{
179
+		$job_response = $this->_enqueue_batch_job_scripts_and_styles_and_start_job();
180
+		wp_enqueue_script(
181
+			'batch_runner_init',
182
+			BATCH_URL . 'assets/batch_runner_init.js',
183
+			['batch_runner'],
184
+			date('Y-m-d-H:i', time()),
185
+			true
186
+		);
187
+		wp_localize_script('batch_runner_init', 'ee_job_response', $job_response->to_array());
188
+		wp_localize_script('batch_runner_init', 'eei18n', EE_Registry::$i18n_js_strings);
189
+
190
+		$return_url = EED_Batch::getRequest()->getRequestParam('return_url', '', DataType::URL);
191
+		if ($return_url) {
192
+			wp_localize_script(
193
+				'batch_runner_init',
194
+				'ee_job_i18n',
195
+				[
196
+					'return_url'                => $return_url,
197
+					'auto_redirect_on_complete' => EED_Batch::getRequest()->getRequestParam(
198
+						'auto_redirect_on_complete'
199
+					),
200
+					'user_message'              => EED_Batch::getRequest()->getRequestParam('assessment_notice')
201
+						?: EED_Batch::getRequest()->getRequestParam('job_start_notice'),
202
+				]
203
+			);
204
+		}
205
+	}
206
+
207
+
208
+	/**
209
+	 * Creates a batch job which will download a file, enqueues a script to run the job, and localizes some data for it
210
+	 */
211
+	public function enqueue_scripts_styles_batch_file_create()
212
+	{
213
+		// creates a job based on the request variable
214
+		$job_response = $this->_enqueue_batch_job_scripts_and_styles_and_start_job();
215
+		wp_enqueue_script(
216
+			'batch_file_runner_init',
217
+			BATCH_URL . 'assets/batch_file_runner_init.js',
218
+			['batch_runner'],
219
+			date('Y-m-d-H:i', time()),
220
+			true
221
+		);
222
+		wp_localize_script('batch_file_runner_init', 'ee_job_response', $job_response->to_array());
223
+		wp_localize_script('batch_file_runner_init', 'eei18n', EE_Registry::$i18n_js_strings);
224
+
225
+		$return_url = EED_Batch::getRequest()->getRequestParam('return_url', '', DataType::URL);
226
+		if ($return_url) {
227
+			wp_localize_script(
228
+				'batch_file_runner_init',
229
+				'ee_job_i18n',
230
+				['return_url' => $return_url]
231
+			);
232
+		}
233
+	}
234
+
235
+
236
+	/**
237
+	 * Enqueues scripts and styles common to any batch job, and creates
238
+	 * a job from the request data, and stores the response in the
239
+	 * $this->_job_step_response property
240
+	 *
241
+	 * @return JobStepResponse
242
+	 */
243
+	protected function _enqueue_batch_job_scripts_and_styles_and_start_job(): JobStepResponse
244
+	{
245
+		// just copy the bits of EE admin's eei18n that we need in the JS
246
+		EE_Registry::$i18n_js_strings['batchJobError'] = __(
247
+			'An error occurred and the job has been stopped. Please refresh the page to try again.',
248
+			'event_espresso'
249
+		);
250
+		EE_Registry::$i18n_js_strings['is_admin']      = is_admin();
251
+		wp_enqueue_style(
252
+			EspressoLegacyAdminAssetManager::CSS_HANDLE_EE_ADMIN,
253
+			EE_ADMIN_URL . 'assets/ee-admin-page.css',
254
+			['espresso_admin_base'],
255
+			EVENT_ESPRESSO_VERSION
256
+		);
257
+		wp_enqueue_style(
258
+			'batch_runner',
259
+			BATCH_URL . 'assets/batch_runner.css',
260
+			[EspressoLegacyAdminAssetManager::CSS_HANDLE_EE_ADMIN],
261
+			date('Y-m-d-H:i', time())
262
+		);
263
+		wp_register_script(
264
+			'progress_bar',
265
+			EE_PLUGIN_DIR_URL . 'core/libraries/batch/Assets/progress_bar.js',
266
+			['jquery'],
267
+			date('Y-m-d-H:i', time()),
268
+			true
269
+		);
270
+		wp_enqueue_style(
271
+			'progress_bar',
272
+			EE_PLUGIN_DIR_URL . 'core/libraries/batch/Assets/progress_bar.css',
273
+			[],
274
+			date('Y-m-d-H:i', time())
275
+		);
276
+		wp_enqueue_script(
277
+			'batch_runner',
278
+			EE_PLUGIN_DIR_URL . 'core/libraries/batch/Assets/batch_runner.js',
279
+			['progress_bar', CoreAssetManager::JS_HANDLE_CORE],
280
+			date('Y-m-d-H:i', time()),
281
+			true
282
+		);
283
+		/** @var BatchRequestProcessor $batch_runner */
284
+		$batch_runner = $this->getLoader()->getShared('EventEspresso\core\libraries\batch\BatchRequestProcessor');
285
+		// eg 'EventEspresso\core\libraries\batch\JobHandlers\RegistrationsReport'
286
+		// remember the response for later. We need it to display the page body
287
+		$this->_job_step_response = $batch_runner->createJob();
288
+		return $this->_job_step_response;
289
+	}
290
+
291
+
292
+	/**
293
+	 * If we are doing a frontend batch job, this makes it so WP shows our template's HTML
294
+	 *
295
+	 * @param string $template
296
+	 * @return string
297
+	 */
298
+	public function override_template(string $template): string
299
+	{
300
+		$request = EED_Batch::getRequest();
301
+		if ($request->requestParamIsSet('batch') && $request->requestParamIsSet(EED_Batch::PAGE_SLUG)) {
302
+			return EE_MODULES . 'batch/templates/batch_frontend_wrapper.template.php';
303
+		}
304
+		return $template;
305
+	}
306
+
307
+
308
+	/**
309
+	 * Adds an admin page which doesn't appear in the admin menu
310
+	 *
311
+	 * @throws EE_Error
312
+	 * @throws ReflectionException
313
+	 */
314
+	public function register_admin_pages()
315
+	{
316
+		add_submenu_page(
317
+			'',
318
+			// parent slug. we don't want this to actually appear in the menu
319
+			esc_html__('Batch Job', 'event_espresso'),
320
+			// page title
321
+			'n/a',
322
+			// menu title
323
+			'read',
324
+			// we want this page to actually be accessible to anyone,
325
+			EED_Batch::PAGE_SLUG,
326
+			// menu slug
327
+			[self::instance(), 'show_admin_page']
328
+		);
329
+	}
330
+
331
+
332
+	/**
333
+	 * Renders the admin page, after most of the work was already done during enqueuing scripts
334
+	 * of creating the job and localizing some data
335
+	 */
336
+	public function show_admin_page()
337
+	{
338
+		echo EEH_Template::locate_template(
339
+			EE_MODULES . 'batch/templates/batch_wrapper.template.php',
340
+			[
341
+				'batch_request_type'        => $this->batch_request_type(),
342
+				'auto_redirect_on_complete' => EED_Batch::getRequest()->getRequestParam('auto_redirect_on_complete'),
343
+				'user_message'              => EED_Batch::getRequest()->getRequestParam('assessment_notice')
344
+					?: EED_Batch::getRequest()->getRequestParam('job_start_notice'),
345
+			]
346
+		);
347
+	}
348
+
349
+
350
+	private function runBatchRunnerJob(string $job)
351
+	{
352
+		$job_id = EED_Batch::getRequest()->getRequestParam('job_id');
353
+		/** @var BatchRequestProcessor $batch_runner */
354
+		$batch_runner = $this->getLoader()->getShared('EventEspresso\core\libraries\batch\BatchRequestProcessor');
355
+		$job_response = $batch_runner->{$job}($job_id);
356
+		$this->_return_json($job_response->to_array());
357
+	}
358
+
359
+
360
+	/**
361
+	 * Receives ajax calls for continuing a job
362
+	 */
363
+	public function continueBatchJob()
364
+	{
365
+		$this->runBatchRunnerJob('continueJob');
366
+	}
367
+
368
+
369
+	/**
370
+	 * Receives ajax calls for continuing a job
371
+	 */
372
+	public function advanceBatchJob()
373
+	{
374
+		$this->runBatchRunnerJob('advanceJob');
375
+	}
376
+
377
+
378
+	/**
379
+	 * Receives the ajax call to cleanup a job
380
+	 *
381
+	 * @return void
382
+	 */
383
+	public function cleanupBatchJob()
384
+	{
385
+		$this->runBatchRunnerJob('cleanupJob');
386
+	}
387
+
388
+
389
+	/**
390
+	 * Returns a json response
391
+	 *
392
+	 * @param array $data The data we want to send echo via in the JSON response's "data" element
393
+	 *
394
+	 * The returned json object is created from an array in the following format:
395
+	 * array(
396
+	 *    'notices' => '', // - contains any EE_Error formatted notices
397
+	 *    'data' => array() //this can be any key/value pairs that a method returns for later json parsing by the js.
398
+	 *    We're also going to include the template args with every package (so js can pick out any specific template
399
+	 *    args that might be included in here)
400
+	 *    'isEEajax' => true,//indicates this is a response from EE
401
+	 * )
402
+	 */
403
+	protected function _return_json(array $data)
404
+	{
405
+		$json = [
406
+			'data'     => $data,
407
+			'isEEajax' => true,
408
+			// special flag so any ajax.Success methods in js can identify this return package as a EEajax package.
409
+		];
410
+
411
+		// make sure there are no php errors or headers_sent.  Then we can set correct json header.
412
+		if (error_get_last() === null || ! headers_sent()) {
413
+			$notices = EE_Error::get_notices(false);
414
+			header('Content-Type: application/json; charset=UTF-8');
415
+			echo wp_json_encode($json + $notices);
416
+			exit();
417
+		}
418
+	}
419
+
420
+
421
+	/**
422
+	 * Gets the job step response which was done during the enqueuing of scripts
423
+	 *
424
+	 * @return JobStepResponse
425
+	 */
426
+	public function job_step_response(): JobStepResponse
427
+	{
428
+		return $this->_job_step_response;
429
+	}
430
+
431
+
432
+	/**
433
+	 * Gets the batch request type indicated in the current request
434
+	 *
435
+	 * @return string: EED_Batch::batch_job, EED_Batch::batch_file_job, EED_Batch::batch_not_job
436
+	 */
437
+	public function batch_request_type(): string
438
+	{
439
+		if (! $this->_batch_request_type) {
440
+			$request = EED_Batch::getRequest();
441
+			$batch   = $request->getRequestParam('batch');
442
+			switch ($batch) {
443
+				case self::batch_job:
444
+					$this->_batch_request_type = self::batch_job;
445
+					break;
446
+				case self::batch_file_job:
447
+					$this->_batch_request_type = self::batch_file_job;
448
+					break;
449
+				default:
450
+					// if we didn't find that it was a batch request, indicate it wasn't
451
+					$this->_batch_request_type = self::batch_not_job;
452
+			}
453
+		}
454
+		return $this->_batch_request_type;
455
+	}
456
+
457
+
458
+	/**
459
+	 * Unnecessary
460
+	 *
461
+	 * @param WP $WP
462
+	 */
463
+	public function run($WP)
464
+	{
465
+	}
466 466
 }
Please login to merge, or discard this patch.
modules/batch/templates/batch_file_runner.template.php 1 patch
Indentation   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -2,8 +2,8 @@  discard block
 block discarded – undo
2 2
 
3 3
 $job_step_response = EED_Batch::instance()->job_step_response();
4 4
 $filename = $job_step_response instanceof EventEspresso\core\libraries\batch\Helpers\JobStepResponse
5
-    ? EEH_File::get_filename_from_filepath($job_step_response->job_parameters()->extra_datum('filepath'))
6
-    : esc_html__('Unknown', 'event_espresso');
5
+	? EEH_File::get_filename_from_filepath($job_step_response->job_parameters()->extra_datum('filepath'))
6
+	: esc_html__('Unknown', 'event_espresso');
7 7
 ?>
8 8
 
9 9
 <div class='ee-batch-runner__wrapper ee-admin-container'>
@@ -15,9 +15,9 @@  discard block
 block discarded – undo
15 15
         <br/>
16 16
         <div id='message-area' class='ee-status-outline ee-status-bg--info'>
17 17
             <?php esc_html_e(
18
-                'The file will download automatically when done, and then you will be redirected.',
19
-                'event_espresso'
20
-            ); ?>
18
+				'The file will download automatically when done, and then you will be redirected.',
19
+				'event_espresso'
20
+			); ?>
21 21
         </div>
22 22
         <div id='progress-area'></div>
23 23
     </div>
Please login to merge, or discard this patch.
admin_pages/transactions/Transactions_Admin_Page.core.php 2 patches
Indentation   +2548 added lines, -2548 removed lines patch added patch discarded remove patch
@@ -13,2552 +13,2552 @@
 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
-     * @throws ReflectionException
97
-     */
98
-    public function _set_page_routes()
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
-     * @throws ReflectionException
283
-     */
284
-    private function _set_transaction_status_array()
285
-    {
286
-        self::$_txn_status = EEM_Transaction::instance()->status_array(true);
287
-    }
288
-
289
-
290
-    /**
291
-     * get_transaction_status_array
292
-     * return the transaction status array for wp_list_table
293
-     *
294
-     * @access public
295
-     * @return array
296
-     */
297
-    public function get_transaction_status_array()
298
-    {
299
-        return self::$_txn_status;
300
-    }
301
-
302
-
303
-    /**
304
-     *    get list of payment statuses
305
-     *
306
-     * @access private
307
-     * @return void
308
-     * @throws EE_Error
309
-     * @throws InvalidArgumentException
310
-     * @throws InvalidDataTypeException
311
-     * @throws InvalidInterfaceException
312
-     * @throws ReflectionException
313
-     */
314
-    private function _get_payment_status_array()
315
-    {
316
-        self::$_pay_status                      = EEM_Payment::instance()->status_array(true);
317
-        $this->_template_args['payment_status'] = self::$_pay_status;
318
-    }
319
-
320
-
321
-    /**
322
-     *    _add_screen_options_default
323
-     *
324
-     * @access protected
325
-     * @return void
326
-     * @throws InvalidArgumentException
327
-     * @throws InvalidDataTypeException
328
-     * @throws InvalidInterfaceException
329
-     */
330
-    protected function _add_screen_options_default()
331
-    {
332
-        $this->_per_page_screen_option();
333
-    }
334
-
335
-
336
-    /**
337
-     * load_scripts_styles
338
-     *
339
-     * @access public
340
-     * @return void
341
-     */
342
-    public function load_scripts_styles()
343
-    {
344
-        // enqueue style
345
-        wp_register_style(
346
-            'espresso_txn',
347
-            TXN_ASSETS_URL . 'espresso_transactions_admin.css',
348
-            [],
349
-            EVENT_ESPRESSO_VERSION
350
-        );
351
-        wp_enqueue_style('espresso_txn');
352
-        // scripts
353
-        wp_register_script(
354
-            'espresso_txn',
355
-            TXN_ASSETS_URL . 'espresso_transactions_admin.js',
356
-            [
357
-                'ee_admin_js',
358
-                'ee-datepicker',
359
-                'jquery-ui-datepicker',
360
-                'jquery-ui-draggable',
361
-                'ee-dialog',
362
-                'ee-accounting',
363
-                'ee-serialize-full-array',
364
-            ],
365
-            EVENT_ESPRESSO_VERSION,
366
-            true
367
-        );
368
-        wp_enqueue_script('espresso_txn');
369
-    }
370
-
371
-
372
-    /**
373
-     *    load_scripts_styles_view_transaction
374
-     *
375
-     * @access public
376
-     * @return void
377
-     */
378
-    public function load_scripts_styles_view_transaction()
379
-    {
380
-        // styles
381
-        wp_enqueue_style('espresso-ui-theme');
382
-    }
383
-
384
-
385
-    /**
386
-     *    load_scripts_styles_default
387
-     *
388
-     * @access public
389
-     * @return void
390
-     */
391
-    public function load_scripts_styles_default()
392
-    {
393
-        // styles
394
-        wp_enqueue_style('espresso-ui-theme');
395
-    }
396
-
397
-
398
-    /**
399
-     *    _set_list_table_views_default
400
-     *
401
-     * @access protected
402
-     * @return void
403
-     */
404
-    protected function _set_list_table_views_default()
405
-    {
406
-        $this->_views = [
407
-            'all'        => [
408
-                'slug'  => 'all',
409
-                'label' => esc_html__('View All Transactions', 'event_espresso'),
410
-                'count' => 0,
411
-            ],
412
-            'abandoned'  => [
413
-                'slug'  => 'abandoned',
414
-                'label' => esc_html__('Abandoned Transactions', 'event_espresso'),
415
-                'count' => 0,
416
-            ],
417
-            'incomplete' => [
418
-                'slug'  => 'incomplete',
419
-                'label' => esc_html__('Incomplete Transactions', 'event_espresso'),
420
-                'count' => 0,
421
-            ],
422
-        ];
423
-        if (
424
-            /**
425
-             * Filters whether a link to the "Failed Transactions" list table
426
-             * appears on the Transactions Admin Page list table.
427
-             * List display can be turned back on via the following:
428
-             * add_filter(
429
-             *     'FHEE__Transactions_Admin_Page___set_list_table_views_default__display_failed_txns_list',
430
-             *     '__return_true'
431
-             * );
432
-             *
433
-             * @param boolean                 $display_failed_txns_list
434
-             * @param Transactions_Admin_Page $this
435
-             * @since 4.9.70.p
436
-             */
437
-        apply_filters(
438
-            'FHEE__Transactions_Admin_Page___set_list_table_views_default__display_failed_txns_list',
439
-            false,
440
-            $this
441
-        )
442
-        ) {
443
-            $this->_views['failed'] = [
444
-                'slug'  => 'failed',
445
-                'label' => esc_html__('Failed Transactions', 'event_espresso'),
446
-                'count' => 0,
447
-            ];
448
-        }
449
-    }
450
-
451
-
452
-    /**
453
-     * _set_transaction_object
454
-     * This sets the _transaction property for the transaction details screen
455
-     *
456
-     * @access private
457
-     * @return void
458
-     * @throws EE_Error
459
-     * @throws InvalidArgumentException
460
-     * @throws RuntimeException
461
-     * @throws InvalidDataTypeException
462
-     * @throws InvalidInterfaceException
463
-     * @throws ReflectionException
464
-     */
465
-    private function _set_transaction_object()
466
-    {
467
-        if ($this->_transaction instanceof EE_Transaction) {
468
-            return;
469
-        } //get out we've already set the object
470
-
471
-        $TXN_ID = $this->request->getRequestParam('TXN_ID', 0, 'int');
472
-
473
-        // get transaction object
474
-        $this->_transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
475
-        $this->_session     = $this->_transaction instanceof EE_Transaction
476
-            ? $this->_transaction->session_data()
477
-            : null;
478
-        if ($this->_transaction instanceof EE_Transaction) {
479
-            $this->_transaction->verify_abandoned_transaction_status();
480
-        }
481
-
482
-        if (! $this->_transaction instanceof EE_Transaction) {
483
-            $error_msg = sprintf(
484
-                esc_html__(
485
-                    'An error occurred and the details for the transaction with the ID # %d could not be retrieved.',
486
-                    'event_espresso'
487
-                ),
488
-                $TXN_ID
489
-            );
490
-            EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
491
-        }
492
-    }
493
-
494
-
495
-    /**
496
-     *    _transaction_legend_items
497
-     *
498
-     * @access protected
499
-     * @return array
500
-     * @throws EE_Error
501
-     * @throws InvalidArgumentException
502
-     * @throws ReflectionException
503
-     * @throws InvalidDataTypeException
504
-     * @throws InvalidInterfaceException
505
-     */
506
-    protected function _transaction_legend_items()
507
-    {
508
-        EE_Registry::instance()->load_helper('MSG_Template');
509
-        $items = [];
510
-
511
-        if (
512
-            $this->capabilities->current_user_can(
513
-                'ee_read_global_messages',
514
-                'view_filtered_messages'
515
-            )
516
-        ) {
517
-            $related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
518
-            if (
519
-                is_array($related_for_icon)
520
-                && isset($related_for_icon['css_class'], $related_for_icon['label'])
521
-            ) {
522
-                $items['view_related_messages'] = [
523
-                    'class' => $related_for_icon['css_class'],
524
-                    'desc'  => $related_for_icon['label'],
525
-                ];
526
-            }
527
-        }
528
-
529
-        $items = apply_filters(
530
-            'FHEE__Transactions_Admin_Page___transaction_legend_items__items',
531
-            array_merge(
532
-                $items,
533
-                [
534
-                    'view_details'          => [
535
-                        'class' => 'dashicons dashicons-cart',
536
-                        'desc'  => esc_html__('View Transaction Details', 'event_espresso'),
537
-                    ],
538
-                    'view_invoice'          => [
539
-                        'class' => 'dashicons dashicons-media-spreadsheet',
540
-                        'desc'  => esc_html__('View Transaction Invoice', 'event_espresso'),
541
-                    ],
542
-                    'view_receipt'          => [
543
-                        'class' => 'dashicons dashicons-text-page',
544
-                        'desc'  => esc_html__('View Transaction Receipt', 'event_espresso'),
545
-                    ],
546
-                    'view_registration'     => [
547
-                        'class' => 'dashicons dashicons-clipboard',
548
-                        'desc'  => esc_html__('View Registration Details', 'event_espresso'),
549
-                    ],
550
-                    'payment_overview_link' => [
551
-                        'class' => 'dashicons dashicons-money',
552
-                        'desc'  => esc_html__('Make Payment on Frontend', 'event_espresso'),
553
-                    ],
554
-                ]
555
-            )
556
-        );
557
-
558
-        if (
559
-            EEH_MSG_Template::is_mt_active('payment_reminder')
560
-            && $this->capabilities->current_user_can(
561
-                'ee_send_message',
562
-                'espresso_transactions_send_payment_reminder'
563
-            )
564
-        ) {
565
-            $items['send_payment_reminder'] = [
566
-                'class' => 'dashicons dashicons-email-alt',
567
-                'desc'  => esc_html__('Send Payment Reminder', 'event_espresso'),
568
-            ];
569
-        } else {
570
-            $items['blank*'] = [
571
-                'class' => '',
572
-                'desc'  => '',
573
-            ];
574
-        }
575
-        $more_items = apply_filters(
576
-            'FHEE__Transactions_Admin_Page___transaction_legend_items__more_items',
577
-            [
578
-                'overpaid'   => [
579
-                    'class' => 'ee-status-legend ee-status-bg--' . EEM_Transaction::overpaid_status_code,
580
-                    'desc'  => EEH_Template::pretty_status(
581
-                        EEM_Transaction::overpaid_status_code,
582
-                        false,
583
-                        'sentence'
584
-                    ),
585
-                ],
586
-                'complete'   => [
587
-                    'class' => 'ee-status-legend ee-status-bg--' . EEM_Transaction::complete_status_code,
588
-                    'desc'  => EEH_Template::pretty_status(
589
-                        EEM_Transaction::complete_status_code,
590
-                        false,
591
-                        'sentence'
592
-                    ),
593
-                ],
594
-                'incomplete' => [
595
-                    'class' => 'ee-status-legend ee-status-bg--' . EEM_Transaction::incomplete_status_code,
596
-                    'desc'  => EEH_Template::pretty_status(
597
-                        EEM_Transaction::incomplete_status_code,
598
-                        false,
599
-                        'sentence'
600
-                    ),
601
-                ],
602
-                'abandoned'  => [
603
-                    'class' => 'ee-status-legend ee-status-bg--' . EEM_Transaction::abandoned_status_code,
604
-                    'desc'  => EEH_Template::pretty_status(
605
-                        EEM_Transaction::abandoned_status_code,
606
-                        false,
607
-                        'sentence'
608
-                    ),
609
-                ],
610
-                'failed'     => [
611
-                    'class' => 'ee-status-legend ee-status-bg--' . EEM_Transaction::failed_status_code,
612
-                    'desc'  => EEH_Template::pretty_status(
613
-                        EEM_Transaction::failed_status_code,
614
-                        false,
615
-                        'sentence'
616
-                    ),
617
-                ],
618
-            ]
619
-        );
620
-
621
-        return array_merge($items, $more_items);
622
-    }
623
-
624
-
625
-    /**
626
-     *    _transactions_overview_list_table
627
-     *
628
-     * @access protected
629
-     * @return void
630
-     * @throws DomainException
631
-     * @throws EE_Error
632
-     * @throws InvalidArgumentException
633
-     * @throws InvalidDataTypeException
634
-     * @throws InvalidInterfaceException
635
-     * @throws ReflectionException
636
-     */
637
-    protected function _transactions_overview_list_table()
638
-    {
639
-        $this->_admin_page_title = esc_html__('Transactions', 'event_espresso');
640
-
641
-        $EVT_ID                                    = $this->request->getRequestParam('EVT_ID', 0, 'int');
642
-        $event                                     = EEM_Event::instance()->get_one_by_ID($EVT_ID);
643
-        $this->_template_args['admin_page_header'] = $event instanceof EE_Event
644
-            ? sprintf(
645
-                esc_html__('%sViewing Transactions for the Event: %s%s', 'event_espresso'),
646
-                '<h3>',
647
-                '<a href="'
648
-                . EE_Admin_Page::add_query_args_and_nonce(
649
-                    ['action' => 'edit', 'post' => $event->ID()],
650
-                    EVENTS_ADMIN_URL
651
-                )
652
-                . '" aria-label="'
653
-                . esc_attr__('Click to Edit event', 'event_espresso')
654
-                . '">' . $event->name() . '</a>',
655
-                '</h3>'
656
-            )
657
-            : '';
658
-        $this->_template_args['after_list_table']  = $this->_display_legend($this->_transaction_legend_items());
659
-        $this->display_admin_list_table_page_with_no_sidebar();
660
-    }
661
-
662
-
663
-    /**
664
-     *    _transaction_details
665
-     * generates HTML for the View Transaction Details Admin page
666
-     *
667
-     * @access protected
668
-     * @return void
669
-     * @throws DomainException
670
-     * @throws EE_Error
671
-     * @throws InvalidArgumentException
672
-     * @throws InvalidDataTypeException
673
-     * @throws InvalidInterfaceException
674
-     * @throws RuntimeException
675
-     * @throws ReflectionException
676
-     */
677
-    protected function _transaction_details()
678
-    {
679
-        do_action('AHEE__Transactions_Admin_Page__transaction_details__start', $this->_transaction);
680
-
681
-        $this->_set_transaction_status_array();
682
-
683
-        $this->_template_args                      = [];
684
-        $this->_template_args['transactions_page'] = $this->_wp_page_slug;
685
-
686
-        $this->_set_transaction_object();
687
-
688
-        if (! $this->_transaction instanceof EE_Transaction) {
689
-            return;
690
-        }
691
-
692
-        $this->_template_args['txn_nmbr']['value'] = $this->_transaction->ID();
693
-        $this->_template_args['txn_nmbr']['label'] = esc_html__('Transaction Number', 'event_espresso');
694
-
695
-        $this->_template_args['txn_datetime']['value'] = $this->_transaction->get_i18n_datetime('TXN_timestamp');
696
-        $this->_template_args['txn_datetime']['label'] = esc_html__('Date', 'event_espresso');
697
-
698
-        $this->_template_args['txn_status']['value'] = self::$_txn_status[ $this->_transaction->status_ID() ];
699
-        $this->_template_args['txn_status']['label'] = esc_html__('Transaction Status', 'event_espresso');
700
-        $this->_template_args['txn_status']['class'] = $this->_transaction->status_ID();
701
-
702
-        $txn_total  = $this->_transaction->total();
703
-        $total_paid = $this->_transaction->paid();
704
-        $amount_due = $txn_total - $total_paid;
705
-
706
-        $this->_template_args['grand_total'] = $txn_total;
707
-        $this->_template_args['total_paid']  = $total_paid;
708
-
709
-        $this->_template_args['amount_due']     = EEH_Template::format_currency($amount_due, false, false);
710
-        $this->_template_args['amount_due_raw'] = $amount_due;
711
-
712
-        $this->_template_args['amount_due_class'] = '';
713
-
714
-        if ($txn_total === (float) 0) {
715
-            // free event
716
-            $this->_template_args['amount_due'] = false;
717
-        } elseif ($amount_due < (float) 0) {
718
-            // overpaid
719
-            $this->_template_args['amount_due_class'] = 'txn-overview-no-payment-spn';
720
-        } elseif ($amount_due > (float) 0) {
721
-            // monies owing
722
-            $this->_template_args['amount_due_class'] = 'txn-overview-part-payment-spn ee-txn-amount-owing';
723
-        } elseif ($total_paid === (float) 0) {
724
-            // no payments made yet
725
-            $this->_template_args['amount_due_class'] = 'txn-overview-no-payment-spn';
726
-        }
727
-
728
-        $payment_method = $this->_transaction->payment_method();
729
-
730
-        $this->_template_args['method_of_payment_name'] = $payment_method instanceof EE_Payment_Method
731
-            ? $payment_method->admin_name()
732
-            : esc_html__('Unknown', 'event_espresso');
733
-
734
-        $this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
735
-        // link back to overview
736
-        $this->_template_args['txn_overview_url'] = $this->request->getServerParam(
737
-            'HTTP_REFERER',
738
-            TXN_ADMIN_URL
739
-        );
740
-
741
-
742
-        // next link
743
-        $next_txn                                 = $this->_transaction->next(
744
-            null,
745
-            [['STS_ID' => ['!=', EEM_Transaction::failed_status_code]]],
746
-            'TXN_ID'
747
-        );
748
-        $this->_template_args['next_transaction'] = $next_txn
749
-            ? $this->_next_link(
750
-                EE_Admin_Page::add_query_args_and_nonce(
751
-                    ['action' => 'view_transaction', 'TXN_ID' => $next_txn['TXN_ID']],
752
-                    TXN_ADMIN_URL
753
-                ),
754
-                'dashicons dashicons-arrow-right ee-icon-size-22'
755
-            )
756
-            : '';
757
-        // previous link
758
-        $previous_txn                                 = $this->_transaction->previous(
759
-            null,
760
-            [['STS_ID' => ['!=', EEM_Transaction::failed_status_code]]],
761
-            'TXN_ID'
762
-        );
763
-        $this->_template_args['previous_transaction'] = $previous_txn
764
-            ? $this->_previous_link(
765
-                EE_Admin_Page::add_query_args_and_nonce(
766
-                    ['action' => 'view_transaction', 'TXN_ID' => $previous_txn['TXN_ID']],
767
-                    TXN_ADMIN_URL
768
-                ),
769
-                'dashicons dashicons-arrow-left ee-icon-size-22'
770
-            )
771
-            : '';
772
-
773
-        $EVT_ID        = $this->request->getRequestParam('EVT_ID', 0, 'int');
774
-        $event_name    = $this->request->getRequestParam('event_name');
775
-        $redirect_from = $this->request->getRequestParam('redirect_from', '', 'url');
776
-
777
-        // were we just redirected here after adding a new registration ???
778
-        if ($EVT_ID && $event_name && $redirect_from) {
779
-            if (
780
-                $this->capabilities->current_user_can(
781
-                    'ee_edit_registrations',
782
-                    'espresso_registrations_new_registration',
783
-                    $EVT_ID
784
-                )
785
-            ) {
786
-                $this->_admin_page_title .= '<a id="add-new-registration" class="add-new-h2 button--primary" href="';
787
-                $this->_admin_page_title .= EE_Admin_Page::add_query_args_and_nonce(
788
-                    [
789
-                        'page'     => 'espresso_registrations',
790
-                        'action'   => 'new_registration',
791
-                        'return'   => 'default',
792
-                        'TXN_ID'   => $this->_transaction->ID(),
793
-                        'event_id' => $EVT_ID,
794
-                    ],
795
-                    REG_ADMIN_URL
796
-                );
797
-                $this->_admin_page_title .= '">';
798
-
799
-                $this->_admin_page_title .= sprintf(
800
-                    esc_html__('Add Another New Registration to Event: "%1$s" ?', 'event_espresso'),
801
-                    htmlentities(urldecode($event_name), ENT_QUOTES, 'UTF-8')
802
-                );
803
-                $this->_admin_page_title .= '</a>';
804
-            }
805
-            EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
806
-        }
807
-        // grab messages at the last second
808
-        $this->_template_args['notices'] = EE_Error::get_notices();
809
-        // path to template
810
-        $template_path                             = TXN_TEMPLATE_PATH . 'txn_admin_details_header.template.php';
811
-        $this->_template_args['admin_page_header'] = EEH_Template::display_template(
812
-            $template_path,
813
-            $this->_template_args,
814
-            true
815
-        );
816
-
817
-        // the details template wrapper
818
-        $this->display_admin_page_with_sidebar();
819
-    }
820
-
821
-
822
-    /**
823
-     *        _transaction_details_metaboxes
824
-     *
825
-     * @access protected
826
-     * @return void
827
-     * @throws EE_Error
828
-     * @throws InvalidArgumentException
829
-     * @throws InvalidDataTypeException
830
-     * @throws InvalidInterfaceException
831
-     * @throws RuntimeException
832
-     * @throws ReflectionException
833
-     */
834
-    protected function _transaction_details_metaboxes()
835
-    {
836
-        $this->_set_transaction_object();
837
-
838
-        if (! $this->_transaction instanceof EE_Transaction) {
839
-            return;
840
-        }
841
-        $this->addMetaBox(
842
-            'edit-txn-details-mbox',
843
-            '<span>' . esc_html__('Transaction Details', 'event_espresso')
844
-            . '&nbsp;<span class="dashicons dashicons-cart" ></span></span>',
845
-            [$this, 'txn_details_meta_box'],
846
-            $this->_wp_page_slug
847
-        );
848
-        $this->addMetaBox(
849
-            'edit-txn-attendees-mbox',
850
-            '<span>' . esc_html__('Attendees Registered in this Transaction', 'event_espresso')
851
-            . '&nbsp;<span class="dashicons dashicons-groups" ></span></span>',
852
-            [$this, 'txn_attendees_meta_box'],
853
-            $this->_wp_page_slug,
854
-            'normal',
855
-            'high',
856
-            ['TXN_ID' => $this->_transaction->ID()]
857
-        );
858
-        $this->addMetaBox(
859
-            'edit-txn-registrant-mbox',
860
-            esc_html__('Primary Contact', 'event_espresso'),
861
-            [$this, 'txn_registrant_side_meta_box'],
862
-            $this->_wp_page_slug,
863
-            'side'
864
-        );
865
-        $this->addMetaBox(
866
-            'edit-txn-billing-info-mbox',
867
-            esc_html__('Billing Information', 'event_espresso'),
868
-            [$this, 'txn_billing_info_side_meta_box'],
869
-            $this->_wp_page_slug,
870
-            'side'
871
-        );
872
-    }
873
-
874
-
875
-    /**
876
-     * Callback for transaction actions metabox.
877
-     *
878
-     * @param EE_Transaction|null $transaction
879
-     * @return string
880
-     * @throws DomainException
881
-     * @throws EE_Error
882
-     * @throws InvalidArgumentException
883
-     * @throws InvalidDataTypeException
884
-     * @throws InvalidInterfaceException
885
-     * @throws ReflectionException
886
-     * @throws RuntimeException
887
-     */
888
-    public function getActionButtons(EE_Transaction $transaction = null)
889
-    {
890
-        $content = '';
891
-        $actions = [];
892
-        if (! $transaction instanceof EE_Transaction) {
893
-            return $content;
894
-        }
895
-        /** @var EE_Registration $primary_registration */
896
-        $primary_registration = $transaction->primary_registration();
897
-        $attendee             = $primary_registration instanceof EE_Registration
898
-            ? $primary_registration->attendee()
899
-            : null;
900
-
901
-        if (
902
-            $attendee instanceof EE_Attendee
903
-            && $this->capabilities->current_user_can(
904
-                'ee_send_message',
905
-                'espresso_transactions_send_payment_reminder'
906
-            )
907
-        ) {
908
-            $actions['payment_reminder'] =
909
-                EEH_MSG_Template::is_mt_active('payment_reminder')
910
-                && $this->_transaction->status_ID() !== EEM_Transaction::complete_status_code
911
-                && $this->_transaction->status_ID() !== EEM_Transaction::overpaid_status_code
912
-                    ? EEH_Template::get_button_or_link(
913
-                    EE_Admin_Page::add_query_args_and_nonce(
914
-                        [
915
-                            'action'      => 'send_payment_reminder',
916
-                            'TXN_ID'      => $this->_transaction->ID(),
917
-                            'redirect_to' => 'view_transaction',
918
-                        ],
919
-                        TXN_ADMIN_URL
920
-                    ),
921
-                    esc_html__(' Send Payment Reminder', 'event_espresso'),
922
-                    'button button--secondary',
923
-                    'dashicons dashicons-email-alt'
924
-                )
925
-                    : '';
926
-        }
927
-
928
-        if (
929
-            $this->capabilities->current_user_can(
930
-                'ee_edit_payments',
931
-                'espresso_transactions_recalculate_line_items'
932
-            )
933
-        ) {
934
-            $actions['recalculate_line_items'] = EEH_Template::get_button_or_link(
935
-                EE_Admin_Page::add_query_args_and_nonce(
936
-                    [
937
-                        'action'      => 'espresso_recalculate_line_items',
938
-                        'TXN_ID'      => $this->_transaction->ID(),
939
-                        'redirect_to' => 'view_transaction',
940
-                    ],
941
-                    TXN_ADMIN_URL
942
-                ),
943
-                esc_html__(' Recalculate Taxes and Total', 'event_espresso'),
944
-                'button button--secondary',
945
-                'dashicons dashicons-update'
946
-            );
947
-        }
948
-
949
-        if (
950
-            $primary_registration instanceof EE_Registration
951
-            && EEH_MSG_Template::is_mt_active('receipt')
952
-        ) {
953
-            $actions['receipt'] = EEH_Template::get_button_or_link(
954
-                $primary_registration->receipt_url(),
955
-                esc_html__('View Receipt', 'event_espresso'),
956
-                'button button--secondary',
957
-                'dashicons dashicons-text-page'
958
-            );
959
-        }
960
-
961
-        if (
962
-            $primary_registration instanceof EE_Registration
963
-            && EEH_MSG_Template::is_mt_active('invoice')
964
-        ) {
965
-            $actions['invoice'] = EEH_Template::get_button_or_link(
966
-                $primary_registration->invoice_url(),
967
-                esc_html__('View Invoice', 'event_espresso'),
968
-                'button button--secondary',
969
-                'dashicons dashicons-media-spreadsheet'
970
-            );
971
-        }
972
-        $actions = array_filter(
973
-            apply_filters('FHEE__Transactions_Admin_Page__getActionButtons__actions', $actions, $transaction)
974
-        );
975
-        if ($actions) {
976
-            $content .= implode('', $actions);
977
-        }
978
-        return $content;
979
-    }
980
-
981
-
982
-    /**
983
-     * txn_details_meta_box
984
-     * generates HTML for the Transaction main meta box
985
-     *
986
-     * @return void
987
-     * @throws DomainException
988
-     * @throws EE_Error
989
-     * @throws InvalidArgumentException
990
-     * @throws InvalidDataTypeException
991
-     * @throws InvalidInterfaceException
992
-     * @throws RuntimeException
993
-     * @throws ReflectionException
994
-     */
995
-    public function txn_details_meta_box()
996
-    {
997
-        $this->_set_transaction_object();
998
-        $this->_template_args['TXN_ID']              = $this->_transaction->ID();
999
-        $this->_template_args['attendee']            =
1000
-            $this->_transaction->primary_registration() instanceof EE_Registration
1001
-                ? $this->_transaction->primary_registration()->attendee()
1002
-                : null;
1003
-        $this->_template_args['can_edit_payments']   = $this->capabilities->current_user_can(
1004
-            'ee_edit_payments',
1005
-            'apply_payment_or_refund_from_registration_details'
1006
-        );
1007
-        $this->_template_args['can_delete_payments'] = $this->capabilities->current_user_can(
1008
-            'ee_delete_payments',
1009
-            'delete_payment_from_registration_details'
1010
-        );
1011
-
1012
-        // get line table
1013
-        EEH_Autoloader::register_line_item_display_autoloaders();
1014
-        $Line_Item_Display                       = new EE_Line_Item_Display(
1015
-            'admin_table',
1016
-            'EE_Admin_Table_Line_Item_Display_Strategy'
1017
-        );
1018
-        $this->_template_args['line_item_table'] = $Line_Item_Display->display_line_item(
1019
-            $this->_transaction->total_line_item()
1020
-        );
1021
-        $this->_template_args['REG_code']        =
1022
-            $this->_transaction->primary_registration() instanceof EE_Registration
1023
-                ? $this->_transaction->primary_registration()->reg_code()
1024
-                : null;
1025
-        // process taxes
1026
-        $taxes                         = $this->_transaction->line_items([['LIN_type' => EEM_Line_Item::type_tax]]);
1027
-        $this->_template_args['taxes'] = ! empty($taxes)
1028
-            ? $taxes
1029
-            : false;
1030
-
1031
-        $this->_template_args['grand_total']     = EEH_Template::format_currency(
1032
-            $this->_transaction->total(),
1033
-            false,
1034
-            false
1035
-        );
1036
-        $this->_template_args['grand_raw_total'] = $this->_transaction->total();
1037
-        $this->_template_args['TXN_status']      = $this->_transaction->status_ID();
1038
-
1039
-        // process payment details
1040
-        $payments = $this->_transaction->payments();
1041
-        if (! empty($payments)) {
1042
-            $this->_template_args['payments']              = $payments;
1043
-            $this->_template_args['existing_reg_payments'] = $this->_get_registration_payment_IDs($payments);
1044
-        } else {
1045
-            $this->_template_args['payments']              = false;
1046
-            $this->_template_args['existing_reg_payments'] = [];
1047
-        }
1048
-
1049
-        $this->_template_args['edit_payment_url']   = add_query_arg(['action' => 'edit_payment'], TXN_ADMIN_URL);
1050
-        $this->_template_args['delete_payment_url'] = add_query_arg(
1051
-            ['action' => 'espresso_delete_payment'],
1052
-            TXN_ADMIN_URL
1053
-        );
1054
-
1055
-        if (isset($txn_details['invoice_number'])) {
1056
-            $this->_template_args['txn_details']['invoice_number']['value'] = $this->_template_args['REG_code'];
1057
-            $this->_template_args['txn_details']['invoice_number']['label'] = esc_html__(
1058
-                'Invoice Number',
1059
-                'event_espresso'
1060
-            );
1061
-        }
1062
-
1063
-        $this->_template_args['txn_details']['registration_session']['value'] =
1064
-            $this->_transaction->primary_registration() instanceof EE_Registration
1065
-                ? $this->_transaction->primary_registration()->session_ID()
1066
-                : null;
1067
-        $this->_template_args['txn_details']['registration_session']['label'] = esc_html__(
1068
-            'Registration Session',
1069
-            'event_espresso'
1070
-        );
1071
-
1072
-        $this->_template_args['txn_details']['ip_address']['value'] = $this->_session['ip_address'] ?? '';
1073
-        $this->_template_args['txn_details']['ip_address']['label'] = esc_html__(
1074
-            'Transaction placed from IP',
1075
-            'event_espresso'
1076
-        );
1077
-
1078
-        $this->_template_args['txn_details']['user_agent']['value'] = $this->_session['user_agent'] ?? '';
1079
-        $this->_template_args['txn_details']['user_agent']['label'] = esc_html__(
1080
-            'Registrant User Agent',
1081
-            'event_espresso'
1082
-        );
1083
-
1084
-        $reg_steps = '<div class="ee-txn-reg-step-status-steps ee-layout-row">';
1085
-        foreach ($this->_transaction->reg_steps() as $reg_step => $reg_step_status) {
1086
-            if ($reg_step_status === true) {
1087
-                $reg_steps .= '<div class="ee-status-pill ee-status-bg--success">'
1088
-                              . sprintf(
1089
-                                  esc_html__('%1$s : Completed', 'event_espresso'),
1090
-                                  ucwords(str_replace('_', ' ', $reg_step))
1091
-                              )
1092
-                              . '</div>';
1093
-            } elseif ($reg_step_status !== false && is_numeric($reg_step_status)) {
1094
-                $reg_steps .= '<div class="ee-status-pill ee-status-bg--attention">'
1095
-                              . sprintf(
1096
-                                  esc_html__('%1$s : Initiated %2$s', 'event_espresso'),
1097
-                                  ucwords(str_replace('_', ' ', $reg_step)),
1098
-                                  date(
1099
-                                      get_option('date_format') . ' ' . get_option('time_format'),
1100
-                                      $reg_step_status + (get_option('gmt_offset') * HOUR_IN_SECONDS)
1101
-                                  )
1102
-                              )
1103
-                              . '</div>';
1104
-            } else {
1105
-                $reg_steps .= '<div class="ee-status-pill ee-status-bg--error">'
1106
-                              . sprintf(
1107
-                                  esc_html__('%1$s : Never Initiated', 'event_espresso'),
1108
-                                  ucwords(str_replace('_', ' ', $reg_step))
1109
-                              )
1110
-                              . '</div>';
1111
-            }
1112
-        }
1113
-        $reg_steps                                                 .= '</ul>';
1114
-        $this->_template_args['txn_details']['reg_steps']['value'] = $reg_steps;
1115
-        $this->_template_args['txn_details']['reg_steps']['label'] = esc_html__(
1116
-            'Registration Step Progress',
1117
-            'event_espresso'
1118
-        );
1119
-
1120
-
1121
-        $this->_get_registrations_to_apply_payment_to();
1122
-        $this->_get_payment_methods($payments);
1123
-        $this->_get_payment_status_array();
1124
-        $this->_get_reg_status_selection(); // sets up the template args for the reg status array for the transaction.
1125
-
1126
-        $this->_template_args['transaction_form_url']    = add_query_arg(
1127
-            [
1128
-                'action'  => 'edit_transaction',
1129
-                'process' => 'transaction',
1130
-            ],
1131
-            TXN_ADMIN_URL
1132
-        );
1133
-        $this->_template_args['apply_payment_form_url']  = add_query_arg(
1134
-            [
1135
-                'page'   => 'espresso_transactions',
1136
-                'action' => 'espresso_apply_payment',
1137
-            ],
1138
-            TXN_ADMIN_URL
1139
-        );
1140
-        $this->_template_args['delete_payment_form_url'] = add_query_arg(
1141
-            [
1142
-                'page'   => 'espresso_transactions',
1143
-                'action' => 'espresso_delete_payment',
1144
-            ],
1145
-            TXN_ADMIN_URL
1146
-        );
1147
-
1148
-        $this->_template_args['action_buttons'] = $this->getActionButtons($this->_transaction);
1149
-
1150
-        // 'espresso_delete_payment_nonce'
1151
-
1152
-        $template_path = TXN_TEMPLATE_PATH . 'txn_admin_details_main_meta_box_txn_details.template.php';
1153
-        echo EEH_Template::display_template($template_path, $this->_template_args, true);
1154
-    }
1155
-
1156
-
1157
-    /**
1158
-     * _get_registration_payment_IDs
1159
-     *    generates an array of Payment IDs and their corresponding Registration IDs
1160
-     *
1161
-     * @access protected
1162
-     * @param EE_Payment[] $payments
1163
-     * @return array
1164
-     * @throws EE_Error
1165
-     * @throws InvalidArgumentException
1166
-     * @throws InvalidDataTypeException
1167
-     * @throws InvalidInterfaceException
1168
-     * @throws ReflectionException
1169
-     */
1170
-    protected function _get_registration_payment_IDs($payments = [])
1171
-    {
1172
-        $existing_reg_payments = [];
1173
-        // get all reg payments for these payments
1174
-        $reg_payments = EEM_Registration_Payment::instance()->get_all(
1175
-            [
1176
-                [
1177
-                    'PAY_ID' => [
1178
-                        'IN',
1179
-                        array_keys($payments),
1180
-                    ],
1181
-                ],
1182
-            ]
1183
-        );
1184
-        if (! empty($reg_payments)) {
1185
-            foreach ($payments as $payment) {
1186
-                if (! $payment instanceof EE_Payment) {
1187
-                    continue;
1188
-                } elseif (! isset($existing_reg_payments[ $payment->ID() ])) {
1189
-                    $existing_reg_payments[ $payment->ID() ] = [];
1190
-                }
1191
-                foreach ($reg_payments as $reg_payment) {
1192
-                    if (
1193
-                        $reg_payment instanceof EE_Registration_Payment
1194
-                        && $reg_payment->payment_ID() === $payment->ID()
1195
-                    ) {
1196
-                        $existing_reg_payments[ $payment->ID() ][] = $reg_payment->registration_ID();
1197
-                    }
1198
-                }
1199
-            }
1200
-        }
1201
-
1202
-        return $existing_reg_payments;
1203
-    }
1204
-
1205
-
1206
-    /**
1207
-     * _get_registrations_to_apply_payment_to
1208
-     *    generates HTML for displaying a series of checkboxes in the admin payment modal window
1209
-     * which allows the admin to only apply the payment to the specific registrations
1210
-     *
1211
-     * @access protected
1212
-     * @return void
1213
-     * @throws EE_Error
1214
-     * @throws InvalidArgumentException
1215
-     * @throws InvalidDataTypeException
1216
-     * @throws InvalidInterfaceException
1217
-     * @throws ReflectionException
1218
-     */
1219
-    protected function _get_registrations_to_apply_payment_to()
1220
-    {
1221
-        // we want any registration with an active status (ie: not deleted or cancelled)
1222
-        $query_params                      = [
1223
-            [
1224
-                'STS_ID' => [
1225
-                    'IN',
1226
-                    [
1227
-                        EEM_Registration::status_id_approved,
1228
-                        EEM_Registration::status_id_pending_payment,
1229
-                        EEM_Registration::status_id_not_approved,
1230
-                    ],
1231
-                ],
1232
-            ],
1233
-        ];
1234
-        $registrations_to_apply_payment_to = EEH_HTML::br() . EEH_HTML::div(
1235
-                '',
1236
-                'txn-admin-apply-payment-to-registrations-dv',
1237
-                '',
1238
-                'clear: both; margin: 1.5em 0 0; display: none;'
1239
-            );
1240
-        $registrations_to_apply_payment_to .= EEH_HTML::br() . EEH_HTML::div('', '', 'admin-primary-mbox-tbl-wrap');
1241
-        $registrations_to_apply_payment_to .= EEH_HTML::table('', '', 'admin-primary-mbox-tbl striped');
1242
-        $registrations_to_apply_payment_to .= EEH_HTML::thead(
1243
-            EEH_HTML::tr(
1244
-                EEH_HTML::th(esc_html__('ID', 'event_espresso')) .
1245
-                EEH_HTML::th(esc_html__('Registrant', 'event_espresso')) .
1246
-                EEH_HTML::th(esc_html__('Ticket', 'event_espresso')) .
1247
-                EEH_HTML::th(esc_html__('Event', 'event_espresso')) .
1248
-                EEH_HTML::th(esc_html__('Paid', 'event_espresso'), '', 'txn-admin-payment-paid-td jst-cntr') .
1249
-                EEH_HTML::th(esc_html__('Owing', 'event_espresso'), '', 'txn-admin-payment-owing-td jst-cntr') .
1250
-                EEH_HTML::th(esc_html__('Apply', 'event_espresso'), '', 'jst-cntr')
1251
-            )
1252
-        );
1253
-        $registrations_to_apply_payment_to .= EEH_HTML::tbody();
1254
-        // get registrations for TXN
1255
-        $registrations         = $this->_transaction->registrations($query_params);
1256
-        $existing_reg_payments = $this->_template_args['existing_reg_payments'];
1257
-        foreach ($registrations as $registration) {
1258
-            if ($registration instanceof EE_Registration) {
1259
-                $attendee_name                     = $registration->attendee() instanceof EE_Attendee
1260
-                    ? $registration->attendee()->full_name()
1261
-                    : esc_html__('Unknown Attendee', 'event_espresso');
1262
-                $owing                             = $registration->final_price() - $registration->paid();
1263
-                $taxable                           = $registration->ticket()->taxable()
1264
-                    ? ' <span class="smaller-text lt-grey-text"> ' . esc_html__('+ tax', 'event_espresso') . '</span>'
1265
-                    : '';
1266
-                $checked                           = empty($existing_reg_payments)
1267
-                                                     || in_array($registration->ID(), $existing_reg_payments, true)
1268
-                    ? ' checked'
1269
-                    : '';
1270
-                $disabled                          = $registration->final_price() > 0
1271
-                    ? ''
1272
-                    : ' disabled';
1273
-                $registrations_to_apply_payment_to .= EEH_HTML::tr(
1274
-                    EEH_HTML::td($registration->ID()) .
1275
-                    EEH_HTML::td($attendee_name) .
1276
-                    EEH_HTML::td(
1277
-                        $registration->ticket()->name() . ' : ' . $registration->ticket()->pretty_price() . $taxable
1278
-                    ) .
1279
-                    EEH_HTML::td($registration->event_name()) .
1280
-                    EEH_HTML::td($registration->pretty_paid(), '', 'txn-admin-payment-paid-td jst-cntr') .
1281
-                    EEH_HTML::td(
1282
-                        EEH_Template::format_currency($owing),
1283
-                        '',
1284
-                        'txn-admin-payment-owing-td jst-cntr'
1285
-                    ) .
1286
-                    EEH_HTML::td(
1287
-                        '<input type="checkbox" value="' . $registration->ID()
1288
-                        . '" name="txn_admin_payment[registrations]"'
1289
-                        . $checked . $disabled . '>',
1290
-                        '',
1291
-                        'jst-cntr'
1292
-                    ),
1293
-                    'apply-payment-registration-row-' . $registration->ID()
1294
-                );
1295
-            }
1296
-        }
1297
-        $registrations_to_apply_payment_to                         .= EEH_HTML::tbodyx();
1298
-        $registrations_to_apply_payment_to                         .= EEH_HTML::tablex();
1299
-        $registrations_to_apply_payment_to                         .= EEH_HTML::divx();
1300
-        $registrations_to_apply_payment_to                         .= EEH_HTML::p(
1301
-            esc_html__(
1302
-                '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.',
1303
-                'event_espresso'
1304
-            ),
1305
-            '',
1306
-            'clear description'
1307
-        );
1308
-        $registrations_to_apply_payment_to                         .= EEH_HTML::divx();
1309
-        $this->_template_args['registrations_to_apply_payment_to'] = $registrations_to_apply_payment_to;
1310
-    }
1311
-
1312
-
1313
-    /**
1314
-     * _get_reg_status_selection
1315
-     *
1316
-     * @return void
1317
-     * @throws EE_Error
1318
-     * @todo   this will need to be adjusted either once MER comes along OR we move default reg status to tickets
1319
-     *         instead of events.
1320
-     * @access protected
1321
-     */
1322
-    protected function _get_reg_status_selection()
1323
-    {
1324
-        // first get all possible statuses
1325
-        $statuses = EEM_Registration::reg_status_array([], true);
1326
-        // let's add a "don't change" option.
1327
-        $status_array['NAN']                                 = esc_html__('Leave the Same', 'event_espresso');
1328
-        $status_array                                        = array_merge($status_array, $statuses);
1329
-        $this->_template_args['status_change_select']        = EEH_Form_Fields::select_input(
1330
-            'txn_reg_status_change[reg_status]',
1331
-            $status_array,
1332
-            'NAN',
1333
-            'id="txn-admin-payment-reg-status-inp"',
1334
-            'txn-reg-status-change-reg-status'
1335
-        );
1336
-        $this->_template_args['delete_status_change_select'] = EEH_Form_Fields::select_input(
1337
-            'delete_txn_reg_status_change[reg_status]',
1338
-            $status_array,
1339
-            'NAN',
1340
-            'delete-txn-admin-payment-reg-status-inp',
1341
-            'delete-txn-reg-status-change-reg-status'
1342
-        );
1343
-    }
1344
-
1345
-
1346
-    /**
1347
-     *    _get_payment_methods
1348
-     * Gets all the payment methods available generally, or the ones that are already
1349
-     * selected on these payments (in case their payment methods are no longer active).
1350
-     * Has the side-effect of updating the template args' payment_methods item
1351
-     *
1352
-     * @access private
1353
-     * @param EE_Payment[] to show on this page
1354
-     * @return void
1355
-     * @throws EE_Error
1356
-     * @throws InvalidArgumentException
1357
-     * @throws InvalidDataTypeException
1358
-     * @throws InvalidInterfaceException
1359
-     * @throws ReflectionException
1360
-     */
1361
-    private function _get_payment_methods($payments = [])
1362
-    {
1363
-        $payment_methods_of_payments = [];
1364
-        foreach ($payments as $payment) {
1365
-            if ($payment instanceof EE_Payment) {
1366
-                $payment_methods_of_payments[] = $payment->ID();
1367
-            }
1368
-        }
1369
-        if ($payment_methods_of_payments) {
1370
-            $query_args = [
1371
-                [
1372
-                    'OR*payment_method_for_payment' => [
1373
-                        'PMD_ID'    => ['IN', $payment_methods_of_payments],
1374
-                        'PMD_scope' => ['LIKE', '%' . EEM_Payment_Method::scope_admin . '%'],
1375
-                    ],
1376
-                ],
1377
-            ];
1378
-        } else {
1379
-            $query_args = [['PMD_scope' => ['LIKE', '%' . EEM_Payment_Method::scope_admin . '%']]];
1380
-        }
1381
-        $this->_template_args['payment_methods'] = EEM_Payment_Method::instance()->get_all($query_args);
1382
-    }
1383
-
1384
-
1385
-    /**
1386
-     * txn_attendees_meta_box
1387
-     *    generates HTML for the Attendees Transaction main meta box
1388
-     *
1389
-     * @access public
1390
-     * @param WP_Post $post
1391
-     * @param array   $metabox
1392
-     * @return void
1393
-     * @throws DomainException
1394
-     * @throws EE_Error
1395
-     * @throws InvalidArgumentException
1396
-     * @throws InvalidDataTypeException
1397
-     * @throws InvalidInterfaceException
1398
-     * @throws ReflectionException
1399
-     */
1400
-    public function txn_attendees_meta_box($post, $metabox = ['args' => []])
1401
-    {
1402
-        /** @noinspection NonSecureExtractUsageInspection */
1403
-        extract($metabox['args']);
1404
-        $this->_template_args['post']            = $post;
1405
-        $this->_template_args['event_attendees'] = [];
1406
-        // process items in cart
1407
-        $line_items = $this->_transaction->get_many_related(
1408
-            'Line_Item',
1409
-            [['LIN_type' => 'line-item']]
1410
-        );
1411
-        if (! empty($line_items)) {
1412
-            foreach ($line_items as $item) {
1413
-                if ($item instanceof EE_Line_Item) {
1414
-                    switch ($item->OBJ_type()) {
1415
-                        case 'Event':
1416
-                            break;
1417
-                        case 'Ticket':
1418
-                            $ticket = $item->ticket();
1419
-                            // right now we're only handling tickets here.
1420
-                            // Cause its expected that only tickets will have attendees right?
1421
-                            if (! $ticket instanceof EE_Ticket) {
1422
-                                break;
1423
-                            }
1424
-                            try {
1425
-                                $event_name = $ticket->get_event_name();
1426
-                            } catch (Exception $e) {
1427
-                                EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1428
-                                $event_name = esc_html__('Unknown Event', 'event_espresso');
1429
-                            }
1430
-                            $event_name   .= ' - ' . $item->name();
1431
-                            $ticket_price = EEH_Template::format_currency($item->unit_price());
1432
-                            // now get all of the registrations for this transaction that use this ticket
1433
-                            $registrations = $ticket->registrations(
1434
-                                [['TXN_ID' => $this->_transaction->ID()]]
1435
-                            );
1436
-                            foreach ($registrations as $registration) {
1437
-                                if (! $registration instanceof EE_Registration) {
1438
-                                    break;
1439
-                                }
1440
-                                $this->_template_args['event_attendees'][ $registration->ID() ]['STS_ID']
1441
-                                    = $registration->status_ID();
1442
-                                $this->_template_args['event_attendees'][ $registration->ID() ]['att_num']
1443
-                                    = $registration->count();
1444
-                                $this->_template_args['event_attendees'][ $registration->ID() ]['event_ticket_name']
1445
-                                    = $event_name;
1446
-                                $this->_template_args['event_attendees'][ $registration->ID() ]['ticket_price']
1447
-                                    = $ticket_price;
1448
-                                // attendee info
1449
-                                $attendee = $registration->get_first_related('Attendee');
1450
-                                if ($attendee instanceof EE_Attendee) {
1451
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['att_id']
1452
-                                        = $attendee->ID();
1453
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['attendee']
1454
-                                        = $attendee->full_name();
1455
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['email']
1456
-                                        = '<a href="mailto:' . $attendee->email() . '?subject=' . $event_name
1457
-                                          . esc_html__(
1458
-                                              ' Event',
1459
-                                              'event_espresso'
1460
-                                          )
1461
-                                          . '">' . $attendee->email() . '</a>';
1462
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['address']
1463
-                                        = EEH_Address::format($attendee, 'inline', false, false);
1464
-                                } else {
1465
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['att_id']   = '';
1466
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['attendee'] = '';
1467
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['email']    = '';
1468
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['address']  = '';
1469
-                                }
1470
-                            }
1471
-                            break;
1472
-                    }
1473
-                }
1474
-            }
1475
-
1476
-            $this->_template_args['transaction_form_url'] = add_query_arg(
1477
-                [
1478
-                    'action'  => 'edit_transaction',
1479
-                    'process' => 'attendees',
1480
-                ],
1481
-                TXN_ADMIN_URL
1482
-            );
1483
-            echo EEH_Template::display_template(
1484
-                TXN_TEMPLATE_PATH . 'txn_admin_details_main_meta_box_attendees.template.php',
1485
-                $this->_template_args,
1486
-                true
1487
-            );
1488
-        } else {
1489
-            printf(
1490
-                esc_html__(
1491
-                    '%1$sFor some reason, there are no attendees registered for this transaction. Likely the registration was abandoned in process.%2$s',
1492
-                    'event_espresso'
1493
-                ),
1494
-                '<p class="important-notice">',
1495
-                '</p>'
1496
-            );
1497
-        }
1498
-    }
1499
-
1500
-
1501
-    /**
1502
-     * txn_registrant_side_meta_box
1503
-     * generates HTML for the Edit Transaction side meta box
1504
-     *
1505
-     * @access public
1506
-     * @return void
1507
-     * @throws DomainException
1508
-     * @throws EE_Error
1509
-     * @throws InvalidArgumentException
1510
-     * @throws InvalidDataTypeException
1511
-     * @throws InvalidInterfaceException
1512
-     * @throws ReflectionException
1513
-     */
1514
-    public function txn_registrant_side_meta_box()
1515
-    {
1516
-        $primary_att = $this->_transaction->primary_registration() instanceof EE_Registration
1517
-            ? $this->_transaction->primary_registration()->get_first_related('Attendee')
1518
-            : null;
1519
-        if (! $primary_att instanceof EE_Attendee) {
1520
-            $this->_template_args['no_attendee_message'] = esc_html__(
1521
-                'There is no attached contact for this transaction.  The transaction either failed due to an error or was abandoned.',
1522
-                'event_espresso'
1523
-            );
1524
-            $primary_att                                 = EEM_Attendee::instance()->create_default_object();
1525
-        }
1526
-        $this->_template_args['ATT_ID']            = $primary_att->ID();
1527
-        $this->_template_args['prime_reg_fname']   = $primary_att->fname();
1528
-        $this->_template_args['prime_reg_lname']   = $primary_att->lname();
1529
-        $this->_template_args['prime_reg_email']   = $primary_att->email();
1530
-        $this->_template_args['prime_reg_phone']   = $primary_att->phone();
1531
-        $this->_template_args['edit_attendee_url'] = EE_Admin_Page::add_query_args_and_nonce(
1532
-            [
1533
-                'action' => 'edit_attendee',
1534
-                'post'   => $primary_att->ID(),
1535
-            ],
1536
-            REG_ADMIN_URL
1537
-        );
1538
-        // get formatted address for registrant
1539
-        $formatted_address                         = EEH_Address::format($primary_att);
1540
-        $formatted_address                         =
1541
-            $formatted_address !== '<div class="espresso-address-dv"><div></div></div>'
1542
-                ? $formatted_address
1543
-                : '';
1544
-        $this->_template_args['formatted_address'] = $formatted_address;
1545
-        echo EEH_Template::display_template(
1546
-            TXN_TEMPLATE_PATH . 'txn_admin_details_side_meta_box_registrant.template.php',
1547
-            $this->_template_args,
1548
-            true
1549
-        );
1550
-    }
1551
-
1552
-
1553
-    /**
1554
-     * txn_billing_info_side_meta_box
1555
-     *    generates HTML for the Edit Transaction side meta box
1556
-     *
1557
-     * @access public
1558
-     * @return void
1559
-     * @throws DomainException
1560
-     * @throws EE_Error
1561
-     * @throws ReflectionException
1562
-     */
1563
-    public function txn_billing_info_side_meta_box()
1564
-    {
1565
-        $this->_template_args['billing_form']     = $this->_transaction->billing_info();
1566
-        $this->_template_args['billing_form_url'] = add_query_arg(
1567
-            ['action' => 'edit_transaction', 'process' => 'billing'],
1568
-            TXN_ADMIN_URL
1569
-        );
1570
-
1571
-        $template_path = TXN_TEMPLATE_PATH . 'txn_admin_details_side_meta_box_billing_info.template.php';
1572
-        echo EEH_Template::display_template($template_path, $this->_template_args, true);
1573
-    }
1574
-
1575
-
1576
-    /**
1577
-     * apply_payments_or_refunds
1578
-     *    registers a payment or refund made towards a transaction
1579
-     *
1580
-     * @access public
1581
-     * @return void
1582
-     * @throws EE_Error
1583
-     * @throws InvalidArgumentException
1584
-     * @throws ReflectionException
1585
-     * @throws RuntimeException
1586
-     * @throws InvalidDataTypeException
1587
-     * @throws InvalidInterfaceException
1588
-     */
1589
-    public function apply_payments_or_refunds()
1590
-    {
1591
-        $valid_data = $this->_validate_payment_request_data();
1592
-        $has_access = $this->capabilities->current_user_can(
1593
-            'ee_edit_payments',
1594
-            'apply_payment_or_refund_from_registration_details'
1595
-        );
1596
-        $TXD_ID     = $this->request->getRequestParam('txn_admin_payment[TXN_ID]', 0, 'int');
1597
-        $amount     = 0;
1598
-        if (! empty($valid_data) && $has_access) {
1599
-            $PAY_ID = $valid_data['PAY_ID'];
1600
-            // save  the new payment
1601
-            $payment = $this->_create_payment_from_request_data($valid_data);
1602
-            $amount  = $payment->amount();
1603
-            // get the TXN for this payment
1604
-            $transaction = $payment->transaction();
1605
-            // verify transaction
1606
-            if ($transaction instanceof EE_Transaction) {
1607
-                // calculate_total_payments_and_update_status
1608
-                $this->_process_transaction_payments($transaction);
1609
-                $REG_IDs = $this->_get_REG_IDs_to_apply_payment_to($payment);
1610
-                $this->_remove_existing_registration_payments($payment, $PAY_ID);
1611
-                // apply payment to registrations (if applicable)
1612
-                if (! empty($REG_IDs)) {
1613
-                    $this->_update_registration_payments($transaction, $payment, $REG_IDs);
1614
-                    $this->_maybe_send_notifications();
1615
-                    // now process status changes for the same registrations
1616
-                    $this->_process_registration_status_change($transaction, $REG_IDs);
1617
-                }
1618
-                $this->_maybe_send_notifications($payment);
1619
-                // prepare to render page
1620
-                do_action(
1621
-                    'AHEE__Transactions_Admin_Page__apply_payments_or_refund__after_recording',
1622
-                    $transaction,
1623
-                    $payment
1624
-                );
1625
-            } else {
1626
-                EE_Error::add_error(
1627
-                    esc_html__(
1628
-                        'A valid Transaction for this payment could not be retrieved.',
1629
-                        'event_espresso'
1630
-                    ),
1631
-                    __FILE__,
1632
-                    __FUNCTION__,
1633
-                    __LINE__
1634
-                );
1635
-            }
1636
-        } elseif ($has_access) {
1637
-            EE_Error::add_error(
1638
-                esc_html__(
1639
-                    'The payment form data could not be processed. Please try again.',
1640
-                    'event_espresso'
1641
-                ),
1642
-                __FILE__,
1643
-                __FUNCTION__,
1644
-                __LINE__
1645
-            );
1646
-        } else {
1647
-            EE_Error::add_error(
1648
-                esc_html__(
1649
-                    'You do not have access to apply payments or refunds to a registration.',
1650
-                    'event_espresso'
1651
-                ),
1652
-                __FILE__,
1653
-                __FUNCTION__,
1654
-                __LINE__
1655
-            );
1656
-        }
1657
-        $query_args = [
1658
-            'page'   => 'espresso_transactions',
1659
-            'action' => 'view_transaction',
1660
-            'TXN_ID' => $TXD_ID,
1661
-        ];
1662
-
1663
-        $this->_redirect_after_action(
1664
-            ! EE_Error::has_error(),
1665
-            $amount > 0
1666
-                ? esc_html__('payment', 'event_espresso')
1667
-                : esc_html__('refund', 'event_espresso'),
1668
-            esc_html__('processed', 'event_espresso'),
1669
-            $query_args
1670
-        );
1671
-    }
1672
-
1673
-
1674
-    /**
1675
-     * _validate_payment_request_data
1676
-     *
1677
-     * @return array
1678
-     * @throws EE_Error
1679
-     * @throws InvalidArgumentException
1680
-     * @throws InvalidDataTypeException
1681
-     * @throws InvalidInterfaceException
1682
-     */
1683
-    protected function _validate_payment_request_data()
1684
-    {
1685
-        if (! $this->request->requestParamIsSet('txn_admin_payment')) {
1686
-            return [];
1687
-        }
1688
-        $payment_form = $this->_generate_payment_form_section();
1689
-        try {
1690
-            if ($payment_form->was_submitted()) {
1691
-                $payment_form->receive_form_submission();
1692
-                if (! $payment_form->is_valid()) {
1693
-                    $submission_error_messages = [];
1694
-                    foreach ($payment_form->get_validation_errors_accumulated() as $validation_error) {
1695
-                        if ($validation_error instanceof EE_Validation_Error) {
1696
-                            $form_input                  = $validation_error->get_form_section();
1697
-                            $submission_error_messages[] = sprintf(
1698
-                                _x('%s : %s', 'Form Section Name : Form Validation Error', 'event_espresso'),
1699
-                                $form_input instanceof EE_Form_Input_Base
1700
-                                    ? $form_input->html_label_text()
1701
-                                    : '',
1702
-                                $validation_error->getMessage()
1703
-                            );
1704
-                        }
1705
-                    }
1706
-                    EE_Error::add_error(
1707
-                        implode('<br />', $submission_error_messages),
1708
-                        __FILE__,
1709
-                        __FUNCTION__,
1710
-                        __LINE__
1711
-                    );
1712
-                    return [];
1713
-                }
1714
-            }
1715
-        } catch (EE_Error $e) {
1716
-            EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1717
-            return [];
1718
-        }
1719
-
1720
-        return $payment_form->valid_data();
1721
-    }
1722
-
1723
-
1724
-    /**
1725
-     * _generate_payment_form_section
1726
-     *
1727
-     * @return EE_Form_Section_Proper
1728
-     * @throws EE_Error
1729
-     */
1730
-    protected function _generate_payment_form_section()
1731
-    {
1732
-        return new EE_Form_Section_Proper(
1733
-            [
1734
-                'name'        => 'txn_admin_payment',
1735
-                'subsections' => [
1736
-                    'PAY_ID'          => new EE_Text_Input(
1737
-                        [
1738
-                            'default'               => 0,
1739
-                            'required'              => false,
1740
-                            'html_label_text'       => esc_html__('Payment ID', 'event_espresso'),
1741
-                            'validation_strategies' => [new EE_Int_Normalization()],
1742
-                        ]
1743
-                    ),
1744
-                    'TXN_ID'          => new EE_Text_Input(
1745
-                        [
1746
-                            'default'               => 0,
1747
-                            'required'              => true,
1748
-                            'html_label_text'       => esc_html__('Transaction ID', 'event_espresso'),
1749
-                            'validation_strategies' => [new EE_Int_Normalization()],
1750
-                        ]
1751
-                    ),
1752
-                    'type'            => new EE_Text_Input(
1753
-                        [
1754
-                            'default'               => 1,
1755
-                            'required'              => true,
1756
-                            'html_label_text'       => esc_html__('Payment or Refund', 'event_espresso'),
1757
-                            'validation_strategies' => [new EE_Int_Normalization()],
1758
-                        ]
1759
-                    ),
1760
-                    'amount'          => new EE_Text_Input(
1761
-                        [
1762
-                            'default'               => 0,
1763
-                            'required'              => true,
1764
-                            'html_label_text'       => esc_html__('Payment amount', 'event_espresso'),
1765
-                            'validation_strategies' => [new EE_Float_Normalization()],
1766
-                        ]
1767
-                    ),
1768
-                    'status'          => new EE_Text_Input(
1769
-                        [
1770
-                            'default'         => EEM_Payment::status_id_approved,
1771
-                            'required'        => true,
1772
-                            'html_label_text' => esc_html__('Payment status', 'event_espresso'),
1773
-                        ]
1774
-                    ),
1775
-                    'PMD_ID'          => new EE_Text_Input(
1776
-                        [
1777
-                            'default'               => 2,
1778
-                            'required'              => true,
1779
-                            'html_label_text'       => esc_html__('Payment Method', 'event_espresso'),
1780
-                            'validation_strategies' => [new EE_Int_Normalization()],
1781
-                        ]
1782
-                    ),
1783
-                    'date'            => new EE_Text_Input(
1784
-                        [
1785
-                            'default'         => time(),
1786
-                            'required'        => true,
1787
-                            'html_label_text' => esc_html__('Payment date', 'event_espresso'),
1788
-                        ]
1789
-                    ),
1790
-                    'txn_id_chq_nmbr' => new EE_Text_Input(
1791
-                        [
1792
-                            'default'               => '',
1793
-                            'required'              => false,
1794
-                            'html_label_text'       => esc_html__('Transaction or Cheque Number', 'event_espresso'),
1795
-                            'validation_strategies' => [
1796
-                                new EE_Max_Length_Validation_Strategy(
1797
-                                    esc_html__('Input too long', 'event_espresso'),
1798
-                                    100
1799
-                                ),
1800
-                            ],
1801
-                        ]
1802
-                    ),
1803
-                    'po_number'       => new EE_Text_Input(
1804
-                        [
1805
-                            'default'               => '',
1806
-                            'required'              => false,
1807
-                            'html_label_text'       => esc_html__('Purchase Order Number', 'event_espresso'),
1808
-                            'validation_strategies' => [
1809
-                                new EE_Max_Length_Validation_Strategy(
1810
-                                    esc_html__('Input too long', 'event_espresso'),
1811
-                                    100
1812
-                                ),
1813
-                            ],
1814
-                        ]
1815
-                    ),
1816
-                    'accounting'      => new EE_Text_Input(
1817
-                        [
1818
-                            'default'               => '',
1819
-                            'required'              => false,
1820
-                            'html_label_text'       => esc_html__('Extra Field for Accounting', 'event_espresso'),
1821
-                            'validation_strategies' => [
1822
-                                new EE_Max_Length_Validation_Strategy(
1823
-                                    esc_html__('Input too long', 'event_espresso'),
1824
-                                    100
1825
-                                ),
1826
-                            ],
1827
-                        ]
1828
-                    ),
1829
-                ],
1830
-            ]
1831
-        );
1832
-    }
1833
-
1834
-
1835
-    /**
1836
-     * _create_payment_from_request_data
1837
-     *
1838
-     * @param array $valid_data
1839
-     * @return EE_Payment
1840
-     * @throws EE_Error
1841
-     * @throws InvalidArgumentException
1842
-     * @throws InvalidDataTypeException
1843
-     * @throws InvalidInterfaceException
1844
-     * @throws ReflectionException
1845
-     */
1846
-    protected function _create_payment_from_request_data($valid_data)
1847
-    {
1848
-        $PAY_ID = $valid_data['PAY_ID'];
1849
-        // get payment amount
1850
-        $amount = $valid_data['amount']
1851
-            ? abs($valid_data['amount'])
1852
-            : 0;
1853
-        // payments have a type value of 1 and refunds have a type value of -1
1854
-        // so multiplying amount by type will give a positive value for payments, and negative values for refunds
1855
-        $amount = $valid_data['type'] < 0
1856
-            ? $amount * -1
1857
-            : $amount;
1858
-        // for some reason the date string coming in has extra spaces between the date and time.  This fixes that.
1859
-        $date    = $valid_data['date']
1860
-            ? preg_replace('/\s+/', ' ', $valid_data['date'])
1861
-            : date('Y-m-d g:i a', current_time('timestamp'));
1862
-        $payment = EE_Payment::new_instance(
1863
-            [
1864
-                'TXN_ID'              => $valid_data['TXN_ID'],
1865
-                'STS_ID'              => $valid_data['status'],
1866
-                'PAY_timestamp'       => $date,
1867
-                'PAY_source'          => EEM_Payment_Method::scope_admin,
1868
-                'PMD_ID'              => $valid_data['PMD_ID'],
1869
-                'PAY_amount'          => $amount,
1870
-                'PAY_txn_id_chq_nmbr' => $valid_data['txn_id_chq_nmbr'],
1871
-                'PAY_po_number'       => $valid_data['po_number'],
1872
-                'PAY_extra_accntng'   => $valid_data['accounting'],
1873
-                'PAY_details'         => $valid_data,
1874
-                'PAY_ID'              => $PAY_ID,
1875
-            ],
1876
-            '',
1877
-            ['Y-m-d', 'g:i a']
1878
-        );
1879
-
1880
-        if (! $payment->save()) {
1881
-            EE_Error::add_error(
1882
-                sprintf(
1883
-                    esc_html__('Payment %1$d has not been successfully saved to the database.', 'event_espresso'),
1884
-                    $payment->ID()
1885
-                ),
1886
-                __FILE__,
1887
-                __FUNCTION__,
1888
-                __LINE__
1889
-            );
1890
-        }
1891
-
1892
-        return $payment;
1893
-    }
1894
-
1895
-
1896
-    /**
1897
-     * _process_transaction_payments
1898
-     *
1899
-     * @param EE_Transaction $transaction
1900
-     * @return void
1901
-     * @throws EE_Error
1902
-     * @throws InvalidArgumentException
1903
-     * @throws ReflectionException
1904
-     * @throws InvalidDataTypeException
1905
-     * @throws InvalidInterfaceException
1906
-     */
1907
-    protected function _process_transaction_payments(EE_Transaction $transaction)
1908
-    {
1909
-        /** @type EE_Transaction_Payments $transaction_payments */
1910
-        $transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
1911
-        // update the transaction with this payment
1912
-        if ($transaction_payments->calculate_total_payments_and_update_status($transaction)) {
1913
-            EE_Error::add_success(
1914
-                esc_html__(
1915
-                    'The payment has been processed successfully.',
1916
-                    'event_espresso'
1917
-                ),
1918
-                __FILE__,
1919
-                __FUNCTION__,
1920
-                __LINE__
1921
-            );
1922
-        } else {
1923
-            EE_Error::add_error(
1924
-                esc_html__(
1925
-                    'The payment was processed successfully but the amount paid for the transaction was not updated.',
1926
-                    'event_espresso'
1927
-                ),
1928
-                __FILE__,
1929
-                __FUNCTION__,
1930
-                __LINE__
1931
-            );
1932
-        }
1933
-    }
1934
-
1935
-
1936
-    /**
1937
-     * _get_REG_IDs_to_apply_payment_to
1938
-     * returns a list of registration IDs that the payment will apply to
1939
-     *
1940
-     * @param EE_Payment $payment
1941
-     * @return array
1942
-     * @throws EE_Error
1943
-     * @throws InvalidArgumentException
1944
-     * @throws InvalidDataTypeException
1945
-     * @throws InvalidInterfaceException
1946
-     * @throws ReflectionException
1947
-     */
1948
-    protected function _get_REG_IDs_to_apply_payment_to(EE_Payment $payment)
1949
-    {
1950
-        // grab array of IDs for specific registrations to apply changes to
1951
-        $apply_to_all = $this->request->getRequestParam(
1952
-            'txn_admin_payment[apply_to_all_registrations]',
1953
-            false,
1954
-            DataType::BOOL
1955
-        );
1956
-        $REG_IDs      = ! $apply_to_all
1957
-            ? $this->request->getRequestParam(
1958
-                'txn_admin_payment[registrations]',
1959
-                [],
1960
-                DataType::INT,
1961
-                true
1962
-            )
1963
-            : [];
1964
-        // nothing specified ? then get all reg IDs
1965
-        if ($apply_to_all || empty($REG_IDs)) {
1966
-            $registrations = $payment->transaction()->registrations(
1967
-                [
1968
-                    [
1969
-                        'STS_ID' => [
1970
-                            'NOT_IN', [ EEM_Registration::status_id_cancelled ]
1971
-                        ]
1972
-                    ]
1973
-                ]
1974
-            );
1975
-            $REG_IDs       = ! empty($registrations)
1976
-                ? array_keys($registrations)
1977
-                : $this->_get_existing_reg_payment_REG_IDs($payment);
1978
-        }
1979
-        // ensure that REG_IDs are integers and NOT strings
1980
-        return array_map('absint', $REG_IDs);
1981
-    }
1982
-
1983
-
1984
-    /**
1985
-     * @return array
1986
-     */
1987
-    public function existing_reg_payment_REG_IDs()
1988
-    {
1989
-        return $this->_existing_reg_payment_REG_IDs;
1990
-    }
1991
-
1992
-
1993
-    /**
1994
-     * @param array $existing_reg_payment_REG_IDs
1995
-     */
1996
-    public function set_existing_reg_payment_REG_IDs($existing_reg_payment_REG_IDs = null)
1997
-    {
1998
-        $this->_existing_reg_payment_REG_IDs = $existing_reg_payment_REG_IDs;
1999
-    }
2000
-
2001
-
2002
-    /**
2003
-     * _get_existing_reg_payment_REG_IDs
2004
-     * returns a list of registration IDs that the payment is currently related to
2005
-     * as recorded in the database
2006
-     *
2007
-     * @param EE_Payment $payment
2008
-     * @return array
2009
-     * @throws EE_Error
2010
-     * @throws InvalidArgumentException
2011
-     * @throws InvalidDataTypeException
2012
-     * @throws InvalidInterfaceException
2013
-     * @throws ReflectionException
2014
-     */
2015
-    protected function _get_existing_reg_payment_REG_IDs(EE_Payment $payment)
2016
-    {
2017
-        if ($this->existing_reg_payment_REG_IDs() === null) {
2018
-            // let's get any existing reg payment records for this payment
2019
-            $existing_reg_payment_REG_IDs = $payment->get_many_related('Registration');
2020
-            // but we only want the REG IDs, so grab the array keys
2021
-            $existing_reg_payment_REG_IDs = ! empty($existing_reg_payment_REG_IDs)
2022
-                ? array_keys($existing_reg_payment_REG_IDs)
2023
-                : [];
2024
-            $this->set_existing_reg_payment_REG_IDs($existing_reg_payment_REG_IDs);
2025
-        }
2026
-
2027
-        return $this->existing_reg_payment_REG_IDs();
2028
-    }
2029
-
2030
-
2031
-    /**
2032
-     * _remove_existing_registration_payments
2033
-     * this calculates the difference between existing relations
2034
-     * to the supplied payment and the new list registration IDs,
2035
-     * removes any related registrations that no longer apply,
2036
-     * and then updates the registration paid fields
2037
-     *
2038
-     * @param EE_Payment $payment
2039
-     * @param int        $PAY_ID
2040
-     * @return bool;
2041
-     * @throws EE_Error
2042
-     * @throws InvalidArgumentException
2043
-     * @throws ReflectionException
2044
-     * @throws InvalidDataTypeException
2045
-     * @throws InvalidInterfaceException
2046
-     */
2047
-    protected function _remove_existing_registration_payments(EE_Payment $payment, $PAY_ID = 0)
2048
-    {
2049
-        // newly created payments will have nothing recorded for $PAY_ID
2050
-        if (absint($PAY_ID) === 0) {
2051
-            return false;
2052
-        }
2053
-        $existing_reg_payment_REG_IDs = $this->_get_existing_reg_payment_REG_IDs($payment);
2054
-        if (empty($existing_reg_payment_REG_IDs)) {
2055
-            return false;
2056
-        }
2057
-        /** @type EE_Transaction_Payments $transaction_payments */
2058
-        $transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
2059
-
2060
-        return $transaction_payments->delete_registration_payments_and_update_registrations(
2061
-            $payment,
2062
-            [
2063
-                [
2064
-                    'PAY_ID' => $payment->ID(),
2065
-                    'REG_ID' => ['IN', $existing_reg_payment_REG_IDs],
2066
-                ],
2067
-            ]
2068
-        );
2069
-    }
2070
-
2071
-
2072
-    /**
2073
-     * _update_registration_payments
2074
-     * this applies the payments to the selected registrations
2075
-     * but only if they have not already been paid for
2076
-     *
2077
-     * @param EE_Transaction $transaction
2078
-     * @param EE_Payment     $payment
2079
-     * @param array          $REG_IDs
2080
-     * @return void
2081
-     * @throws EE_Error
2082
-     * @throws InvalidArgumentException
2083
-     * @throws ReflectionException
2084
-     * @throws RuntimeException
2085
-     * @throws InvalidDataTypeException
2086
-     * @throws InvalidInterfaceException
2087
-     */
2088
-    protected function _update_registration_payments(
2089
-        EE_Transaction $transaction,
2090
-        EE_Payment $payment,
2091
-        $REG_IDs = []
2092
-    ) {
2093
-        // we can pass our own custom set of registrations to EE_Payment_Processor::process_registration_payments()
2094
-        // so let's do that using our set of REG_IDs from the form
2095
-        $registration_query_where_params = [
2096
-            'REG_ID' => ['IN', $REG_IDs],
2097
-        ];
2098
-        // but add in some conditions regarding payment,
2099
-        // so that we don't apply payments to registrations that are free or have already been paid for
2100
-        // but ONLY if the payment is NOT a refund ( ie: the payment amount is not negative )
2101
-        if (! $payment->is_a_refund()) {
2102
-            $registration_query_where_params['REG_final_price']  = ['!=', 0];
2103
-            $registration_query_where_params['REG_final_price*'] = ['!=', 'REG_paid', true];
2104
-        }
2105
-        $registrations = $transaction->registrations([$registration_query_where_params]);
2106
-        if (! empty($registrations)) {
2107
-            /** @type EE_Payment_Processor $payment_processor */
2108
-            $payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
2109
-            $payment_processor->process_registration_payments($transaction, $payment, $registrations);
2110
-        }
2111
-    }
2112
-
2113
-
2114
-    /**
2115
-     * _process_registration_status_change
2116
-     * This processes requested registration status changes for all the registrations
2117
-     * on a given transaction and (optionally) sends out notifications for the changes.
2118
-     *
2119
-     * @param EE_Transaction $transaction
2120
-     * @param array          $REG_IDs
2121
-     * @return bool
2122
-     * @throws EE_Error
2123
-     * @throws InvalidArgumentException
2124
-     * @throws ReflectionException
2125
-     * @throws InvalidDataTypeException
2126
-     * @throws InvalidInterfaceException
2127
-     */
2128
-    protected function _process_registration_status_change(EE_Transaction $transaction, $REG_IDs = [], $reg_status = '')
2129
-    {
2130
-        // first if there is no change in status then we get out.
2131
-        $reg_status = $reg_status
2132
-            ?: $this->request->getRequestParam('txn_reg_status_change[reg_status]', 'NAN');
2133
-        if ($reg_status === 'NAN') {
2134
-            // no error message, no change requested, just nothing to do man.
2135
-            return false;
2136
-        }
2137
-        /** @type EE_Transaction_Processor $transaction_processor */
2138
-        $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
2139
-
2140
-        // made it here dude?  Oh WOW.  K, let's take care of changing the statuses
2141
-        return $transaction_processor->manually_update_registration_statuses(
2142
-            $transaction,
2143
-            $reg_status,
2144
-            [['REG_ID' => ['IN', $REG_IDs]]]
2145
-        );
2146
-    }
2147
-
2148
-
2149
-    /**
2150
-     * _build_payment_json_response
2151
-     *
2152
-     * @access public
2153
-     * @param EE_Payment  $payment
2154
-     * @param array       $REG_IDs
2155
-     * @param bool | null $delete_txn_reg_status_change
2156
-     * @return array
2157
-     * @throws EE_Error
2158
-     * @throws InvalidArgumentException
2159
-     * @throws InvalidDataTypeException
2160
-     * @throws InvalidInterfaceException
2161
-     * @throws ReflectionException
2162
-     */
2163
-    protected function _build_payment_json_response(
2164
-        EE_Payment $payment,
2165
-        $REG_IDs = [],
2166
-        $delete_txn_reg_status_change = null
2167
-    ) {
2168
-        // was the payment deleted ?
2169
-        if (is_bool($delete_txn_reg_status_change)) {
2170
-            return [
2171
-                'PAY_ID'                       => $payment->ID(),
2172
-                'amount'                       => $payment->amount(),
2173
-                'total_paid'                   => $payment->transaction()->paid(),
2174
-                'txn_status'                   => $payment->transaction()->status_ID(),
2175
-                'pay_status'                   => $payment->STS_ID(),
2176
-                'registrations'                => $this->_registration_payment_data_array($REG_IDs),
2177
-                'delete_txn_reg_status_change' => $delete_txn_reg_status_change,
2178
-            ];
2179
-        }
2180
-
2181
-        $this->_get_payment_status_array();
2182
-        $payment_method = $payment->payment_method();
2183
-        return [
2184
-            'amount'           => $payment->amount(),
2185
-            'total_paid'       => $payment->transaction()->paid(),
2186
-            'txn_status'       => $payment->transaction()->status_ID(),
2187
-            'pay_status'       => $payment->STS_ID(),
2188
-            'PAY_ID'           => $payment->ID(),
2189
-            'STS_ID'           => $payment->STS_ID(),
2190
-            'status'           => self::$_pay_status[ $payment->STS_ID() ],
2191
-            'date'             => $payment->timestamp('Y-m-d', 'h:i a'),
2192
-            'method'           => strtoupper($payment->source()),
2193
-            'PM_ID'            => $payment_method instanceof EE_Payment_Method
2194
-                ? $payment_method->ID()
2195
-                : 1,
2196
-            'gateway'          => $payment_method instanceof EE_Payment_Method
2197
-                ? $payment_method->admin_name()
2198
-                : esc_html__('Unknown', 'event_espresso'),
2199
-            'gateway_response' => $payment->gateway_response(),
2200
-            'txn_id_chq_nmbr'  => $payment->txn_id_chq_nmbr(),
2201
-            'po_number'        => $payment->po_number(),
2202
-            'extra_accntng'    => $payment->extra_accntng(),
2203
-            'registrations'    => $this->_registration_payment_data_array($REG_IDs),
2204
-        ];
2205
-    }
2206
-
2207
-
2208
-    /**
2209
-     * delete_payment
2210
-     *    delete a payment or refund made towards a transaction
2211
-     *
2212
-     * @access public
2213
-     * @return void
2214
-     * @throws EE_Error
2215
-     * @throws InvalidArgumentException
2216
-     * @throws ReflectionException
2217
-     * @throws InvalidDataTypeException
2218
-     * @throws InvalidInterfaceException
2219
-     */
2220
-    public function delete_payment()
2221
-    {
2222
-        $TXD_ID = $this->request->getRequestParam('delete_txn_admin_payment[TXN_ID]', 0, 'int');
2223
-        // $json_response_data = ['return_data' => false];
2224
-        $PAY_ID     = $this->request->getRequestParam('delete_txn_admin_payment[PAY_ID]', 0, 'int');
2225
-        $amount     = 0;
2226
-        $can_delete = $this->capabilities->current_user_can(
2227
-            'ee_delete_payments',
2228
-            'delete_payment_from_registration_details'
2229
-        );
2230
-        if ($PAY_ID && $can_delete) {
2231
-            $delete_txn_reg_status_change = $this->request->getRequestParam('delete_txn_reg_status_change[reg_status]');
2232
-            $payment                      = EEM_Payment::instance()->get_one_by_ID($PAY_ID);
2233
-            if ($payment instanceof EE_Payment) {
2234
-                $amount  = $payment->amount();
2235
-                $REG_IDs = $this->_get_existing_reg_payment_REG_IDs($payment);
2236
-                /** @type EE_Transaction_Payments $transaction_payments */
2237
-                $transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
2238
-                if ($transaction_payments->delete_payment_and_update_transaction($payment)) {
2239
-                    if ($delete_txn_reg_status_change) {
2240
-                        $this->_maybe_send_notifications();
2241
-                        $this->_process_registration_status_change(
2242
-                            $payment->transaction(),
2243
-                            $REG_IDs,
2244
-                            $delete_txn_reg_status_change
2245
-                        );
2246
-                    }
2247
-                }
2248
-            } else {
2249
-                EE_Error::add_error(
2250
-                    esc_html__('Valid Payment data could not be retrieved from the database.', 'event_espresso'),
2251
-                    __FILE__,
2252
-                    __FUNCTION__,
2253
-                    __LINE__
2254
-                );
2255
-            }
2256
-        } elseif ($can_delete) {
2257
-            EE_Error::add_error(
2258
-                esc_html__(
2259
-                    'A valid Payment ID was not received, therefore payment form data could not be loaded.',
2260
-                    'event_espresso'
2261
-                ),
2262
-                __FILE__,
2263
-                __FUNCTION__,
2264
-                __LINE__
2265
-            );
2266
-        } else {
2267
-            EE_Error::add_error(
2268
-                esc_html__(
2269
-                    'You do not have access to delete a payment.',
2270
-                    'event_espresso'
2271
-                ),
2272
-                __FILE__,
2273
-                __FUNCTION__,
2274
-                __LINE__
2275
-            );
2276
-        }
2277
-        $query_args = [
2278
-            'page'   => 'espresso_transactions',
2279
-            'action' => 'view_transaction',
2280
-            'TXN_ID' => $TXD_ID,
2281
-        ];
2282
-        $this->_redirect_after_action(
2283
-            ! EE_Error::has_error(),
2284
-            $amount > 0
2285
-                ? esc_html__('payment', 'event_espresso')
2286
-                : esc_html__('refund', 'event_espresso'),
2287
-            esc_html__('deleted', 'event_espresso'),
2288
-            $query_args
2289
-        );
2290
-    }
2291
-
2292
-
2293
-    /**
2294
-     * _registration_payment_data_array
2295
-     * adds info for 'owing' and 'paid' for each registration to the json response
2296
-     *
2297
-     * @access protected
2298
-     * @param array $REG_IDs
2299
-     * @return array
2300
-     * @throws EE_Error
2301
-     * @throws InvalidArgumentException
2302
-     * @throws InvalidDataTypeException
2303
-     * @throws InvalidInterfaceException
2304
-     * @throws ReflectionException
2305
-     */
2306
-    protected function _registration_payment_data_array($REG_IDs)
2307
-    {
2308
-        $registration_payment_data = [];
2309
-        // if non empty reg_ids lets get an array of registrations and update the values for the apply_payment/refund rows.
2310
-        if (! empty($REG_IDs)) {
2311
-            $registrations = EEM_Registration::instance()->get_all([['REG_ID' => ['IN', $REG_IDs]]]);
2312
-            foreach ($registrations as $registration) {
2313
-                if ($registration instanceof EE_Registration) {
2314
-                    $registration_payment_data[ $registration->ID() ] = [
2315
-                        'paid'  => $registration->pretty_paid(),
2316
-                        'owing' => EEH_Template::format_currency($registration->final_price() - $registration->paid()),
2317
-                    ];
2318
-                }
2319
-            }
2320
-        }
2321
-
2322
-        return $registration_payment_data;
2323
-    }
2324
-
2325
-
2326
-    /**
2327
-     * _maybe_send_notifications
2328
-     * determines whether or not the admin has indicated that notifications should be sent.
2329
-     * If so, will toggle a filter switch for delivering registration notices.
2330
-     * If passed an EE_Payment object, then it will trigger payment notifications instead.
2331
-     *
2332
-     * @access protected
2333
-     * @param EE_Payment | null $payment
2334
-     */
2335
-    protected function _maybe_send_notifications($payment = null)
2336
-    {
2337
-        switch ($payment instanceof EE_Payment) {
2338
-            // payment notifications
2339
-            case true:
2340
-                if ($this->request->getRequestParam('txn_payments[send_notifications]', false, 'bool')) {
2341
-                    $this->_process_payment_notification($payment);
2342
-                }
2343
-                break;
2344
-            // registration notifications
2345
-            case false:
2346
-                if ($this->request->getRequestParam('txn_reg_status_change[send_notifications]', false, 'bool')) {
2347
-                    add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true');
2348
-                }
2349
-                break;
2350
-        }
2351
-    }
2352
-
2353
-
2354
-    /**
2355
-     * _send_payment_reminder
2356
-     *    generates HTML for the View Transaction Details Admin page
2357
-     *
2358
-     * @access protected
2359
-     * @return void
2360
-     * @throws EE_Error
2361
-     * @throws InvalidArgumentException
2362
-     * @throws InvalidDataTypeException
2363
-     * @throws InvalidInterfaceException
2364
-     */
2365
-    protected function _send_payment_reminder()
2366
-    {
2367
-        $TXN_ID      = $this->request->getRequestParam('TXN_ID', 0, 'int');
2368
-        $transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
2369
-        $redirect_to = $this->request->getRequestParam('redirect_to');
2370
-        $query_args  = $redirect_to
2371
-            ? ['action' => $redirect_to, 'TXN_ID' => $TXN_ID,]
2372
-            : [];
2373
-        do_action(
2374
-            'AHEE__Transactions_Admin_Page___send_payment_reminder__process_admin_payment_reminder',
2375
-            $transaction
2376
-        );
2377
-        $this->_redirect_after_action(
2378
-            false,
2379
-            esc_html__('payment reminder', 'event_espresso'),
2380
-            esc_html__('sent', 'event_espresso'),
2381
-            $query_args,
2382
-            true
2383
-        );
2384
-    }
2385
-
2386
-
2387
-    /**
2388
-     *  get_transactions
2389
-     *    get transactions for given parameters (used by list table)
2390
-     *
2391
-     * @param int     $per_page how many transactions displayed per page
2392
-     * @param boolean $count    return the count or objects
2393
-     * @param string  $view
2394
-     * @return EE_Transaction[]|int int = count || array of transaction objects
2395
-     * @throws EE_Error
2396
-     * @throws InvalidArgumentException
2397
-     * @throws InvalidDataTypeException
2398
-     * @throws InvalidInterfaceException
2399
-     * @throws ReflectionException
2400
-     */
2401
-    public function get_transactions($per_page, $count = false, $view = '')
2402
-    {
2403
-        $start_date = wp_strip_all_tags(
2404
-            $this->request->getRequestParam('txn-filter-start-date', date('m/d/Y', strtotime('-10 year')))
2405
-        );
2406
-        $end_date   = wp_strip_all_tags(
2407
-            $this->request->getRequestParam('txn-filter-end-date', date('m/d/Y'))
2408
-        );
2409
-
2410
-        // make sure our timestamps start and end right at the boundaries for each day
2411
-        $start_date = date('Y-m-d', strtotime($start_date)) . ' 00:00:00';
2412
-        $end_date   = date('Y-m-d', strtotime($end_date)) . ' 23:59:59';
2413
-
2414
-
2415
-        // convert to timestamps
2416
-        $start_date = strtotime($start_date);
2417
-        $end_date   = strtotime($end_date);
2418
-
2419
-        // makes sure start date is the lowest value and vice versa
2420
-        $start_date = min($start_date, $end_date);
2421
-        $end_date   = max($start_date, $end_date);
2422
-
2423
-        // convert to correct format for query
2424
-        $start_date = EEM_Transaction::instance()->convert_datetime_for_query(
2425
-            'TXN_timestamp',
2426
-            date('Y-m-d H:i:s', $start_date),
2427
-            'Y-m-d H:i:s'
2428
-        );
2429
-        $end_date   = EEM_Transaction::instance()->convert_datetime_for_query(
2430
-            'TXN_timestamp',
2431
-            date('Y-m-d H:i:s', $end_date),
2432
-            'Y-m-d H:i:s'
2433
-        );
2434
-
2435
-
2436
-        // set orderby
2437
-        $orderby = $this->request->getRequestParam('orderby');
2438
-
2439
-        switch ($orderby) {
2440
-            case 'TXN_ID':
2441
-                break;
2442
-            case 'ATT_fname':
2443
-                $orderby = 'Registration.Attendee.ATT_fname';
2444
-                break;
2445
-            case 'event_name':
2446
-                $orderby = 'Registration.Event.EVT_name';
2447
-                break;
2448
-            default: // 'TXN_timestamp'
2449
-                $orderby = 'TXN_timestamp';
2450
-        }
2451
-
2452
-        $sort         = $this->request->getRequestParam('order', 'DESC');
2453
-        $current_page = $this->request->getRequestParam('paged', 1, 'int');
2454
-
2455
-        $per_page = absint($per_page)
2456
-            ? $per_page
2457
-            : 10;
2458
-        $per_page = $this->request->getRequestParam('perpage', $per_page, 'int');
2459
-
2460
-        $offset = ($current_page - 1) * $per_page;
2461
-        $limit  = [$offset, $per_page];
2462
-
2463
-        $_where = [
2464
-            'TXN_timestamp'          => ['BETWEEN', [$start_date, $end_date]],
2465
-            'Registration.REG_count' => 1,
2466
-        ];
2467
-
2468
-        $EVT_ID = $this->request->getRequestParam('EVT_ID', 0, 'int');
2469
-        if ($EVT_ID) {
2470
-            $_where['Registration.EVT_ID'] = $EVT_ID;
2471
-        }
2472
-
2473
-        $search_term = $this->request->getRequestParam('s');
2474
-        if ($search_term) {
2475
-            $search_term  = '%' . $search_term . '%';
2476
-            $_where['OR'] = [
2477
-                'Registration.Event.EVT_name'         => ['LIKE', $search_term],
2478
-                'Registration.Event.EVT_desc'         => ['LIKE', $search_term],
2479
-                'Registration.Event.EVT_short_desc'   => ['LIKE', $search_term],
2480
-                'Registration.Attendee.ATT_full_name' => ['LIKE', $search_term],
2481
-                'Registration.Attendee.ATT_fname'     => ['LIKE', $search_term],
2482
-                'Registration.Attendee.ATT_lname'     => ['LIKE', $search_term],
2483
-                'Registration.Attendee.ATT_short_bio' => ['LIKE', $search_term],
2484
-                'Registration.Attendee.ATT_email'     => ['LIKE', $search_term],
2485
-                'Registration.Attendee.ATT_address'   => ['LIKE', $search_term],
2486
-                'Registration.Attendee.ATT_address2'  => ['LIKE', $search_term],
2487
-                'Registration.Attendee.ATT_city'      => ['LIKE', $search_term],
2488
-                'Registration.REG_final_price'        => ['LIKE', $search_term],
2489
-                'Registration.REG_code'               => ['LIKE', $search_term],
2490
-                'Registration.REG_count'              => ['LIKE', $search_term],
2491
-                'Registration.REG_group_size'         => ['LIKE', $search_term],
2492
-                'Registration.Ticket.TKT_name'        => ['LIKE', $search_term],
2493
-                'Registration.Ticket.TKT_description' => ['LIKE', $search_term],
2494
-                'Payment.PAY_source'                  => ['LIKE', $search_term],
2495
-                'Payment.Payment_Method.PMD_name'     => ['LIKE', $search_term],
2496
-                'TXN_session_data'                    => ['LIKE', $search_term],
2497
-                'Payment.PAY_txn_id_chq_nmbr'         => ['LIKE', $search_term],
2498
-            ];
2499
-        }
2500
-
2501
-        $status = $this->request->getRequestParam('status');
2502
-        // failed transactions
2503
-        $failed     = (! empty($status) && $status === 'failed' && ! $count) || ($count && $view === 'failed');
2504
-        $abandoned  = (! empty($status) && $status === 'abandoned' && ! $count) || ($count && $view === 'abandoned');
2505
-        $incomplete = (! empty($status) && $status === 'incomplete' && ! $count) || ($count && $view === 'incomplete');
2506
-
2507
-        if ($failed) {
2508
-            $_where['STS_ID'] = EEM_Transaction::failed_status_code;
2509
-        } elseif ($abandoned) {
2510
-            $_where['STS_ID'] = EEM_Transaction::abandoned_status_code;
2511
-        } elseif ($incomplete) {
2512
-            $_where['STS_ID'] = EEM_Transaction::incomplete_status_code;
2513
-        } else {
2514
-            $_where['STS_ID']  = ['!=', EEM_Transaction::failed_status_code];
2515
-            $_where['STS_ID*'] = ['!=', EEM_Transaction::abandoned_status_code];
2516
-        }
2517
-
2518
-        $query_params = apply_filters(
2519
-            'FHEE__Transactions_Admin_Page___get_transactions_query_params',
2520
-            [
2521
-                $_where,
2522
-                'order_by'                 => [$orderby => $sort],
2523
-                'limit'                    => $limit,
2524
-                'default_where_conditions' => EEM_Base::default_where_conditions_this_only,
2525
-            ],
2526
-            $this->request->requestParams(),
2527
-            $view,
2528
-            $count
2529
-        );
2530
-
2531
-        return $count
2532
-            ? EEM_Transaction::instance()->count([$query_params[0]], 'TXN_ID', true)
2533
-            : EEM_Transaction::instance()->get_all($query_params);
2534
-    }
2535
-
2536
-
2537
-    /**
2538
-     * @throws EE_Error
2539
-     * @throws InvalidArgumentException
2540
-     * @throws InvalidDataTypeException
2541
-     * @throws InvalidInterfaceException
2542
-     * @throws ReflectionException
2543
-     * @throws RuntimeException
2544
-     * @since 4.9.79.p
2545
-     */
2546
-    public function recalculateLineItems()
2547
-    {
2548
-        $TXN_ID = $this->request->getRequestParam('TXN_ID', 0, 'int');
2549
-        /** @var EE_Transaction $transaction */
2550
-        $transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
2551
-        $success     = $transaction->recalculateLineItems();
2552
-        $redirect_to = $this->request->getRequestParam('redirect_to');
2553
-        $query_args  = $redirect_to
2554
-            ? ['action' => $redirect_to, 'TXN_ID' => $TXN_ID,]
2555
-            : [];
2556
-        $this->_redirect_after_action(
2557
-            $success,
2558
-            esc_html__('Transaction taxes and totals', 'event_espresso'),
2559
-            esc_html__('recalculated', 'event_espresso'),
2560
-            $query_args,
2561
-            true
2562
-        );
2563
-    }
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
+	 * @throws ReflectionException
97
+	 */
98
+	public function _set_page_routes()
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
+	 * @throws ReflectionException
283
+	 */
284
+	private function _set_transaction_status_array()
285
+	{
286
+		self::$_txn_status = EEM_Transaction::instance()->status_array(true);
287
+	}
288
+
289
+
290
+	/**
291
+	 * get_transaction_status_array
292
+	 * return the transaction status array for wp_list_table
293
+	 *
294
+	 * @access public
295
+	 * @return array
296
+	 */
297
+	public function get_transaction_status_array()
298
+	{
299
+		return self::$_txn_status;
300
+	}
301
+
302
+
303
+	/**
304
+	 *    get list of payment statuses
305
+	 *
306
+	 * @access private
307
+	 * @return void
308
+	 * @throws EE_Error
309
+	 * @throws InvalidArgumentException
310
+	 * @throws InvalidDataTypeException
311
+	 * @throws InvalidInterfaceException
312
+	 * @throws ReflectionException
313
+	 */
314
+	private function _get_payment_status_array()
315
+	{
316
+		self::$_pay_status                      = EEM_Payment::instance()->status_array(true);
317
+		$this->_template_args['payment_status'] = self::$_pay_status;
318
+	}
319
+
320
+
321
+	/**
322
+	 *    _add_screen_options_default
323
+	 *
324
+	 * @access protected
325
+	 * @return void
326
+	 * @throws InvalidArgumentException
327
+	 * @throws InvalidDataTypeException
328
+	 * @throws InvalidInterfaceException
329
+	 */
330
+	protected function _add_screen_options_default()
331
+	{
332
+		$this->_per_page_screen_option();
333
+	}
334
+
335
+
336
+	/**
337
+	 * load_scripts_styles
338
+	 *
339
+	 * @access public
340
+	 * @return void
341
+	 */
342
+	public function load_scripts_styles()
343
+	{
344
+		// enqueue style
345
+		wp_register_style(
346
+			'espresso_txn',
347
+			TXN_ASSETS_URL . 'espresso_transactions_admin.css',
348
+			[],
349
+			EVENT_ESPRESSO_VERSION
350
+		);
351
+		wp_enqueue_style('espresso_txn');
352
+		// scripts
353
+		wp_register_script(
354
+			'espresso_txn',
355
+			TXN_ASSETS_URL . 'espresso_transactions_admin.js',
356
+			[
357
+				'ee_admin_js',
358
+				'ee-datepicker',
359
+				'jquery-ui-datepicker',
360
+				'jquery-ui-draggable',
361
+				'ee-dialog',
362
+				'ee-accounting',
363
+				'ee-serialize-full-array',
364
+			],
365
+			EVENT_ESPRESSO_VERSION,
366
+			true
367
+		);
368
+		wp_enqueue_script('espresso_txn');
369
+	}
370
+
371
+
372
+	/**
373
+	 *    load_scripts_styles_view_transaction
374
+	 *
375
+	 * @access public
376
+	 * @return void
377
+	 */
378
+	public function load_scripts_styles_view_transaction()
379
+	{
380
+		// styles
381
+		wp_enqueue_style('espresso-ui-theme');
382
+	}
383
+
384
+
385
+	/**
386
+	 *    load_scripts_styles_default
387
+	 *
388
+	 * @access public
389
+	 * @return void
390
+	 */
391
+	public function load_scripts_styles_default()
392
+	{
393
+		// styles
394
+		wp_enqueue_style('espresso-ui-theme');
395
+	}
396
+
397
+
398
+	/**
399
+	 *    _set_list_table_views_default
400
+	 *
401
+	 * @access protected
402
+	 * @return void
403
+	 */
404
+	protected function _set_list_table_views_default()
405
+	{
406
+		$this->_views = [
407
+			'all'        => [
408
+				'slug'  => 'all',
409
+				'label' => esc_html__('View All Transactions', 'event_espresso'),
410
+				'count' => 0,
411
+			],
412
+			'abandoned'  => [
413
+				'slug'  => 'abandoned',
414
+				'label' => esc_html__('Abandoned Transactions', 'event_espresso'),
415
+				'count' => 0,
416
+			],
417
+			'incomplete' => [
418
+				'slug'  => 'incomplete',
419
+				'label' => esc_html__('Incomplete Transactions', 'event_espresso'),
420
+				'count' => 0,
421
+			],
422
+		];
423
+		if (
424
+			/**
425
+			 * Filters whether a link to the "Failed Transactions" list table
426
+			 * appears on the Transactions Admin Page list table.
427
+			 * List display can be turned back on via the following:
428
+			 * add_filter(
429
+			 *     'FHEE__Transactions_Admin_Page___set_list_table_views_default__display_failed_txns_list',
430
+			 *     '__return_true'
431
+			 * );
432
+			 *
433
+			 * @param boolean                 $display_failed_txns_list
434
+			 * @param Transactions_Admin_Page $this
435
+			 * @since 4.9.70.p
436
+			 */
437
+		apply_filters(
438
+			'FHEE__Transactions_Admin_Page___set_list_table_views_default__display_failed_txns_list',
439
+			false,
440
+			$this
441
+		)
442
+		) {
443
+			$this->_views['failed'] = [
444
+				'slug'  => 'failed',
445
+				'label' => esc_html__('Failed Transactions', 'event_espresso'),
446
+				'count' => 0,
447
+			];
448
+		}
449
+	}
450
+
451
+
452
+	/**
453
+	 * _set_transaction_object
454
+	 * This sets the _transaction property for the transaction details screen
455
+	 *
456
+	 * @access private
457
+	 * @return void
458
+	 * @throws EE_Error
459
+	 * @throws InvalidArgumentException
460
+	 * @throws RuntimeException
461
+	 * @throws InvalidDataTypeException
462
+	 * @throws InvalidInterfaceException
463
+	 * @throws ReflectionException
464
+	 */
465
+	private function _set_transaction_object()
466
+	{
467
+		if ($this->_transaction instanceof EE_Transaction) {
468
+			return;
469
+		} //get out we've already set the object
470
+
471
+		$TXN_ID = $this->request->getRequestParam('TXN_ID', 0, 'int');
472
+
473
+		// get transaction object
474
+		$this->_transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
475
+		$this->_session     = $this->_transaction instanceof EE_Transaction
476
+			? $this->_transaction->session_data()
477
+			: null;
478
+		if ($this->_transaction instanceof EE_Transaction) {
479
+			$this->_transaction->verify_abandoned_transaction_status();
480
+		}
481
+
482
+		if (! $this->_transaction instanceof EE_Transaction) {
483
+			$error_msg = sprintf(
484
+				esc_html__(
485
+					'An error occurred and the details for the transaction with the ID # %d could not be retrieved.',
486
+					'event_espresso'
487
+				),
488
+				$TXN_ID
489
+			);
490
+			EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
491
+		}
492
+	}
493
+
494
+
495
+	/**
496
+	 *    _transaction_legend_items
497
+	 *
498
+	 * @access protected
499
+	 * @return array
500
+	 * @throws EE_Error
501
+	 * @throws InvalidArgumentException
502
+	 * @throws ReflectionException
503
+	 * @throws InvalidDataTypeException
504
+	 * @throws InvalidInterfaceException
505
+	 */
506
+	protected function _transaction_legend_items()
507
+	{
508
+		EE_Registry::instance()->load_helper('MSG_Template');
509
+		$items = [];
510
+
511
+		if (
512
+			$this->capabilities->current_user_can(
513
+				'ee_read_global_messages',
514
+				'view_filtered_messages'
515
+			)
516
+		) {
517
+			$related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
518
+			if (
519
+				is_array($related_for_icon)
520
+				&& isset($related_for_icon['css_class'], $related_for_icon['label'])
521
+			) {
522
+				$items['view_related_messages'] = [
523
+					'class' => $related_for_icon['css_class'],
524
+					'desc'  => $related_for_icon['label'],
525
+				];
526
+			}
527
+		}
528
+
529
+		$items = apply_filters(
530
+			'FHEE__Transactions_Admin_Page___transaction_legend_items__items',
531
+			array_merge(
532
+				$items,
533
+				[
534
+					'view_details'          => [
535
+						'class' => 'dashicons dashicons-cart',
536
+						'desc'  => esc_html__('View Transaction Details', 'event_espresso'),
537
+					],
538
+					'view_invoice'          => [
539
+						'class' => 'dashicons dashicons-media-spreadsheet',
540
+						'desc'  => esc_html__('View Transaction Invoice', 'event_espresso'),
541
+					],
542
+					'view_receipt'          => [
543
+						'class' => 'dashicons dashicons-text-page',
544
+						'desc'  => esc_html__('View Transaction Receipt', 'event_espresso'),
545
+					],
546
+					'view_registration'     => [
547
+						'class' => 'dashicons dashicons-clipboard',
548
+						'desc'  => esc_html__('View Registration Details', 'event_espresso'),
549
+					],
550
+					'payment_overview_link' => [
551
+						'class' => 'dashicons dashicons-money',
552
+						'desc'  => esc_html__('Make Payment on Frontend', 'event_espresso'),
553
+					],
554
+				]
555
+			)
556
+		);
557
+
558
+		if (
559
+			EEH_MSG_Template::is_mt_active('payment_reminder')
560
+			&& $this->capabilities->current_user_can(
561
+				'ee_send_message',
562
+				'espresso_transactions_send_payment_reminder'
563
+			)
564
+		) {
565
+			$items['send_payment_reminder'] = [
566
+				'class' => 'dashicons dashicons-email-alt',
567
+				'desc'  => esc_html__('Send Payment Reminder', 'event_espresso'),
568
+			];
569
+		} else {
570
+			$items['blank*'] = [
571
+				'class' => '',
572
+				'desc'  => '',
573
+			];
574
+		}
575
+		$more_items = apply_filters(
576
+			'FHEE__Transactions_Admin_Page___transaction_legend_items__more_items',
577
+			[
578
+				'overpaid'   => [
579
+					'class' => 'ee-status-legend ee-status-bg--' . EEM_Transaction::overpaid_status_code,
580
+					'desc'  => EEH_Template::pretty_status(
581
+						EEM_Transaction::overpaid_status_code,
582
+						false,
583
+						'sentence'
584
+					),
585
+				],
586
+				'complete'   => [
587
+					'class' => 'ee-status-legend ee-status-bg--' . EEM_Transaction::complete_status_code,
588
+					'desc'  => EEH_Template::pretty_status(
589
+						EEM_Transaction::complete_status_code,
590
+						false,
591
+						'sentence'
592
+					),
593
+				],
594
+				'incomplete' => [
595
+					'class' => 'ee-status-legend ee-status-bg--' . EEM_Transaction::incomplete_status_code,
596
+					'desc'  => EEH_Template::pretty_status(
597
+						EEM_Transaction::incomplete_status_code,
598
+						false,
599
+						'sentence'
600
+					),
601
+				],
602
+				'abandoned'  => [
603
+					'class' => 'ee-status-legend ee-status-bg--' . EEM_Transaction::abandoned_status_code,
604
+					'desc'  => EEH_Template::pretty_status(
605
+						EEM_Transaction::abandoned_status_code,
606
+						false,
607
+						'sentence'
608
+					),
609
+				],
610
+				'failed'     => [
611
+					'class' => 'ee-status-legend ee-status-bg--' . EEM_Transaction::failed_status_code,
612
+					'desc'  => EEH_Template::pretty_status(
613
+						EEM_Transaction::failed_status_code,
614
+						false,
615
+						'sentence'
616
+					),
617
+				],
618
+			]
619
+		);
620
+
621
+		return array_merge($items, $more_items);
622
+	}
623
+
624
+
625
+	/**
626
+	 *    _transactions_overview_list_table
627
+	 *
628
+	 * @access protected
629
+	 * @return void
630
+	 * @throws DomainException
631
+	 * @throws EE_Error
632
+	 * @throws InvalidArgumentException
633
+	 * @throws InvalidDataTypeException
634
+	 * @throws InvalidInterfaceException
635
+	 * @throws ReflectionException
636
+	 */
637
+	protected function _transactions_overview_list_table()
638
+	{
639
+		$this->_admin_page_title = esc_html__('Transactions', 'event_espresso');
640
+
641
+		$EVT_ID                                    = $this->request->getRequestParam('EVT_ID', 0, 'int');
642
+		$event                                     = EEM_Event::instance()->get_one_by_ID($EVT_ID);
643
+		$this->_template_args['admin_page_header'] = $event instanceof EE_Event
644
+			? sprintf(
645
+				esc_html__('%sViewing Transactions for the Event: %s%s', 'event_espresso'),
646
+				'<h3>',
647
+				'<a href="'
648
+				. EE_Admin_Page::add_query_args_and_nonce(
649
+					['action' => 'edit', 'post' => $event->ID()],
650
+					EVENTS_ADMIN_URL
651
+				)
652
+				. '" aria-label="'
653
+				. esc_attr__('Click to Edit event', 'event_espresso')
654
+				. '">' . $event->name() . '</a>',
655
+				'</h3>'
656
+			)
657
+			: '';
658
+		$this->_template_args['after_list_table']  = $this->_display_legend($this->_transaction_legend_items());
659
+		$this->display_admin_list_table_page_with_no_sidebar();
660
+	}
661
+
662
+
663
+	/**
664
+	 *    _transaction_details
665
+	 * generates HTML for the View Transaction Details Admin page
666
+	 *
667
+	 * @access protected
668
+	 * @return void
669
+	 * @throws DomainException
670
+	 * @throws EE_Error
671
+	 * @throws InvalidArgumentException
672
+	 * @throws InvalidDataTypeException
673
+	 * @throws InvalidInterfaceException
674
+	 * @throws RuntimeException
675
+	 * @throws ReflectionException
676
+	 */
677
+	protected function _transaction_details()
678
+	{
679
+		do_action('AHEE__Transactions_Admin_Page__transaction_details__start', $this->_transaction);
680
+
681
+		$this->_set_transaction_status_array();
682
+
683
+		$this->_template_args                      = [];
684
+		$this->_template_args['transactions_page'] = $this->_wp_page_slug;
685
+
686
+		$this->_set_transaction_object();
687
+
688
+		if (! $this->_transaction instanceof EE_Transaction) {
689
+			return;
690
+		}
691
+
692
+		$this->_template_args['txn_nmbr']['value'] = $this->_transaction->ID();
693
+		$this->_template_args['txn_nmbr']['label'] = esc_html__('Transaction Number', 'event_espresso');
694
+
695
+		$this->_template_args['txn_datetime']['value'] = $this->_transaction->get_i18n_datetime('TXN_timestamp');
696
+		$this->_template_args['txn_datetime']['label'] = esc_html__('Date', 'event_espresso');
697
+
698
+		$this->_template_args['txn_status']['value'] = self::$_txn_status[ $this->_transaction->status_ID() ];
699
+		$this->_template_args['txn_status']['label'] = esc_html__('Transaction Status', 'event_espresso');
700
+		$this->_template_args['txn_status']['class'] = $this->_transaction->status_ID();
701
+
702
+		$txn_total  = $this->_transaction->total();
703
+		$total_paid = $this->_transaction->paid();
704
+		$amount_due = $txn_total - $total_paid;
705
+
706
+		$this->_template_args['grand_total'] = $txn_total;
707
+		$this->_template_args['total_paid']  = $total_paid;
708
+
709
+		$this->_template_args['amount_due']     = EEH_Template::format_currency($amount_due, false, false);
710
+		$this->_template_args['amount_due_raw'] = $amount_due;
711
+
712
+		$this->_template_args['amount_due_class'] = '';
713
+
714
+		if ($txn_total === (float) 0) {
715
+			// free event
716
+			$this->_template_args['amount_due'] = false;
717
+		} elseif ($amount_due < (float) 0) {
718
+			// overpaid
719
+			$this->_template_args['amount_due_class'] = 'txn-overview-no-payment-spn';
720
+		} elseif ($amount_due > (float) 0) {
721
+			// monies owing
722
+			$this->_template_args['amount_due_class'] = 'txn-overview-part-payment-spn ee-txn-amount-owing';
723
+		} elseif ($total_paid === (float) 0) {
724
+			// no payments made yet
725
+			$this->_template_args['amount_due_class'] = 'txn-overview-no-payment-spn';
726
+		}
727
+
728
+		$payment_method = $this->_transaction->payment_method();
729
+
730
+		$this->_template_args['method_of_payment_name'] = $payment_method instanceof EE_Payment_Method
731
+			? $payment_method->admin_name()
732
+			: esc_html__('Unknown', 'event_espresso');
733
+
734
+		$this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
735
+		// link back to overview
736
+		$this->_template_args['txn_overview_url'] = $this->request->getServerParam(
737
+			'HTTP_REFERER',
738
+			TXN_ADMIN_URL
739
+		);
740
+
741
+
742
+		// next link
743
+		$next_txn                                 = $this->_transaction->next(
744
+			null,
745
+			[['STS_ID' => ['!=', EEM_Transaction::failed_status_code]]],
746
+			'TXN_ID'
747
+		);
748
+		$this->_template_args['next_transaction'] = $next_txn
749
+			? $this->_next_link(
750
+				EE_Admin_Page::add_query_args_and_nonce(
751
+					['action' => 'view_transaction', 'TXN_ID' => $next_txn['TXN_ID']],
752
+					TXN_ADMIN_URL
753
+				),
754
+				'dashicons dashicons-arrow-right ee-icon-size-22'
755
+			)
756
+			: '';
757
+		// previous link
758
+		$previous_txn                                 = $this->_transaction->previous(
759
+			null,
760
+			[['STS_ID' => ['!=', EEM_Transaction::failed_status_code]]],
761
+			'TXN_ID'
762
+		);
763
+		$this->_template_args['previous_transaction'] = $previous_txn
764
+			? $this->_previous_link(
765
+				EE_Admin_Page::add_query_args_and_nonce(
766
+					['action' => 'view_transaction', 'TXN_ID' => $previous_txn['TXN_ID']],
767
+					TXN_ADMIN_URL
768
+				),
769
+				'dashicons dashicons-arrow-left ee-icon-size-22'
770
+			)
771
+			: '';
772
+
773
+		$EVT_ID        = $this->request->getRequestParam('EVT_ID', 0, 'int');
774
+		$event_name    = $this->request->getRequestParam('event_name');
775
+		$redirect_from = $this->request->getRequestParam('redirect_from', '', 'url');
776
+
777
+		// were we just redirected here after adding a new registration ???
778
+		if ($EVT_ID && $event_name && $redirect_from) {
779
+			if (
780
+				$this->capabilities->current_user_can(
781
+					'ee_edit_registrations',
782
+					'espresso_registrations_new_registration',
783
+					$EVT_ID
784
+				)
785
+			) {
786
+				$this->_admin_page_title .= '<a id="add-new-registration" class="add-new-h2 button--primary" href="';
787
+				$this->_admin_page_title .= EE_Admin_Page::add_query_args_and_nonce(
788
+					[
789
+						'page'     => 'espresso_registrations',
790
+						'action'   => 'new_registration',
791
+						'return'   => 'default',
792
+						'TXN_ID'   => $this->_transaction->ID(),
793
+						'event_id' => $EVT_ID,
794
+					],
795
+					REG_ADMIN_URL
796
+				);
797
+				$this->_admin_page_title .= '">';
798
+
799
+				$this->_admin_page_title .= sprintf(
800
+					esc_html__('Add Another New Registration to Event: "%1$s" ?', 'event_espresso'),
801
+					htmlentities(urldecode($event_name), ENT_QUOTES, 'UTF-8')
802
+				);
803
+				$this->_admin_page_title .= '</a>';
804
+			}
805
+			EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
806
+		}
807
+		// grab messages at the last second
808
+		$this->_template_args['notices'] = EE_Error::get_notices();
809
+		// path to template
810
+		$template_path                             = TXN_TEMPLATE_PATH . 'txn_admin_details_header.template.php';
811
+		$this->_template_args['admin_page_header'] = EEH_Template::display_template(
812
+			$template_path,
813
+			$this->_template_args,
814
+			true
815
+		);
816
+
817
+		// the details template wrapper
818
+		$this->display_admin_page_with_sidebar();
819
+	}
820
+
821
+
822
+	/**
823
+	 *        _transaction_details_metaboxes
824
+	 *
825
+	 * @access protected
826
+	 * @return void
827
+	 * @throws EE_Error
828
+	 * @throws InvalidArgumentException
829
+	 * @throws InvalidDataTypeException
830
+	 * @throws InvalidInterfaceException
831
+	 * @throws RuntimeException
832
+	 * @throws ReflectionException
833
+	 */
834
+	protected function _transaction_details_metaboxes()
835
+	{
836
+		$this->_set_transaction_object();
837
+
838
+		if (! $this->_transaction instanceof EE_Transaction) {
839
+			return;
840
+		}
841
+		$this->addMetaBox(
842
+			'edit-txn-details-mbox',
843
+			'<span>' . esc_html__('Transaction Details', 'event_espresso')
844
+			. '&nbsp;<span class="dashicons dashicons-cart" ></span></span>',
845
+			[$this, 'txn_details_meta_box'],
846
+			$this->_wp_page_slug
847
+		);
848
+		$this->addMetaBox(
849
+			'edit-txn-attendees-mbox',
850
+			'<span>' . esc_html__('Attendees Registered in this Transaction', 'event_espresso')
851
+			. '&nbsp;<span class="dashicons dashicons-groups" ></span></span>',
852
+			[$this, 'txn_attendees_meta_box'],
853
+			$this->_wp_page_slug,
854
+			'normal',
855
+			'high',
856
+			['TXN_ID' => $this->_transaction->ID()]
857
+		);
858
+		$this->addMetaBox(
859
+			'edit-txn-registrant-mbox',
860
+			esc_html__('Primary Contact', 'event_espresso'),
861
+			[$this, 'txn_registrant_side_meta_box'],
862
+			$this->_wp_page_slug,
863
+			'side'
864
+		);
865
+		$this->addMetaBox(
866
+			'edit-txn-billing-info-mbox',
867
+			esc_html__('Billing Information', 'event_espresso'),
868
+			[$this, 'txn_billing_info_side_meta_box'],
869
+			$this->_wp_page_slug,
870
+			'side'
871
+		);
872
+	}
873
+
874
+
875
+	/**
876
+	 * Callback for transaction actions metabox.
877
+	 *
878
+	 * @param EE_Transaction|null $transaction
879
+	 * @return string
880
+	 * @throws DomainException
881
+	 * @throws EE_Error
882
+	 * @throws InvalidArgumentException
883
+	 * @throws InvalidDataTypeException
884
+	 * @throws InvalidInterfaceException
885
+	 * @throws ReflectionException
886
+	 * @throws RuntimeException
887
+	 */
888
+	public function getActionButtons(EE_Transaction $transaction = null)
889
+	{
890
+		$content = '';
891
+		$actions = [];
892
+		if (! $transaction instanceof EE_Transaction) {
893
+			return $content;
894
+		}
895
+		/** @var EE_Registration $primary_registration */
896
+		$primary_registration = $transaction->primary_registration();
897
+		$attendee             = $primary_registration instanceof EE_Registration
898
+			? $primary_registration->attendee()
899
+			: null;
900
+
901
+		if (
902
+			$attendee instanceof EE_Attendee
903
+			&& $this->capabilities->current_user_can(
904
+				'ee_send_message',
905
+				'espresso_transactions_send_payment_reminder'
906
+			)
907
+		) {
908
+			$actions['payment_reminder'] =
909
+				EEH_MSG_Template::is_mt_active('payment_reminder')
910
+				&& $this->_transaction->status_ID() !== EEM_Transaction::complete_status_code
911
+				&& $this->_transaction->status_ID() !== EEM_Transaction::overpaid_status_code
912
+					? EEH_Template::get_button_or_link(
913
+					EE_Admin_Page::add_query_args_and_nonce(
914
+						[
915
+							'action'      => 'send_payment_reminder',
916
+							'TXN_ID'      => $this->_transaction->ID(),
917
+							'redirect_to' => 'view_transaction',
918
+						],
919
+						TXN_ADMIN_URL
920
+					),
921
+					esc_html__(' Send Payment Reminder', 'event_espresso'),
922
+					'button button--secondary',
923
+					'dashicons dashicons-email-alt'
924
+				)
925
+					: '';
926
+		}
927
+
928
+		if (
929
+			$this->capabilities->current_user_can(
930
+				'ee_edit_payments',
931
+				'espresso_transactions_recalculate_line_items'
932
+			)
933
+		) {
934
+			$actions['recalculate_line_items'] = EEH_Template::get_button_or_link(
935
+				EE_Admin_Page::add_query_args_and_nonce(
936
+					[
937
+						'action'      => 'espresso_recalculate_line_items',
938
+						'TXN_ID'      => $this->_transaction->ID(),
939
+						'redirect_to' => 'view_transaction',
940
+					],
941
+					TXN_ADMIN_URL
942
+				),
943
+				esc_html__(' Recalculate Taxes and Total', 'event_espresso'),
944
+				'button button--secondary',
945
+				'dashicons dashicons-update'
946
+			);
947
+		}
948
+
949
+		if (
950
+			$primary_registration instanceof EE_Registration
951
+			&& EEH_MSG_Template::is_mt_active('receipt')
952
+		) {
953
+			$actions['receipt'] = EEH_Template::get_button_or_link(
954
+				$primary_registration->receipt_url(),
955
+				esc_html__('View Receipt', 'event_espresso'),
956
+				'button button--secondary',
957
+				'dashicons dashicons-text-page'
958
+			);
959
+		}
960
+
961
+		if (
962
+			$primary_registration instanceof EE_Registration
963
+			&& EEH_MSG_Template::is_mt_active('invoice')
964
+		) {
965
+			$actions['invoice'] = EEH_Template::get_button_or_link(
966
+				$primary_registration->invoice_url(),
967
+				esc_html__('View Invoice', 'event_espresso'),
968
+				'button button--secondary',
969
+				'dashicons dashicons-media-spreadsheet'
970
+			);
971
+		}
972
+		$actions = array_filter(
973
+			apply_filters('FHEE__Transactions_Admin_Page__getActionButtons__actions', $actions, $transaction)
974
+		);
975
+		if ($actions) {
976
+			$content .= implode('', $actions);
977
+		}
978
+		return $content;
979
+	}
980
+
981
+
982
+	/**
983
+	 * txn_details_meta_box
984
+	 * generates HTML for the Transaction main meta box
985
+	 *
986
+	 * @return void
987
+	 * @throws DomainException
988
+	 * @throws EE_Error
989
+	 * @throws InvalidArgumentException
990
+	 * @throws InvalidDataTypeException
991
+	 * @throws InvalidInterfaceException
992
+	 * @throws RuntimeException
993
+	 * @throws ReflectionException
994
+	 */
995
+	public function txn_details_meta_box()
996
+	{
997
+		$this->_set_transaction_object();
998
+		$this->_template_args['TXN_ID']              = $this->_transaction->ID();
999
+		$this->_template_args['attendee']            =
1000
+			$this->_transaction->primary_registration() instanceof EE_Registration
1001
+				? $this->_transaction->primary_registration()->attendee()
1002
+				: null;
1003
+		$this->_template_args['can_edit_payments']   = $this->capabilities->current_user_can(
1004
+			'ee_edit_payments',
1005
+			'apply_payment_or_refund_from_registration_details'
1006
+		);
1007
+		$this->_template_args['can_delete_payments'] = $this->capabilities->current_user_can(
1008
+			'ee_delete_payments',
1009
+			'delete_payment_from_registration_details'
1010
+		);
1011
+
1012
+		// get line table
1013
+		EEH_Autoloader::register_line_item_display_autoloaders();
1014
+		$Line_Item_Display                       = new EE_Line_Item_Display(
1015
+			'admin_table',
1016
+			'EE_Admin_Table_Line_Item_Display_Strategy'
1017
+		);
1018
+		$this->_template_args['line_item_table'] = $Line_Item_Display->display_line_item(
1019
+			$this->_transaction->total_line_item()
1020
+		);
1021
+		$this->_template_args['REG_code']        =
1022
+			$this->_transaction->primary_registration() instanceof EE_Registration
1023
+				? $this->_transaction->primary_registration()->reg_code()
1024
+				: null;
1025
+		// process taxes
1026
+		$taxes                         = $this->_transaction->line_items([['LIN_type' => EEM_Line_Item::type_tax]]);
1027
+		$this->_template_args['taxes'] = ! empty($taxes)
1028
+			? $taxes
1029
+			: false;
1030
+
1031
+		$this->_template_args['grand_total']     = EEH_Template::format_currency(
1032
+			$this->_transaction->total(),
1033
+			false,
1034
+			false
1035
+		);
1036
+		$this->_template_args['grand_raw_total'] = $this->_transaction->total();
1037
+		$this->_template_args['TXN_status']      = $this->_transaction->status_ID();
1038
+
1039
+		// process payment details
1040
+		$payments = $this->_transaction->payments();
1041
+		if (! empty($payments)) {
1042
+			$this->_template_args['payments']              = $payments;
1043
+			$this->_template_args['existing_reg_payments'] = $this->_get_registration_payment_IDs($payments);
1044
+		} else {
1045
+			$this->_template_args['payments']              = false;
1046
+			$this->_template_args['existing_reg_payments'] = [];
1047
+		}
1048
+
1049
+		$this->_template_args['edit_payment_url']   = add_query_arg(['action' => 'edit_payment'], TXN_ADMIN_URL);
1050
+		$this->_template_args['delete_payment_url'] = add_query_arg(
1051
+			['action' => 'espresso_delete_payment'],
1052
+			TXN_ADMIN_URL
1053
+		);
1054
+
1055
+		if (isset($txn_details['invoice_number'])) {
1056
+			$this->_template_args['txn_details']['invoice_number']['value'] = $this->_template_args['REG_code'];
1057
+			$this->_template_args['txn_details']['invoice_number']['label'] = esc_html__(
1058
+				'Invoice Number',
1059
+				'event_espresso'
1060
+			);
1061
+		}
1062
+
1063
+		$this->_template_args['txn_details']['registration_session']['value'] =
1064
+			$this->_transaction->primary_registration() instanceof EE_Registration
1065
+				? $this->_transaction->primary_registration()->session_ID()
1066
+				: null;
1067
+		$this->_template_args['txn_details']['registration_session']['label'] = esc_html__(
1068
+			'Registration Session',
1069
+			'event_espresso'
1070
+		);
1071
+
1072
+		$this->_template_args['txn_details']['ip_address']['value'] = $this->_session['ip_address'] ?? '';
1073
+		$this->_template_args['txn_details']['ip_address']['label'] = esc_html__(
1074
+			'Transaction placed from IP',
1075
+			'event_espresso'
1076
+		);
1077
+
1078
+		$this->_template_args['txn_details']['user_agent']['value'] = $this->_session['user_agent'] ?? '';
1079
+		$this->_template_args['txn_details']['user_agent']['label'] = esc_html__(
1080
+			'Registrant User Agent',
1081
+			'event_espresso'
1082
+		);
1083
+
1084
+		$reg_steps = '<div class="ee-txn-reg-step-status-steps ee-layout-row">';
1085
+		foreach ($this->_transaction->reg_steps() as $reg_step => $reg_step_status) {
1086
+			if ($reg_step_status === true) {
1087
+				$reg_steps .= '<div class="ee-status-pill ee-status-bg--success">'
1088
+							  . sprintf(
1089
+								  esc_html__('%1$s : Completed', 'event_espresso'),
1090
+								  ucwords(str_replace('_', ' ', $reg_step))
1091
+							  )
1092
+							  . '</div>';
1093
+			} elseif ($reg_step_status !== false && is_numeric($reg_step_status)) {
1094
+				$reg_steps .= '<div class="ee-status-pill ee-status-bg--attention">'
1095
+							  . sprintf(
1096
+								  esc_html__('%1$s : Initiated %2$s', 'event_espresso'),
1097
+								  ucwords(str_replace('_', ' ', $reg_step)),
1098
+								  date(
1099
+									  get_option('date_format') . ' ' . get_option('time_format'),
1100
+									  $reg_step_status + (get_option('gmt_offset') * HOUR_IN_SECONDS)
1101
+								  )
1102
+							  )
1103
+							  . '</div>';
1104
+			} else {
1105
+				$reg_steps .= '<div class="ee-status-pill ee-status-bg--error">'
1106
+							  . sprintf(
1107
+								  esc_html__('%1$s : Never Initiated', 'event_espresso'),
1108
+								  ucwords(str_replace('_', ' ', $reg_step))
1109
+							  )
1110
+							  . '</div>';
1111
+			}
1112
+		}
1113
+		$reg_steps                                                 .= '</ul>';
1114
+		$this->_template_args['txn_details']['reg_steps']['value'] = $reg_steps;
1115
+		$this->_template_args['txn_details']['reg_steps']['label'] = esc_html__(
1116
+			'Registration Step Progress',
1117
+			'event_espresso'
1118
+		);
1119
+
1120
+
1121
+		$this->_get_registrations_to_apply_payment_to();
1122
+		$this->_get_payment_methods($payments);
1123
+		$this->_get_payment_status_array();
1124
+		$this->_get_reg_status_selection(); // sets up the template args for the reg status array for the transaction.
1125
+
1126
+		$this->_template_args['transaction_form_url']    = add_query_arg(
1127
+			[
1128
+				'action'  => 'edit_transaction',
1129
+				'process' => 'transaction',
1130
+			],
1131
+			TXN_ADMIN_URL
1132
+		);
1133
+		$this->_template_args['apply_payment_form_url']  = add_query_arg(
1134
+			[
1135
+				'page'   => 'espresso_transactions',
1136
+				'action' => 'espresso_apply_payment',
1137
+			],
1138
+			TXN_ADMIN_URL
1139
+		);
1140
+		$this->_template_args['delete_payment_form_url'] = add_query_arg(
1141
+			[
1142
+				'page'   => 'espresso_transactions',
1143
+				'action' => 'espresso_delete_payment',
1144
+			],
1145
+			TXN_ADMIN_URL
1146
+		);
1147
+
1148
+		$this->_template_args['action_buttons'] = $this->getActionButtons($this->_transaction);
1149
+
1150
+		// 'espresso_delete_payment_nonce'
1151
+
1152
+		$template_path = TXN_TEMPLATE_PATH . 'txn_admin_details_main_meta_box_txn_details.template.php';
1153
+		echo EEH_Template::display_template($template_path, $this->_template_args, true);
1154
+	}
1155
+
1156
+
1157
+	/**
1158
+	 * _get_registration_payment_IDs
1159
+	 *    generates an array of Payment IDs and their corresponding Registration IDs
1160
+	 *
1161
+	 * @access protected
1162
+	 * @param EE_Payment[] $payments
1163
+	 * @return array
1164
+	 * @throws EE_Error
1165
+	 * @throws InvalidArgumentException
1166
+	 * @throws InvalidDataTypeException
1167
+	 * @throws InvalidInterfaceException
1168
+	 * @throws ReflectionException
1169
+	 */
1170
+	protected function _get_registration_payment_IDs($payments = [])
1171
+	{
1172
+		$existing_reg_payments = [];
1173
+		// get all reg payments for these payments
1174
+		$reg_payments = EEM_Registration_Payment::instance()->get_all(
1175
+			[
1176
+				[
1177
+					'PAY_ID' => [
1178
+						'IN',
1179
+						array_keys($payments),
1180
+					],
1181
+				],
1182
+			]
1183
+		);
1184
+		if (! empty($reg_payments)) {
1185
+			foreach ($payments as $payment) {
1186
+				if (! $payment instanceof EE_Payment) {
1187
+					continue;
1188
+				} elseif (! isset($existing_reg_payments[ $payment->ID() ])) {
1189
+					$existing_reg_payments[ $payment->ID() ] = [];
1190
+				}
1191
+				foreach ($reg_payments as $reg_payment) {
1192
+					if (
1193
+						$reg_payment instanceof EE_Registration_Payment
1194
+						&& $reg_payment->payment_ID() === $payment->ID()
1195
+					) {
1196
+						$existing_reg_payments[ $payment->ID() ][] = $reg_payment->registration_ID();
1197
+					}
1198
+				}
1199
+			}
1200
+		}
1201
+
1202
+		return $existing_reg_payments;
1203
+	}
1204
+
1205
+
1206
+	/**
1207
+	 * _get_registrations_to_apply_payment_to
1208
+	 *    generates HTML for displaying a series of checkboxes in the admin payment modal window
1209
+	 * which allows the admin to only apply the payment to the specific registrations
1210
+	 *
1211
+	 * @access protected
1212
+	 * @return void
1213
+	 * @throws EE_Error
1214
+	 * @throws InvalidArgumentException
1215
+	 * @throws InvalidDataTypeException
1216
+	 * @throws InvalidInterfaceException
1217
+	 * @throws ReflectionException
1218
+	 */
1219
+	protected function _get_registrations_to_apply_payment_to()
1220
+	{
1221
+		// we want any registration with an active status (ie: not deleted or cancelled)
1222
+		$query_params                      = [
1223
+			[
1224
+				'STS_ID' => [
1225
+					'IN',
1226
+					[
1227
+						EEM_Registration::status_id_approved,
1228
+						EEM_Registration::status_id_pending_payment,
1229
+						EEM_Registration::status_id_not_approved,
1230
+					],
1231
+				],
1232
+			],
1233
+		];
1234
+		$registrations_to_apply_payment_to = EEH_HTML::br() . EEH_HTML::div(
1235
+				'',
1236
+				'txn-admin-apply-payment-to-registrations-dv',
1237
+				'',
1238
+				'clear: both; margin: 1.5em 0 0; display: none;'
1239
+			);
1240
+		$registrations_to_apply_payment_to .= EEH_HTML::br() . EEH_HTML::div('', '', 'admin-primary-mbox-tbl-wrap');
1241
+		$registrations_to_apply_payment_to .= EEH_HTML::table('', '', 'admin-primary-mbox-tbl striped');
1242
+		$registrations_to_apply_payment_to .= EEH_HTML::thead(
1243
+			EEH_HTML::tr(
1244
+				EEH_HTML::th(esc_html__('ID', 'event_espresso')) .
1245
+				EEH_HTML::th(esc_html__('Registrant', 'event_espresso')) .
1246
+				EEH_HTML::th(esc_html__('Ticket', 'event_espresso')) .
1247
+				EEH_HTML::th(esc_html__('Event', 'event_espresso')) .
1248
+				EEH_HTML::th(esc_html__('Paid', 'event_espresso'), '', 'txn-admin-payment-paid-td jst-cntr') .
1249
+				EEH_HTML::th(esc_html__('Owing', 'event_espresso'), '', 'txn-admin-payment-owing-td jst-cntr') .
1250
+				EEH_HTML::th(esc_html__('Apply', 'event_espresso'), '', 'jst-cntr')
1251
+			)
1252
+		);
1253
+		$registrations_to_apply_payment_to .= EEH_HTML::tbody();
1254
+		// get registrations for TXN
1255
+		$registrations         = $this->_transaction->registrations($query_params);
1256
+		$existing_reg_payments = $this->_template_args['existing_reg_payments'];
1257
+		foreach ($registrations as $registration) {
1258
+			if ($registration instanceof EE_Registration) {
1259
+				$attendee_name                     = $registration->attendee() instanceof EE_Attendee
1260
+					? $registration->attendee()->full_name()
1261
+					: esc_html__('Unknown Attendee', 'event_espresso');
1262
+				$owing                             = $registration->final_price() - $registration->paid();
1263
+				$taxable                           = $registration->ticket()->taxable()
1264
+					? ' <span class="smaller-text lt-grey-text"> ' . esc_html__('+ tax', 'event_espresso') . '</span>'
1265
+					: '';
1266
+				$checked                           = empty($existing_reg_payments)
1267
+													 || in_array($registration->ID(), $existing_reg_payments, true)
1268
+					? ' checked'
1269
+					: '';
1270
+				$disabled                          = $registration->final_price() > 0
1271
+					? ''
1272
+					: ' disabled';
1273
+				$registrations_to_apply_payment_to .= EEH_HTML::tr(
1274
+					EEH_HTML::td($registration->ID()) .
1275
+					EEH_HTML::td($attendee_name) .
1276
+					EEH_HTML::td(
1277
+						$registration->ticket()->name() . ' : ' . $registration->ticket()->pretty_price() . $taxable
1278
+					) .
1279
+					EEH_HTML::td($registration->event_name()) .
1280
+					EEH_HTML::td($registration->pretty_paid(), '', 'txn-admin-payment-paid-td jst-cntr') .
1281
+					EEH_HTML::td(
1282
+						EEH_Template::format_currency($owing),
1283
+						'',
1284
+						'txn-admin-payment-owing-td jst-cntr'
1285
+					) .
1286
+					EEH_HTML::td(
1287
+						'<input type="checkbox" value="' . $registration->ID()
1288
+						. '" name="txn_admin_payment[registrations]"'
1289
+						. $checked . $disabled . '>',
1290
+						'',
1291
+						'jst-cntr'
1292
+					),
1293
+					'apply-payment-registration-row-' . $registration->ID()
1294
+				);
1295
+			}
1296
+		}
1297
+		$registrations_to_apply_payment_to                         .= EEH_HTML::tbodyx();
1298
+		$registrations_to_apply_payment_to                         .= EEH_HTML::tablex();
1299
+		$registrations_to_apply_payment_to                         .= EEH_HTML::divx();
1300
+		$registrations_to_apply_payment_to                         .= EEH_HTML::p(
1301
+			esc_html__(
1302
+				'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.',
1303
+				'event_espresso'
1304
+			),
1305
+			'',
1306
+			'clear description'
1307
+		);
1308
+		$registrations_to_apply_payment_to                         .= EEH_HTML::divx();
1309
+		$this->_template_args['registrations_to_apply_payment_to'] = $registrations_to_apply_payment_to;
1310
+	}
1311
+
1312
+
1313
+	/**
1314
+	 * _get_reg_status_selection
1315
+	 *
1316
+	 * @return void
1317
+	 * @throws EE_Error
1318
+	 * @todo   this will need to be adjusted either once MER comes along OR we move default reg status to tickets
1319
+	 *         instead of events.
1320
+	 * @access protected
1321
+	 */
1322
+	protected function _get_reg_status_selection()
1323
+	{
1324
+		// first get all possible statuses
1325
+		$statuses = EEM_Registration::reg_status_array([], true);
1326
+		// let's add a "don't change" option.
1327
+		$status_array['NAN']                                 = esc_html__('Leave the Same', 'event_espresso');
1328
+		$status_array                                        = array_merge($status_array, $statuses);
1329
+		$this->_template_args['status_change_select']        = EEH_Form_Fields::select_input(
1330
+			'txn_reg_status_change[reg_status]',
1331
+			$status_array,
1332
+			'NAN',
1333
+			'id="txn-admin-payment-reg-status-inp"',
1334
+			'txn-reg-status-change-reg-status'
1335
+		);
1336
+		$this->_template_args['delete_status_change_select'] = EEH_Form_Fields::select_input(
1337
+			'delete_txn_reg_status_change[reg_status]',
1338
+			$status_array,
1339
+			'NAN',
1340
+			'delete-txn-admin-payment-reg-status-inp',
1341
+			'delete-txn-reg-status-change-reg-status'
1342
+		);
1343
+	}
1344
+
1345
+
1346
+	/**
1347
+	 *    _get_payment_methods
1348
+	 * Gets all the payment methods available generally, or the ones that are already
1349
+	 * selected on these payments (in case their payment methods are no longer active).
1350
+	 * Has the side-effect of updating the template args' payment_methods item
1351
+	 *
1352
+	 * @access private
1353
+	 * @param EE_Payment[] to show on this page
1354
+	 * @return void
1355
+	 * @throws EE_Error
1356
+	 * @throws InvalidArgumentException
1357
+	 * @throws InvalidDataTypeException
1358
+	 * @throws InvalidInterfaceException
1359
+	 * @throws ReflectionException
1360
+	 */
1361
+	private function _get_payment_methods($payments = [])
1362
+	{
1363
+		$payment_methods_of_payments = [];
1364
+		foreach ($payments as $payment) {
1365
+			if ($payment instanceof EE_Payment) {
1366
+				$payment_methods_of_payments[] = $payment->ID();
1367
+			}
1368
+		}
1369
+		if ($payment_methods_of_payments) {
1370
+			$query_args = [
1371
+				[
1372
+					'OR*payment_method_for_payment' => [
1373
+						'PMD_ID'    => ['IN', $payment_methods_of_payments],
1374
+						'PMD_scope' => ['LIKE', '%' . EEM_Payment_Method::scope_admin . '%'],
1375
+					],
1376
+				],
1377
+			];
1378
+		} else {
1379
+			$query_args = [['PMD_scope' => ['LIKE', '%' . EEM_Payment_Method::scope_admin . '%']]];
1380
+		}
1381
+		$this->_template_args['payment_methods'] = EEM_Payment_Method::instance()->get_all($query_args);
1382
+	}
1383
+
1384
+
1385
+	/**
1386
+	 * txn_attendees_meta_box
1387
+	 *    generates HTML for the Attendees Transaction main meta box
1388
+	 *
1389
+	 * @access public
1390
+	 * @param WP_Post $post
1391
+	 * @param array   $metabox
1392
+	 * @return void
1393
+	 * @throws DomainException
1394
+	 * @throws EE_Error
1395
+	 * @throws InvalidArgumentException
1396
+	 * @throws InvalidDataTypeException
1397
+	 * @throws InvalidInterfaceException
1398
+	 * @throws ReflectionException
1399
+	 */
1400
+	public function txn_attendees_meta_box($post, $metabox = ['args' => []])
1401
+	{
1402
+		/** @noinspection NonSecureExtractUsageInspection */
1403
+		extract($metabox['args']);
1404
+		$this->_template_args['post']            = $post;
1405
+		$this->_template_args['event_attendees'] = [];
1406
+		// process items in cart
1407
+		$line_items = $this->_transaction->get_many_related(
1408
+			'Line_Item',
1409
+			[['LIN_type' => 'line-item']]
1410
+		);
1411
+		if (! empty($line_items)) {
1412
+			foreach ($line_items as $item) {
1413
+				if ($item instanceof EE_Line_Item) {
1414
+					switch ($item->OBJ_type()) {
1415
+						case 'Event':
1416
+							break;
1417
+						case 'Ticket':
1418
+							$ticket = $item->ticket();
1419
+							// right now we're only handling tickets here.
1420
+							// Cause its expected that only tickets will have attendees right?
1421
+							if (! $ticket instanceof EE_Ticket) {
1422
+								break;
1423
+							}
1424
+							try {
1425
+								$event_name = $ticket->get_event_name();
1426
+							} catch (Exception $e) {
1427
+								EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1428
+								$event_name = esc_html__('Unknown Event', 'event_espresso');
1429
+							}
1430
+							$event_name   .= ' - ' . $item->name();
1431
+							$ticket_price = EEH_Template::format_currency($item->unit_price());
1432
+							// now get all of the registrations for this transaction that use this ticket
1433
+							$registrations = $ticket->registrations(
1434
+								[['TXN_ID' => $this->_transaction->ID()]]
1435
+							);
1436
+							foreach ($registrations as $registration) {
1437
+								if (! $registration instanceof EE_Registration) {
1438
+									break;
1439
+								}
1440
+								$this->_template_args['event_attendees'][ $registration->ID() ]['STS_ID']
1441
+									= $registration->status_ID();
1442
+								$this->_template_args['event_attendees'][ $registration->ID() ]['att_num']
1443
+									= $registration->count();
1444
+								$this->_template_args['event_attendees'][ $registration->ID() ]['event_ticket_name']
1445
+									= $event_name;
1446
+								$this->_template_args['event_attendees'][ $registration->ID() ]['ticket_price']
1447
+									= $ticket_price;
1448
+								// attendee info
1449
+								$attendee = $registration->get_first_related('Attendee');
1450
+								if ($attendee instanceof EE_Attendee) {
1451
+									$this->_template_args['event_attendees'][ $registration->ID() ]['att_id']
1452
+										= $attendee->ID();
1453
+									$this->_template_args['event_attendees'][ $registration->ID() ]['attendee']
1454
+										= $attendee->full_name();
1455
+									$this->_template_args['event_attendees'][ $registration->ID() ]['email']
1456
+										= '<a href="mailto:' . $attendee->email() . '?subject=' . $event_name
1457
+										  . esc_html__(
1458
+											  ' Event',
1459
+											  'event_espresso'
1460
+										  )
1461
+										  . '">' . $attendee->email() . '</a>';
1462
+									$this->_template_args['event_attendees'][ $registration->ID() ]['address']
1463
+										= EEH_Address::format($attendee, 'inline', false, false);
1464
+								} else {
1465
+									$this->_template_args['event_attendees'][ $registration->ID() ]['att_id']   = '';
1466
+									$this->_template_args['event_attendees'][ $registration->ID() ]['attendee'] = '';
1467
+									$this->_template_args['event_attendees'][ $registration->ID() ]['email']    = '';
1468
+									$this->_template_args['event_attendees'][ $registration->ID() ]['address']  = '';
1469
+								}
1470
+							}
1471
+							break;
1472
+					}
1473
+				}
1474
+			}
1475
+
1476
+			$this->_template_args['transaction_form_url'] = add_query_arg(
1477
+				[
1478
+					'action'  => 'edit_transaction',
1479
+					'process' => 'attendees',
1480
+				],
1481
+				TXN_ADMIN_URL
1482
+			);
1483
+			echo EEH_Template::display_template(
1484
+				TXN_TEMPLATE_PATH . 'txn_admin_details_main_meta_box_attendees.template.php',
1485
+				$this->_template_args,
1486
+				true
1487
+			);
1488
+		} else {
1489
+			printf(
1490
+				esc_html__(
1491
+					'%1$sFor some reason, there are no attendees registered for this transaction. Likely the registration was abandoned in process.%2$s',
1492
+					'event_espresso'
1493
+				),
1494
+				'<p class="important-notice">',
1495
+				'</p>'
1496
+			);
1497
+		}
1498
+	}
1499
+
1500
+
1501
+	/**
1502
+	 * txn_registrant_side_meta_box
1503
+	 * generates HTML for the Edit Transaction side meta box
1504
+	 *
1505
+	 * @access public
1506
+	 * @return void
1507
+	 * @throws DomainException
1508
+	 * @throws EE_Error
1509
+	 * @throws InvalidArgumentException
1510
+	 * @throws InvalidDataTypeException
1511
+	 * @throws InvalidInterfaceException
1512
+	 * @throws ReflectionException
1513
+	 */
1514
+	public function txn_registrant_side_meta_box()
1515
+	{
1516
+		$primary_att = $this->_transaction->primary_registration() instanceof EE_Registration
1517
+			? $this->_transaction->primary_registration()->get_first_related('Attendee')
1518
+			: null;
1519
+		if (! $primary_att instanceof EE_Attendee) {
1520
+			$this->_template_args['no_attendee_message'] = esc_html__(
1521
+				'There is no attached contact for this transaction.  The transaction either failed due to an error or was abandoned.',
1522
+				'event_espresso'
1523
+			);
1524
+			$primary_att                                 = EEM_Attendee::instance()->create_default_object();
1525
+		}
1526
+		$this->_template_args['ATT_ID']            = $primary_att->ID();
1527
+		$this->_template_args['prime_reg_fname']   = $primary_att->fname();
1528
+		$this->_template_args['prime_reg_lname']   = $primary_att->lname();
1529
+		$this->_template_args['prime_reg_email']   = $primary_att->email();
1530
+		$this->_template_args['prime_reg_phone']   = $primary_att->phone();
1531
+		$this->_template_args['edit_attendee_url'] = EE_Admin_Page::add_query_args_and_nonce(
1532
+			[
1533
+				'action' => 'edit_attendee',
1534
+				'post'   => $primary_att->ID(),
1535
+			],
1536
+			REG_ADMIN_URL
1537
+		);
1538
+		// get formatted address for registrant
1539
+		$formatted_address                         = EEH_Address::format($primary_att);
1540
+		$formatted_address                         =
1541
+			$formatted_address !== '<div class="espresso-address-dv"><div></div></div>'
1542
+				? $formatted_address
1543
+				: '';
1544
+		$this->_template_args['formatted_address'] = $formatted_address;
1545
+		echo EEH_Template::display_template(
1546
+			TXN_TEMPLATE_PATH . 'txn_admin_details_side_meta_box_registrant.template.php',
1547
+			$this->_template_args,
1548
+			true
1549
+		);
1550
+	}
1551
+
1552
+
1553
+	/**
1554
+	 * txn_billing_info_side_meta_box
1555
+	 *    generates HTML for the Edit Transaction side meta box
1556
+	 *
1557
+	 * @access public
1558
+	 * @return void
1559
+	 * @throws DomainException
1560
+	 * @throws EE_Error
1561
+	 * @throws ReflectionException
1562
+	 */
1563
+	public function txn_billing_info_side_meta_box()
1564
+	{
1565
+		$this->_template_args['billing_form']     = $this->_transaction->billing_info();
1566
+		$this->_template_args['billing_form_url'] = add_query_arg(
1567
+			['action' => 'edit_transaction', 'process' => 'billing'],
1568
+			TXN_ADMIN_URL
1569
+		);
1570
+
1571
+		$template_path = TXN_TEMPLATE_PATH . 'txn_admin_details_side_meta_box_billing_info.template.php';
1572
+		echo EEH_Template::display_template($template_path, $this->_template_args, true);
1573
+	}
1574
+
1575
+
1576
+	/**
1577
+	 * apply_payments_or_refunds
1578
+	 *    registers a payment or refund made towards a transaction
1579
+	 *
1580
+	 * @access public
1581
+	 * @return void
1582
+	 * @throws EE_Error
1583
+	 * @throws InvalidArgumentException
1584
+	 * @throws ReflectionException
1585
+	 * @throws RuntimeException
1586
+	 * @throws InvalidDataTypeException
1587
+	 * @throws InvalidInterfaceException
1588
+	 */
1589
+	public function apply_payments_or_refunds()
1590
+	{
1591
+		$valid_data = $this->_validate_payment_request_data();
1592
+		$has_access = $this->capabilities->current_user_can(
1593
+			'ee_edit_payments',
1594
+			'apply_payment_or_refund_from_registration_details'
1595
+		);
1596
+		$TXD_ID     = $this->request->getRequestParam('txn_admin_payment[TXN_ID]', 0, 'int');
1597
+		$amount     = 0;
1598
+		if (! empty($valid_data) && $has_access) {
1599
+			$PAY_ID = $valid_data['PAY_ID'];
1600
+			// save  the new payment
1601
+			$payment = $this->_create_payment_from_request_data($valid_data);
1602
+			$amount  = $payment->amount();
1603
+			// get the TXN for this payment
1604
+			$transaction = $payment->transaction();
1605
+			// verify transaction
1606
+			if ($transaction instanceof EE_Transaction) {
1607
+				// calculate_total_payments_and_update_status
1608
+				$this->_process_transaction_payments($transaction);
1609
+				$REG_IDs = $this->_get_REG_IDs_to_apply_payment_to($payment);
1610
+				$this->_remove_existing_registration_payments($payment, $PAY_ID);
1611
+				// apply payment to registrations (if applicable)
1612
+				if (! empty($REG_IDs)) {
1613
+					$this->_update_registration_payments($transaction, $payment, $REG_IDs);
1614
+					$this->_maybe_send_notifications();
1615
+					// now process status changes for the same registrations
1616
+					$this->_process_registration_status_change($transaction, $REG_IDs);
1617
+				}
1618
+				$this->_maybe_send_notifications($payment);
1619
+				// prepare to render page
1620
+				do_action(
1621
+					'AHEE__Transactions_Admin_Page__apply_payments_or_refund__after_recording',
1622
+					$transaction,
1623
+					$payment
1624
+				);
1625
+			} else {
1626
+				EE_Error::add_error(
1627
+					esc_html__(
1628
+						'A valid Transaction for this payment could not be retrieved.',
1629
+						'event_espresso'
1630
+					),
1631
+					__FILE__,
1632
+					__FUNCTION__,
1633
+					__LINE__
1634
+				);
1635
+			}
1636
+		} elseif ($has_access) {
1637
+			EE_Error::add_error(
1638
+				esc_html__(
1639
+					'The payment form data could not be processed. Please try again.',
1640
+					'event_espresso'
1641
+				),
1642
+				__FILE__,
1643
+				__FUNCTION__,
1644
+				__LINE__
1645
+			);
1646
+		} else {
1647
+			EE_Error::add_error(
1648
+				esc_html__(
1649
+					'You do not have access to apply payments or refunds to a registration.',
1650
+					'event_espresso'
1651
+				),
1652
+				__FILE__,
1653
+				__FUNCTION__,
1654
+				__LINE__
1655
+			);
1656
+		}
1657
+		$query_args = [
1658
+			'page'   => 'espresso_transactions',
1659
+			'action' => 'view_transaction',
1660
+			'TXN_ID' => $TXD_ID,
1661
+		];
1662
+
1663
+		$this->_redirect_after_action(
1664
+			! EE_Error::has_error(),
1665
+			$amount > 0
1666
+				? esc_html__('payment', 'event_espresso')
1667
+				: esc_html__('refund', 'event_espresso'),
1668
+			esc_html__('processed', 'event_espresso'),
1669
+			$query_args
1670
+		);
1671
+	}
1672
+
1673
+
1674
+	/**
1675
+	 * _validate_payment_request_data
1676
+	 *
1677
+	 * @return array
1678
+	 * @throws EE_Error
1679
+	 * @throws InvalidArgumentException
1680
+	 * @throws InvalidDataTypeException
1681
+	 * @throws InvalidInterfaceException
1682
+	 */
1683
+	protected function _validate_payment_request_data()
1684
+	{
1685
+		if (! $this->request->requestParamIsSet('txn_admin_payment')) {
1686
+			return [];
1687
+		}
1688
+		$payment_form = $this->_generate_payment_form_section();
1689
+		try {
1690
+			if ($payment_form->was_submitted()) {
1691
+				$payment_form->receive_form_submission();
1692
+				if (! $payment_form->is_valid()) {
1693
+					$submission_error_messages = [];
1694
+					foreach ($payment_form->get_validation_errors_accumulated() as $validation_error) {
1695
+						if ($validation_error instanceof EE_Validation_Error) {
1696
+							$form_input                  = $validation_error->get_form_section();
1697
+							$submission_error_messages[] = sprintf(
1698
+								_x('%s : %s', 'Form Section Name : Form Validation Error', 'event_espresso'),
1699
+								$form_input instanceof EE_Form_Input_Base
1700
+									? $form_input->html_label_text()
1701
+									: '',
1702
+								$validation_error->getMessage()
1703
+							);
1704
+						}
1705
+					}
1706
+					EE_Error::add_error(
1707
+						implode('<br />', $submission_error_messages),
1708
+						__FILE__,
1709
+						__FUNCTION__,
1710
+						__LINE__
1711
+					);
1712
+					return [];
1713
+				}
1714
+			}
1715
+		} catch (EE_Error $e) {
1716
+			EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1717
+			return [];
1718
+		}
1719
+
1720
+		return $payment_form->valid_data();
1721
+	}
1722
+
1723
+
1724
+	/**
1725
+	 * _generate_payment_form_section
1726
+	 *
1727
+	 * @return EE_Form_Section_Proper
1728
+	 * @throws EE_Error
1729
+	 */
1730
+	protected function _generate_payment_form_section()
1731
+	{
1732
+		return new EE_Form_Section_Proper(
1733
+			[
1734
+				'name'        => 'txn_admin_payment',
1735
+				'subsections' => [
1736
+					'PAY_ID'          => new EE_Text_Input(
1737
+						[
1738
+							'default'               => 0,
1739
+							'required'              => false,
1740
+							'html_label_text'       => esc_html__('Payment ID', 'event_espresso'),
1741
+							'validation_strategies' => [new EE_Int_Normalization()],
1742
+						]
1743
+					),
1744
+					'TXN_ID'          => new EE_Text_Input(
1745
+						[
1746
+							'default'               => 0,
1747
+							'required'              => true,
1748
+							'html_label_text'       => esc_html__('Transaction ID', 'event_espresso'),
1749
+							'validation_strategies' => [new EE_Int_Normalization()],
1750
+						]
1751
+					),
1752
+					'type'            => new EE_Text_Input(
1753
+						[
1754
+							'default'               => 1,
1755
+							'required'              => true,
1756
+							'html_label_text'       => esc_html__('Payment or Refund', 'event_espresso'),
1757
+							'validation_strategies' => [new EE_Int_Normalization()],
1758
+						]
1759
+					),
1760
+					'amount'          => new EE_Text_Input(
1761
+						[
1762
+							'default'               => 0,
1763
+							'required'              => true,
1764
+							'html_label_text'       => esc_html__('Payment amount', 'event_espresso'),
1765
+							'validation_strategies' => [new EE_Float_Normalization()],
1766
+						]
1767
+					),
1768
+					'status'          => new EE_Text_Input(
1769
+						[
1770
+							'default'         => EEM_Payment::status_id_approved,
1771
+							'required'        => true,
1772
+							'html_label_text' => esc_html__('Payment status', 'event_espresso'),
1773
+						]
1774
+					),
1775
+					'PMD_ID'          => new EE_Text_Input(
1776
+						[
1777
+							'default'               => 2,
1778
+							'required'              => true,
1779
+							'html_label_text'       => esc_html__('Payment Method', 'event_espresso'),
1780
+							'validation_strategies' => [new EE_Int_Normalization()],
1781
+						]
1782
+					),
1783
+					'date'            => new EE_Text_Input(
1784
+						[
1785
+							'default'         => time(),
1786
+							'required'        => true,
1787
+							'html_label_text' => esc_html__('Payment date', 'event_espresso'),
1788
+						]
1789
+					),
1790
+					'txn_id_chq_nmbr' => new EE_Text_Input(
1791
+						[
1792
+							'default'               => '',
1793
+							'required'              => false,
1794
+							'html_label_text'       => esc_html__('Transaction or Cheque Number', 'event_espresso'),
1795
+							'validation_strategies' => [
1796
+								new EE_Max_Length_Validation_Strategy(
1797
+									esc_html__('Input too long', 'event_espresso'),
1798
+									100
1799
+								),
1800
+							],
1801
+						]
1802
+					),
1803
+					'po_number'       => new EE_Text_Input(
1804
+						[
1805
+							'default'               => '',
1806
+							'required'              => false,
1807
+							'html_label_text'       => esc_html__('Purchase Order Number', 'event_espresso'),
1808
+							'validation_strategies' => [
1809
+								new EE_Max_Length_Validation_Strategy(
1810
+									esc_html__('Input too long', 'event_espresso'),
1811
+									100
1812
+								),
1813
+							],
1814
+						]
1815
+					),
1816
+					'accounting'      => new EE_Text_Input(
1817
+						[
1818
+							'default'               => '',
1819
+							'required'              => false,
1820
+							'html_label_text'       => esc_html__('Extra Field for Accounting', 'event_espresso'),
1821
+							'validation_strategies' => [
1822
+								new EE_Max_Length_Validation_Strategy(
1823
+									esc_html__('Input too long', 'event_espresso'),
1824
+									100
1825
+								),
1826
+							],
1827
+						]
1828
+					),
1829
+				],
1830
+			]
1831
+		);
1832
+	}
1833
+
1834
+
1835
+	/**
1836
+	 * _create_payment_from_request_data
1837
+	 *
1838
+	 * @param array $valid_data
1839
+	 * @return EE_Payment
1840
+	 * @throws EE_Error
1841
+	 * @throws InvalidArgumentException
1842
+	 * @throws InvalidDataTypeException
1843
+	 * @throws InvalidInterfaceException
1844
+	 * @throws ReflectionException
1845
+	 */
1846
+	protected function _create_payment_from_request_data($valid_data)
1847
+	{
1848
+		$PAY_ID = $valid_data['PAY_ID'];
1849
+		// get payment amount
1850
+		$amount = $valid_data['amount']
1851
+			? abs($valid_data['amount'])
1852
+			: 0;
1853
+		// payments have a type value of 1 and refunds have a type value of -1
1854
+		// so multiplying amount by type will give a positive value for payments, and negative values for refunds
1855
+		$amount = $valid_data['type'] < 0
1856
+			? $amount * -1
1857
+			: $amount;
1858
+		// for some reason the date string coming in has extra spaces between the date and time.  This fixes that.
1859
+		$date    = $valid_data['date']
1860
+			? preg_replace('/\s+/', ' ', $valid_data['date'])
1861
+			: date('Y-m-d g:i a', current_time('timestamp'));
1862
+		$payment = EE_Payment::new_instance(
1863
+			[
1864
+				'TXN_ID'              => $valid_data['TXN_ID'],
1865
+				'STS_ID'              => $valid_data['status'],
1866
+				'PAY_timestamp'       => $date,
1867
+				'PAY_source'          => EEM_Payment_Method::scope_admin,
1868
+				'PMD_ID'              => $valid_data['PMD_ID'],
1869
+				'PAY_amount'          => $amount,
1870
+				'PAY_txn_id_chq_nmbr' => $valid_data['txn_id_chq_nmbr'],
1871
+				'PAY_po_number'       => $valid_data['po_number'],
1872
+				'PAY_extra_accntng'   => $valid_data['accounting'],
1873
+				'PAY_details'         => $valid_data,
1874
+				'PAY_ID'              => $PAY_ID,
1875
+			],
1876
+			'',
1877
+			['Y-m-d', 'g:i a']
1878
+		);
1879
+
1880
+		if (! $payment->save()) {
1881
+			EE_Error::add_error(
1882
+				sprintf(
1883
+					esc_html__('Payment %1$d has not been successfully saved to the database.', 'event_espresso'),
1884
+					$payment->ID()
1885
+				),
1886
+				__FILE__,
1887
+				__FUNCTION__,
1888
+				__LINE__
1889
+			);
1890
+		}
1891
+
1892
+		return $payment;
1893
+	}
1894
+
1895
+
1896
+	/**
1897
+	 * _process_transaction_payments
1898
+	 *
1899
+	 * @param EE_Transaction $transaction
1900
+	 * @return void
1901
+	 * @throws EE_Error
1902
+	 * @throws InvalidArgumentException
1903
+	 * @throws ReflectionException
1904
+	 * @throws InvalidDataTypeException
1905
+	 * @throws InvalidInterfaceException
1906
+	 */
1907
+	protected function _process_transaction_payments(EE_Transaction $transaction)
1908
+	{
1909
+		/** @type EE_Transaction_Payments $transaction_payments */
1910
+		$transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
1911
+		// update the transaction with this payment
1912
+		if ($transaction_payments->calculate_total_payments_and_update_status($transaction)) {
1913
+			EE_Error::add_success(
1914
+				esc_html__(
1915
+					'The payment has been processed successfully.',
1916
+					'event_espresso'
1917
+				),
1918
+				__FILE__,
1919
+				__FUNCTION__,
1920
+				__LINE__
1921
+			);
1922
+		} else {
1923
+			EE_Error::add_error(
1924
+				esc_html__(
1925
+					'The payment was processed successfully but the amount paid for the transaction was not updated.',
1926
+					'event_espresso'
1927
+				),
1928
+				__FILE__,
1929
+				__FUNCTION__,
1930
+				__LINE__
1931
+			);
1932
+		}
1933
+	}
1934
+
1935
+
1936
+	/**
1937
+	 * _get_REG_IDs_to_apply_payment_to
1938
+	 * returns a list of registration IDs that the payment will apply to
1939
+	 *
1940
+	 * @param EE_Payment $payment
1941
+	 * @return array
1942
+	 * @throws EE_Error
1943
+	 * @throws InvalidArgumentException
1944
+	 * @throws InvalidDataTypeException
1945
+	 * @throws InvalidInterfaceException
1946
+	 * @throws ReflectionException
1947
+	 */
1948
+	protected function _get_REG_IDs_to_apply_payment_to(EE_Payment $payment)
1949
+	{
1950
+		// grab array of IDs for specific registrations to apply changes to
1951
+		$apply_to_all = $this->request->getRequestParam(
1952
+			'txn_admin_payment[apply_to_all_registrations]',
1953
+			false,
1954
+			DataType::BOOL
1955
+		);
1956
+		$REG_IDs      = ! $apply_to_all
1957
+			? $this->request->getRequestParam(
1958
+				'txn_admin_payment[registrations]',
1959
+				[],
1960
+				DataType::INT,
1961
+				true
1962
+			)
1963
+			: [];
1964
+		// nothing specified ? then get all reg IDs
1965
+		if ($apply_to_all || empty($REG_IDs)) {
1966
+			$registrations = $payment->transaction()->registrations(
1967
+				[
1968
+					[
1969
+						'STS_ID' => [
1970
+							'NOT_IN', [ EEM_Registration::status_id_cancelled ]
1971
+						]
1972
+					]
1973
+				]
1974
+			);
1975
+			$REG_IDs       = ! empty($registrations)
1976
+				? array_keys($registrations)
1977
+				: $this->_get_existing_reg_payment_REG_IDs($payment);
1978
+		}
1979
+		// ensure that REG_IDs are integers and NOT strings
1980
+		return array_map('absint', $REG_IDs);
1981
+	}
1982
+
1983
+
1984
+	/**
1985
+	 * @return array
1986
+	 */
1987
+	public function existing_reg_payment_REG_IDs()
1988
+	{
1989
+		return $this->_existing_reg_payment_REG_IDs;
1990
+	}
1991
+
1992
+
1993
+	/**
1994
+	 * @param array $existing_reg_payment_REG_IDs
1995
+	 */
1996
+	public function set_existing_reg_payment_REG_IDs($existing_reg_payment_REG_IDs = null)
1997
+	{
1998
+		$this->_existing_reg_payment_REG_IDs = $existing_reg_payment_REG_IDs;
1999
+	}
2000
+
2001
+
2002
+	/**
2003
+	 * _get_existing_reg_payment_REG_IDs
2004
+	 * returns a list of registration IDs that the payment is currently related to
2005
+	 * as recorded in the database
2006
+	 *
2007
+	 * @param EE_Payment $payment
2008
+	 * @return array
2009
+	 * @throws EE_Error
2010
+	 * @throws InvalidArgumentException
2011
+	 * @throws InvalidDataTypeException
2012
+	 * @throws InvalidInterfaceException
2013
+	 * @throws ReflectionException
2014
+	 */
2015
+	protected function _get_existing_reg_payment_REG_IDs(EE_Payment $payment)
2016
+	{
2017
+		if ($this->existing_reg_payment_REG_IDs() === null) {
2018
+			// let's get any existing reg payment records for this payment
2019
+			$existing_reg_payment_REG_IDs = $payment->get_many_related('Registration');
2020
+			// but we only want the REG IDs, so grab the array keys
2021
+			$existing_reg_payment_REG_IDs = ! empty($existing_reg_payment_REG_IDs)
2022
+				? array_keys($existing_reg_payment_REG_IDs)
2023
+				: [];
2024
+			$this->set_existing_reg_payment_REG_IDs($existing_reg_payment_REG_IDs);
2025
+		}
2026
+
2027
+		return $this->existing_reg_payment_REG_IDs();
2028
+	}
2029
+
2030
+
2031
+	/**
2032
+	 * _remove_existing_registration_payments
2033
+	 * this calculates the difference between existing relations
2034
+	 * to the supplied payment and the new list registration IDs,
2035
+	 * removes any related registrations that no longer apply,
2036
+	 * and then updates the registration paid fields
2037
+	 *
2038
+	 * @param EE_Payment $payment
2039
+	 * @param int        $PAY_ID
2040
+	 * @return bool;
2041
+	 * @throws EE_Error
2042
+	 * @throws InvalidArgumentException
2043
+	 * @throws ReflectionException
2044
+	 * @throws InvalidDataTypeException
2045
+	 * @throws InvalidInterfaceException
2046
+	 */
2047
+	protected function _remove_existing_registration_payments(EE_Payment $payment, $PAY_ID = 0)
2048
+	{
2049
+		// newly created payments will have nothing recorded for $PAY_ID
2050
+		if (absint($PAY_ID) === 0) {
2051
+			return false;
2052
+		}
2053
+		$existing_reg_payment_REG_IDs = $this->_get_existing_reg_payment_REG_IDs($payment);
2054
+		if (empty($existing_reg_payment_REG_IDs)) {
2055
+			return false;
2056
+		}
2057
+		/** @type EE_Transaction_Payments $transaction_payments */
2058
+		$transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
2059
+
2060
+		return $transaction_payments->delete_registration_payments_and_update_registrations(
2061
+			$payment,
2062
+			[
2063
+				[
2064
+					'PAY_ID' => $payment->ID(),
2065
+					'REG_ID' => ['IN', $existing_reg_payment_REG_IDs],
2066
+				],
2067
+			]
2068
+		);
2069
+	}
2070
+
2071
+
2072
+	/**
2073
+	 * _update_registration_payments
2074
+	 * this applies the payments to the selected registrations
2075
+	 * but only if they have not already been paid for
2076
+	 *
2077
+	 * @param EE_Transaction $transaction
2078
+	 * @param EE_Payment     $payment
2079
+	 * @param array          $REG_IDs
2080
+	 * @return void
2081
+	 * @throws EE_Error
2082
+	 * @throws InvalidArgumentException
2083
+	 * @throws ReflectionException
2084
+	 * @throws RuntimeException
2085
+	 * @throws InvalidDataTypeException
2086
+	 * @throws InvalidInterfaceException
2087
+	 */
2088
+	protected function _update_registration_payments(
2089
+		EE_Transaction $transaction,
2090
+		EE_Payment $payment,
2091
+		$REG_IDs = []
2092
+	) {
2093
+		// we can pass our own custom set of registrations to EE_Payment_Processor::process_registration_payments()
2094
+		// so let's do that using our set of REG_IDs from the form
2095
+		$registration_query_where_params = [
2096
+			'REG_ID' => ['IN', $REG_IDs],
2097
+		];
2098
+		// but add in some conditions regarding payment,
2099
+		// so that we don't apply payments to registrations that are free or have already been paid for
2100
+		// but ONLY if the payment is NOT a refund ( ie: the payment amount is not negative )
2101
+		if (! $payment->is_a_refund()) {
2102
+			$registration_query_where_params['REG_final_price']  = ['!=', 0];
2103
+			$registration_query_where_params['REG_final_price*'] = ['!=', 'REG_paid', true];
2104
+		}
2105
+		$registrations = $transaction->registrations([$registration_query_where_params]);
2106
+		if (! empty($registrations)) {
2107
+			/** @type EE_Payment_Processor $payment_processor */
2108
+			$payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
2109
+			$payment_processor->process_registration_payments($transaction, $payment, $registrations);
2110
+		}
2111
+	}
2112
+
2113
+
2114
+	/**
2115
+	 * _process_registration_status_change
2116
+	 * This processes requested registration status changes for all the registrations
2117
+	 * on a given transaction and (optionally) sends out notifications for the changes.
2118
+	 *
2119
+	 * @param EE_Transaction $transaction
2120
+	 * @param array          $REG_IDs
2121
+	 * @return bool
2122
+	 * @throws EE_Error
2123
+	 * @throws InvalidArgumentException
2124
+	 * @throws ReflectionException
2125
+	 * @throws InvalidDataTypeException
2126
+	 * @throws InvalidInterfaceException
2127
+	 */
2128
+	protected function _process_registration_status_change(EE_Transaction $transaction, $REG_IDs = [], $reg_status = '')
2129
+	{
2130
+		// first if there is no change in status then we get out.
2131
+		$reg_status = $reg_status
2132
+			?: $this->request->getRequestParam('txn_reg_status_change[reg_status]', 'NAN');
2133
+		if ($reg_status === 'NAN') {
2134
+			// no error message, no change requested, just nothing to do man.
2135
+			return false;
2136
+		}
2137
+		/** @type EE_Transaction_Processor $transaction_processor */
2138
+		$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
2139
+
2140
+		// made it here dude?  Oh WOW.  K, let's take care of changing the statuses
2141
+		return $transaction_processor->manually_update_registration_statuses(
2142
+			$transaction,
2143
+			$reg_status,
2144
+			[['REG_ID' => ['IN', $REG_IDs]]]
2145
+		);
2146
+	}
2147
+
2148
+
2149
+	/**
2150
+	 * _build_payment_json_response
2151
+	 *
2152
+	 * @access public
2153
+	 * @param EE_Payment  $payment
2154
+	 * @param array       $REG_IDs
2155
+	 * @param bool | null $delete_txn_reg_status_change
2156
+	 * @return array
2157
+	 * @throws EE_Error
2158
+	 * @throws InvalidArgumentException
2159
+	 * @throws InvalidDataTypeException
2160
+	 * @throws InvalidInterfaceException
2161
+	 * @throws ReflectionException
2162
+	 */
2163
+	protected function _build_payment_json_response(
2164
+		EE_Payment $payment,
2165
+		$REG_IDs = [],
2166
+		$delete_txn_reg_status_change = null
2167
+	) {
2168
+		// was the payment deleted ?
2169
+		if (is_bool($delete_txn_reg_status_change)) {
2170
+			return [
2171
+				'PAY_ID'                       => $payment->ID(),
2172
+				'amount'                       => $payment->amount(),
2173
+				'total_paid'                   => $payment->transaction()->paid(),
2174
+				'txn_status'                   => $payment->transaction()->status_ID(),
2175
+				'pay_status'                   => $payment->STS_ID(),
2176
+				'registrations'                => $this->_registration_payment_data_array($REG_IDs),
2177
+				'delete_txn_reg_status_change' => $delete_txn_reg_status_change,
2178
+			];
2179
+		}
2180
+
2181
+		$this->_get_payment_status_array();
2182
+		$payment_method = $payment->payment_method();
2183
+		return [
2184
+			'amount'           => $payment->amount(),
2185
+			'total_paid'       => $payment->transaction()->paid(),
2186
+			'txn_status'       => $payment->transaction()->status_ID(),
2187
+			'pay_status'       => $payment->STS_ID(),
2188
+			'PAY_ID'           => $payment->ID(),
2189
+			'STS_ID'           => $payment->STS_ID(),
2190
+			'status'           => self::$_pay_status[ $payment->STS_ID() ],
2191
+			'date'             => $payment->timestamp('Y-m-d', 'h:i a'),
2192
+			'method'           => strtoupper($payment->source()),
2193
+			'PM_ID'            => $payment_method instanceof EE_Payment_Method
2194
+				? $payment_method->ID()
2195
+				: 1,
2196
+			'gateway'          => $payment_method instanceof EE_Payment_Method
2197
+				? $payment_method->admin_name()
2198
+				: esc_html__('Unknown', 'event_espresso'),
2199
+			'gateway_response' => $payment->gateway_response(),
2200
+			'txn_id_chq_nmbr'  => $payment->txn_id_chq_nmbr(),
2201
+			'po_number'        => $payment->po_number(),
2202
+			'extra_accntng'    => $payment->extra_accntng(),
2203
+			'registrations'    => $this->_registration_payment_data_array($REG_IDs),
2204
+		];
2205
+	}
2206
+
2207
+
2208
+	/**
2209
+	 * delete_payment
2210
+	 *    delete a payment or refund made towards a transaction
2211
+	 *
2212
+	 * @access public
2213
+	 * @return void
2214
+	 * @throws EE_Error
2215
+	 * @throws InvalidArgumentException
2216
+	 * @throws ReflectionException
2217
+	 * @throws InvalidDataTypeException
2218
+	 * @throws InvalidInterfaceException
2219
+	 */
2220
+	public function delete_payment()
2221
+	{
2222
+		$TXD_ID = $this->request->getRequestParam('delete_txn_admin_payment[TXN_ID]', 0, 'int');
2223
+		// $json_response_data = ['return_data' => false];
2224
+		$PAY_ID     = $this->request->getRequestParam('delete_txn_admin_payment[PAY_ID]', 0, 'int');
2225
+		$amount     = 0;
2226
+		$can_delete = $this->capabilities->current_user_can(
2227
+			'ee_delete_payments',
2228
+			'delete_payment_from_registration_details'
2229
+		);
2230
+		if ($PAY_ID && $can_delete) {
2231
+			$delete_txn_reg_status_change = $this->request->getRequestParam('delete_txn_reg_status_change[reg_status]');
2232
+			$payment                      = EEM_Payment::instance()->get_one_by_ID($PAY_ID);
2233
+			if ($payment instanceof EE_Payment) {
2234
+				$amount  = $payment->amount();
2235
+				$REG_IDs = $this->_get_existing_reg_payment_REG_IDs($payment);
2236
+				/** @type EE_Transaction_Payments $transaction_payments */
2237
+				$transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
2238
+				if ($transaction_payments->delete_payment_and_update_transaction($payment)) {
2239
+					if ($delete_txn_reg_status_change) {
2240
+						$this->_maybe_send_notifications();
2241
+						$this->_process_registration_status_change(
2242
+							$payment->transaction(),
2243
+							$REG_IDs,
2244
+							$delete_txn_reg_status_change
2245
+						);
2246
+					}
2247
+				}
2248
+			} else {
2249
+				EE_Error::add_error(
2250
+					esc_html__('Valid Payment data could not be retrieved from the database.', 'event_espresso'),
2251
+					__FILE__,
2252
+					__FUNCTION__,
2253
+					__LINE__
2254
+				);
2255
+			}
2256
+		} elseif ($can_delete) {
2257
+			EE_Error::add_error(
2258
+				esc_html__(
2259
+					'A valid Payment ID was not received, therefore payment form data could not be loaded.',
2260
+					'event_espresso'
2261
+				),
2262
+				__FILE__,
2263
+				__FUNCTION__,
2264
+				__LINE__
2265
+			);
2266
+		} else {
2267
+			EE_Error::add_error(
2268
+				esc_html__(
2269
+					'You do not have access to delete a payment.',
2270
+					'event_espresso'
2271
+				),
2272
+				__FILE__,
2273
+				__FUNCTION__,
2274
+				__LINE__
2275
+			);
2276
+		}
2277
+		$query_args = [
2278
+			'page'   => 'espresso_transactions',
2279
+			'action' => 'view_transaction',
2280
+			'TXN_ID' => $TXD_ID,
2281
+		];
2282
+		$this->_redirect_after_action(
2283
+			! EE_Error::has_error(),
2284
+			$amount > 0
2285
+				? esc_html__('payment', 'event_espresso')
2286
+				: esc_html__('refund', 'event_espresso'),
2287
+			esc_html__('deleted', 'event_espresso'),
2288
+			$query_args
2289
+		);
2290
+	}
2291
+
2292
+
2293
+	/**
2294
+	 * _registration_payment_data_array
2295
+	 * adds info for 'owing' and 'paid' for each registration to the json response
2296
+	 *
2297
+	 * @access protected
2298
+	 * @param array $REG_IDs
2299
+	 * @return array
2300
+	 * @throws EE_Error
2301
+	 * @throws InvalidArgumentException
2302
+	 * @throws InvalidDataTypeException
2303
+	 * @throws InvalidInterfaceException
2304
+	 * @throws ReflectionException
2305
+	 */
2306
+	protected function _registration_payment_data_array($REG_IDs)
2307
+	{
2308
+		$registration_payment_data = [];
2309
+		// if non empty reg_ids lets get an array of registrations and update the values for the apply_payment/refund rows.
2310
+		if (! empty($REG_IDs)) {
2311
+			$registrations = EEM_Registration::instance()->get_all([['REG_ID' => ['IN', $REG_IDs]]]);
2312
+			foreach ($registrations as $registration) {
2313
+				if ($registration instanceof EE_Registration) {
2314
+					$registration_payment_data[ $registration->ID() ] = [
2315
+						'paid'  => $registration->pretty_paid(),
2316
+						'owing' => EEH_Template::format_currency($registration->final_price() - $registration->paid()),
2317
+					];
2318
+				}
2319
+			}
2320
+		}
2321
+
2322
+		return $registration_payment_data;
2323
+	}
2324
+
2325
+
2326
+	/**
2327
+	 * _maybe_send_notifications
2328
+	 * determines whether or not the admin has indicated that notifications should be sent.
2329
+	 * If so, will toggle a filter switch for delivering registration notices.
2330
+	 * If passed an EE_Payment object, then it will trigger payment notifications instead.
2331
+	 *
2332
+	 * @access protected
2333
+	 * @param EE_Payment | null $payment
2334
+	 */
2335
+	protected function _maybe_send_notifications($payment = null)
2336
+	{
2337
+		switch ($payment instanceof EE_Payment) {
2338
+			// payment notifications
2339
+			case true:
2340
+				if ($this->request->getRequestParam('txn_payments[send_notifications]', false, 'bool')) {
2341
+					$this->_process_payment_notification($payment);
2342
+				}
2343
+				break;
2344
+			// registration notifications
2345
+			case false:
2346
+				if ($this->request->getRequestParam('txn_reg_status_change[send_notifications]', false, 'bool')) {
2347
+					add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true');
2348
+				}
2349
+				break;
2350
+		}
2351
+	}
2352
+
2353
+
2354
+	/**
2355
+	 * _send_payment_reminder
2356
+	 *    generates HTML for the View Transaction Details Admin page
2357
+	 *
2358
+	 * @access protected
2359
+	 * @return void
2360
+	 * @throws EE_Error
2361
+	 * @throws InvalidArgumentException
2362
+	 * @throws InvalidDataTypeException
2363
+	 * @throws InvalidInterfaceException
2364
+	 */
2365
+	protected function _send_payment_reminder()
2366
+	{
2367
+		$TXN_ID      = $this->request->getRequestParam('TXN_ID', 0, 'int');
2368
+		$transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
2369
+		$redirect_to = $this->request->getRequestParam('redirect_to');
2370
+		$query_args  = $redirect_to
2371
+			? ['action' => $redirect_to, 'TXN_ID' => $TXN_ID,]
2372
+			: [];
2373
+		do_action(
2374
+			'AHEE__Transactions_Admin_Page___send_payment_reminder__process_admin_payment_reminder',
2375
+			$transaction
2376
+		);
2377
+		$this->_redirect_after_action(
2378
+			false,
2379
+			esc_html__('payment reminder', 'event_espresso'),
2380
+			esc_html__('sent', 'event_espresso'),
2381
+			$query_args,
2382
+			true
2383
+		);
2384
+	}
2385
+
2386
+
2387
+	/**
2388
+	 *  get_transactions
2389
+	 *    get transactions for given parameters (used by list table)
2390
+	 *
2391
+	 * @param int     $per_page how many transactions displayed per page
2392
+	 * @param boolean $count    return the count or objects
2393
+	 * @param string  $view
2394
+	 * @return EE_Transaction[]|int int = count || array of transaction objects
2395
+	 * @throws EE_Error
2396
+	 * @throws InvalidArgumentException
2397
+	 * @throws InvalidDataTypeException
2398
+	 * @throws InvalidInterfaceException
2399
+	 * @throws ReflectionException
2400
+	 */
2401
+	public function get_transactions($per_page, $count = false, $view = '')
2402
+	{
2403
+		$start_date = wp_strip_all_tags(
2404
+			$this->request->getRequestParam('txn-filter-start-date', date('m/d/Y', strtotime('-10 year')))
2405
+		);
2406
+		$end_date   = wp_strip_all_tags(
2407
+			$this->request->getRequestParam('txn-filter-end-date', date('m/d/Y'))
2408
+		);
2409
+
2410
+		// make sure our timestamps start and end right at the boundaries for each day
2411
+		$start_date = date('Y-m-d', strtotime($start_date)) . ' 00:00:00';
2412
+		$end_date   = date('Y-m-d', strtotime($end_date)) . ' 23:59:59';
2413
+
2414
+
2415
+		// convert to timestamps
2416
+		$start_date = strtotime($start_date);
2417
+		$end_date   = strtotime($end_date);
2418
+
2419
+		// makes sure start date is the lowest value and vice versa
2420
+		$start_date = min($start_date, $end_date);
2421
+		$end_date   = max($start_date, $end_date);
2422
+
2423
+		// convert to correct format for query
2424
+		$start_date = EEM_Transaction::instance()->convert_datetime_for_query(
2425
+			'TXN_timestamp',
2426
+			date('Y-m-d H:i:s', $start_date),
2427
+			'Y-m-d H:i:s'
2428
+		);
2429
+		$end_date   = EEM_Transaction::instance()->convert_datetime_for_query(
2430
+			'TXN_timestamp',
2431
+			date('Y-m-d H:i:s', $end_date),
2432
+			'Y-m-d H:i:s'
2433
+		);
2434
+
2435
+
2436
+		// set orderby
2437
+		$orderby = $this->request->getRequestParam('orderby');
2438
+
2439
+		switch ($orderby) {
2440
+			case 'TXN_ID':
2441
+				break;
2442
+			case 'ATT_fname':
2443
+				$orderby = 'Registration.Attendee.ATT_fname';
2444
+				break;
2445
+			case 'event_name':
2446
+				$orderby = 'Registration.Event.EVT_name';
2447
+				break;
2448
+			default: // 'TXN_timestamp'
2449
+				$orderby = 'TXN_timestamp';
2450
+		}
2451
+
2452
+		$sort         = $this->request->getRequestParam('order', 'DESC');
2453
+		$current_page = $this->request->getRequestParam('paged', 1, 'int');
2454
+
2455
+		$per_page = absint($per_page)
2456
+			? $per_page
2457
+			: 10;
2458
+		$per_page = $this->request->getRequestParam('perpage', $per_page, 'int');
2459
+
2460
+		$offset = ($current_page - 1) * $per_page;
2461
+		$limit  = [$offset, $per_page];
2462
+
2463
+		$_where = [
2464
+			'TXN_timestamp'          => ['BETWEEN', [$start_date, $end_date]],
2465
+			'Registration.REG_count' => 1,
2466
+		];
2467
+
2468
+		$EVT_ID = $this->request->getRequestParam('EVT_ID', 0, 'int');
2469
+		if ($EVT_ID) {
2470
+			$_where['Registration.EVT_ID'] = $EVT_ID;
2471
+		}
2472
+
2473
+		$search_term = $this->request->getRequestParam('s');
2474
+		if ($search_term) {
2475
+			$search_term  = '%' . $search_term . '%';
2476
+			$_where['OR'] = [
2477
+				'Registration.Event.EVT_name'         => ['LIKE', $search_term],
2478
+				'Registration.Event.EVT_desc'         => ['LIKE', $search_term],
2479
+				'Registration.Event.EVT_short_desc'   => ['LIKE', $search_term],
2480
+				'Registration.Attendee.ATT_full_name' => ['LIKE', $search_term],
2481
+				'Registration.Attendee.ATT_fname'     => ['LIKE', $search_term],
2482
+				'Registration.Attendee.ATT_lname'     => ['LIKE', $search_term],
2483
+				'Registration.Attendee.ATT_short_bio' => ['LIKE', $search_term],
2484
+				'Registration.Attendee.ATT_email'     => ['LIKE', $search_term],
2485
+				'Registration.Attendee.ATT_address'   => ['LIKE', $search_term],
2486
+				'Registration.Attendee.ATT_address2'  => ['LIKE', $search_term],
2487
+				'Registration.Attendee.ATT_city'      => ['LIKE', $search_term],
2488
+				'Registration.REG_final_price'        => ['LIKE', $search_term],
2489
+				'Registration.REG_code'               => ['LIKE', $search_term],
2490
+				'Registration.REG_count'              => ['LIKE', $search_term],
2491
+				'Registration.REG_group_size'         => ['LIKE', $search_term],
2492
+				'Registration.Ticket.TKT_name'        => ['LIKE', $search_term],
2493
+				'Registration.Ticket.TKT_description' => ['LIKE', $search_term],
2494
+				'Payment.PAY_source'                  => ['LIKE', $search_term],
2495
+				'Payment.Payment_Method.PMD_name'     => ['LIKE', $search_term],
2496
+				'TXN_session_data'                    => ['LIKE', $search_term],
2497
+				'Payment.PAY_txn_id_chq_nmbr'         => ['LIKE', $search_term],
2498
+			];
2499
+		}
2500
+
2501
+		$status = $this->request->getRequestParam('status');
2502
+		// failed transactions
2503
+		$failed     = (! empty($status) && $status === 'failed' && ! $count) || ($count && $view === 'failed');
2504
+		$abandoned  = (! empty($status) && $status === 'abandoned' && ! $count) || ($count && $view === 'abandoned');
2505
+		$incomplete = (! empty($status) && $status === 'incomplete' && ! $count) || ($count && $view === 'incomplete');
2506
+
2507
+		if ($failed) {
2508
+			$_where['STS_ID'] = EEM_Transaction::failed_status_code;
2509
+		} elseif ($abandoned) {
2510
+			$_where['STS_ID'] = EEM_Transaction::abandoned_status_code;
2511
+		} elseif ($incomplete) {
2512
+			$_where['STS_ID'] = EEM_Transaction::incomplete_status_code;
2513
+		} else {
2514
+			$_where['STS_ID']  = ['!=', EEM_Transaction::failed_status_code];
2515
+			$_where['STS_ID*'] = ['!=', EEM_Transaction::abandoned_status_code];
2516
+		}
2517
+
2518
+		$query_params = apply_filters(
2519
+			'FHEE__Transactions_Admin_Page___get_transactions_query_params',
2520
+			[
2521
+				$_where,
2522
+				'order_by'                 => [$orderby => $sort],
2523
+				'limit'                    => $limit,
2524
+				'default_where_conditions' => EEM_Base::default_where_conditions_this_only,
2525
+			],
2526
+			$this->request->requestParams(),
2527
+			$view,
2528
+			$count
2529
+		);
2530
+
2531
+		return $count
2532
+			? EEM_Transaction::instance()->count([$query_params[0]], 'TXN_ID', true)
2533
+			: EEM_Transaction::instance()->get_all($query_params);
2534
+	}
2535
+
2536
+
2537
+	/**
2538
+	 * @throws EE_Error
2539
+	 * @throws InvalidArgumentException
2540
+	 * @throws InvalidDataTypeException
2541
+	 * @throws InvalidInterfaceException
2542
+	 * @throws ReflectionException
2543
+	 * @throws RuntimeException
2544
+	 * @since 4.9.79.p
2545
+	 */
2546
+	public function recalculateLineItems()
2547
+	{
2548
+		$TXN_ID = $this->request->getRequestParam('TXN_ID', 0, 'int');
2549
+		/** @var EE_Transaction $transaction */
2550
+		$transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
2551
+		$success     = $transaction->recalculateLineItems();
2552
+		$redirect_to = $this->request->getRequestParam('redirect_to');
2553
+		$query_args  = $redirect_to
2554
+			? ['action' => $redirect_to, 'TXN_ID' => $TXN_ID,]
2555
+			: [];
2556
+		$this->_redirect_after_action(
2557
+			$success,
2558
+			esc_html__('Transaction taxes and totals', 'event_espresso'),
2559
+			esc_html__('recalculated', 'event_espresso'),
2560
+			$query_args,
2561
+			true
2562
+		);
2563
+	}
2564 2564
 }
Please login to merge, or discard this patch.
Spacing   +103 added lines, -103 removed lines patch added patch discarded remove patch
@@ -243,7 +243,7 @@  discard block
 block discarded – undo
243 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 244
             'event_espresso'
245 245
         );
246
-        EE_Registry::$i18n_js_strings['error_occurred']          = esc_html__(
246
+        EE_Registry::$i18n_js_strings['error_occurred'] = esc_html__(
247 247
             'An error occurred! Please refresh the page and try again.',
248 248
             'event_espresso'
249 249
         );
@@ -344,7 +344,7 @@  discard block
 block discarded – undo
344 344
         // enqueue style
345 345
         wp_register_style(
346 346
             'espresso_txn',
347
-            TXN_ASSETS_URL . 'espresso_transactions_admin.css',
347
+            TXN_ASSETS_URL.'espresso_transactions_admin.css',
348 348
             [],
349 349
             EVENT_ESPRESSO_VERSION
350 350
         );
@@ -352,7 +352,7 @@  discard block
 block discarded – undo
352 352
         // scripts
353 353
         wp_register_script(
354 354
             'espresso_txn',
355
-            TXN_ASSETS_URL . 'espresso_transactions_admin.js',
355
+            TXN_ASSETS_URL.'espresso_transactions_admin.js',
356 356
             [
357 357
                 'ee_admin_js',
358 358
                 'ee-datepicker',
@@ -479,7 +479,7 @@  discard block
 block discarded – undo
479 479
             $this->_transaction->verify_abandoned_transaction_status();
480 480
         }
481 481
 
482
-        if (! $this->_transaction instanceof EE_Transaction) {
482
+        if ( ! $this->_transaction instanceof EE_Transaction) {
483 483
             $error_msg = sprintf(
484 484
                 esc_html__(
485 485
                     'An error occurred and the details for the transaction with the ID # %d could not be retrieved.',
@@ -576,7 +576,7 @@  discard block
 block discarded – undo
576 576
             'FHEE__Transactions_Admin_Page___transaction_legend_items__more_items',
577 577
             [
578 578
                 'overpaid'   => [
579
-                    'class' => 'ee-status-legend ee-status-bg--' . EEM_Transaction::overpaid_status_code,
579
+                    'class' => 'ee-status-legend ee-status-bg--'.EEM_Transaction::overpaid_status_code,
580 580
                     'desc'  => EEH_Template::pretty_status(
581 581
                         EEM_Transaction::overpaid_status_code,
582 582
                         false,
@@ -584,7 +584,7 @@  discard block
 block discarded – undo
584 584
                     ),
585 585
                 ],
586 586
                 'complete'   => [
587
-                    'class' => 'ee-status-legend ee-status-bg--' . EEM_Transaction::complete_status_code,
587
+                    'class' => 'ee-status-legend ee-status-bg--'.EEM_Transaction::complete_status_code,
588 588
                     'desc'  => EEH_Template::pretty_status(
589 589
                         EEM_Transaction::complete_status_code,
590 590
                         false,
@@ -592,7 +592,7 @@  discard block
 block discarded – undo
592 592
                     ),
593 593
                 ],
594 594
                 'incomplete' => [
595
-                    'class' => 'ee-status-legend ee-status-bg--' . EEM_Transaction::incomplete_status_code,
595
+                    'class' => 'ee-status-legend ee-status-bg--'.EEM_Transaction::incomplete_status_code,
596 596
                     'desc'  => EEH_Template::pretty_status(
597 597
                         EEM_Transaction::incomplete_status_code,
598 598
                         false,
@@ -600,7 +600,7 @@  discard block
 block discarded – undo
600 600
                     ),
601 601
                 ],
602 602
                 'abandoned'  => [
603
-                    'class' => 'ee-status-legend ee-status-bg--' . EEM_Transaction::abandoned_status_code,
603
+                    'class' => 'ee-status-legend ee-status-bg--'.EEM_Transaction::abandoned_status_code,
604 604
                     'desc'  => EEH_Template::pretty_status(
605 605
                         EEM_Transaction::abandoned_status_code,
606 606
                         false,
@@ -608,7 +608,7 @@  discard block
 block discarded – undo
608 608
                     ),
609 609
                 ],
610 610
                 'failed'     => [
611
-                    'class' => 'ee-status-legend ee-status-bg--' . EEM_Transaction::failed_status_code,
611
+                    'class' => 'ee-status-legend ee-status-bg--'.EEM_Transaction::failed_status_code,
612 612
                     'desc'  => EEH_Template::pretty_status(
613 613
                         EEM_Transaction::failed_status_code,
614 614
                         false,
@@ -651,11 +651,11 @@  discard block
 block discarded – undo
651 651
                 )
652 652
                 . '" aria-label="'
653 653
                 . esc_attr__('Click to Edit event', 'event_espresso')
654
-                . '">' . $event->name() . '</a>',
654
+                . '">'.$event->name().'</a>',
655 655
                 '</h3>'
656 656
             )
657 657
             : '';
658
-        $this->_template_args['after_list_table']  = $this->_display_legend($this->_transaction_legend_items());
658
+        $this->_template_args['after_list_table'] = $this->_display_legend($this->_transaction_legend_items());
659 659
         $this->display_admin_list_table_page_with_no_sidebar();
660 660
     }
661 661
 
@@ -685,7 +685,7 @@  discard block
 block discarded – undo
685 685
 
686 686
         $this->_set_transaction_object();
687 687
 
688
-        if (! $this->_transaction instanceof EE_Transaction) {
688
+        if ( ! $this->_transaction instanceof EE_Transaction) {
689 689
             return;
690 690
         }
691 691
 
@@ -695,7 +695,7 @@  discard block
 block discarded – undo
695 695
         $this->_template_args['txn_datetime']['value'] = $this->_transaction->get_i18n_datetime('TXN_timestamp');
696 696
         $this->_template_args['txn_datetime']['label'] = esc_html__('Date', 'event_espresso');
697 697
 
698
-        $this->_template_args['txn_status']['value'] = self::$_txn_status[ $this->_transaction->status_ID() ];
698
+        $this->_template_args['txn_status']['value'] = self::$_txn_status[$this->_transaction->status_ID()];
699 699
         $this->_template_args['txn_status']['label'] = esc_html__('Transaction Status', 'event_espresso');
700 700
         $this->_template_args['txn_status']['class'] = $this->_transaction->status_ID();
701 701
 
@@ -740,7 +740,7 @@  discard block
 block discarded – undo
740 740
 
741 741
 
742 742
         // next link
743
-        $next_txn                                 = $this->_transaction->next(
743
+        $next_txn = $this->_transaction->next(
744 744
             null,
745 745
             [['STS_ID' => ['!=', EEM_Transaction::failed_status_code]]],
746 746
             'TXN_ID'
@@ -755,7 +755,7 @@  discard block
 block discarded – undo
755 755
             )
756 756
             : '';
757 757
         // previous link
758
-        $previous_txn                                 = $this->_transaction->previous(
758
+        $previous_txn = $this->_transaction->previous(
759 759
             null,
760 760
             [['STS_ID' => ['!=', EEM_Transaction::failed_status_code]]],
761 761
             'TXN_ID'
@@ -807,7 +807,7 @@  discard block
 block discarded – undo
807 807
         // grab messages at the last second
808 808
         $this->_template_args['notices'] = EE_Error::get_notices();
809 809
         // path to template
810
-        $template_path                             = TXN_TEMPLATE_PATH . 'txn_admin_details_header.template.php';
810
+        $template_path                             = TXN_TEMPLATE_PATH.'txn_admin_details_header.template.php';
811 811
         $this->_template_args['admin_page_header'] = EEH_Template::display_template(
812 812
             $template_path,
813 813
             $this->_template_args,
@@ -835,19 +835,19 @@  discard block
 block discarded – undo
835 835
     {
836 836
         $this->_set_transaction_object();
837 837
 
838
-        if (! $this->_transaction instanceof EE_Transaction) {
838
+        if ( ! $this->_transaction instanceof EE_Transaction) {
839 839
             return;
840 840
         }
841 841
         $this->addMetaBox(
842 842
             'edit-txn-details-mbox',
843
-            '<span>' . esc_html__('Transaction Details', 'event_espresso')
843
+            '<span>'.esc_html__('Transaction Details', 'event_espresso')
844 844
             . '&nbsp;<span class="dashicons dashicons-cart" ></span></span>',
845 845
             [$this, 'txn_details_meta_box'],
846 846
             $this->_wp_page_slug
847 847
         );
848 848
         $this->addMetaBox(
849 849
             'edit-txn-attendees-mbox',
850
-            '<span>' . esc_html__('Attendees Registered in this Transaction', 'event_espresso')
850
+            '<span>'.esc_html__('Attendees Registered in this Transaction', 'event_espresso')
851 851
             . '&nbsp;<span class="dashicons dashicons-groups" ></span></span>',
852 852
             [$this, 'txn_attendees_meta_box'],
853 853
             $this->_wp_page_slug,
@@ -889,7 +889,7 @@  discard block
 block discarded – undo
889 889
     {
890 890
         $content = '';
891 891
         $actions = [];
892
-        if (! $transaction instanceof EE_Transaction) {
892
+        if ( ! $transaction instanceof EE_Transaction) {
893 893
             return $content;
894 894
         }
895 895
         /** @var EE_Registration $primary_registration */
@@ -1000,7 +1000,7 @@  discard block
 block discarded – undo
1000 1000
             $this->_transaction->primary_registration() instanceof EE_Registration
1001 1001
                 ? $this->_transaction->primary_registration()->attendee()
1002 1002
                 : null;
1003
-        $this->_template_args['can_edit_payments']   = $this->capabilities->current_user_can(
1003
+        $this->_template_args['can_edit_payments'] = $this->capabilities->current_user_can(
1004 1004
             'ee_edit_payments',
1005 1005
             'apply_payment_or_refund_from_registration_details'
1006 1006
         );
@@ -1011,7 +1011,7 @@  discard block
 block discarded – undo
1011 1011
 
1012 1012
         // get line table
1013 1013
         EEH_Autoloader::register_line_item_display_autoloaders();
1014
-        $Line_Item_Display                       = new EE_Line_Item_Display(
1014
+        $Line_Item_Display = new EE_Line_Item_Display(
1015 1015
             'admin_table',
1016 1016
             'EE_Admin_Table_Line_Item_Display_Strategy'
1017 1017
         );
@@ -1028,7 +1028,7 @@  discard block
 block discarded – undo
1028 1028
             ? $taxes
1029 1029
             : false;
1030 1030
 
1031
-        $this->_template_args['grand_total']     = EEH_Template::format_currency(
1031
+        $this->_template_args['grand_total'] = EEH_Template::format_currency(
1032 1032
             $this->_transaction->total(),
1033 1033
             false,
1034 1034
             false
@@ -1038,7 +1038,7 @@  discard block
 block discarded – undo
1038 1038
 
1039 1039
         // process payment details
1040 1040
         $payments = $this->_transaction->payments();
1041
-        if (! empty($payments)) {
1041
+        if ( ! empty($payments)) {
1042 1042
             $this->_template_args['payments']              = $payments;
1043 1043
             $this->_template_args['existing_reg_payments'] = $this->_get_registration_payment_IDs($payments);
1044 1044
         } else {
@@ -1096,7 +1096,7 @@  discard block
 block discarded – undo
1096 1096
                                   esc_html__('%1$s : Initiated %2$s', 'event_espresso'),
1097 1097
                                   ucwords(str_replace('_', ' ', $reg_step)),
1098 1098
                                   date(
1099
-                                      get_option('date_format') . ' ' . get_option('time_format'),
1099
+                                      get_option('date_format').' '.get_option('time_format'),
1100 1100
                                       $reg_step_status + (get_option('gmt_offset') * HOUR_IN_SECONDS)
1101 1101
                                   )
1102 1102
                               )
@@ -1110,7 +1110,7 @@  discard block
 block discarded – undo
1110 1110
                               . '</div>';
1111 1111
             }
1112 1112
         }
1113
-        $reg_steps                                                 .= '</ul>';
1113
+        $reg_steps .= '</ul>';
1114 1114
         $this->_template_args['txn_details']['reg_steps']['value'] = $reg_steps;
1115 1115
         $this->_template_args['txn_details']['reg_steps']['label'] = esc_html__(
1116 1116
             'Registration Step Progress',
@@ -1123,14 +1123,14 @@  discard block
 block discarded – undo
1123 1123
         $this->_get_payment_status_array();
1124 1124
         $this->_get_reg_status_selection(); // sets up the template args for the reg status array for the transaction.
1125 1125
 
1126
-        $this->_template_args['transaction_form_url']    = add_query_arg(
1126
+        $this->_template_args['transaction_form_url'] = add_query_arg(
1127 1127
             [
1128 1128
                 'action'  => 'edit_transaction',
1129 1129
                 'process' => 'transaction',
1130 1130
             ],
1131 1131
             TXN_ADMIN_URL
1132 1132
         );
1133
-        $this->_template_args['apply_payment_form_url']  = add_query_arg(
1133
+        $this->_template_args['apply_payment_form_url'] = add_query_arg(
1134 1134
             [
1135 1135
                 'page'   => 'espresso_transactions',
1136 1136
                 'action' => 'espresso_apply_payment',
@@ -1149,7 +1149,7 @@  discard block
 block discarded – undo
1149 1149
 
1150 1150
         // 'espresso_delete_payment_nonce'
1151 1151
 
1152
-        $template_path = TXN_TEMPLATE_PATH . 'txn_admin_details_main_meta_box_txn_details.template.php';
1152
+        $template_path = TXN_TEMPLATE_PATH.'txn_admin_details_main_meta_box_txn_details.template.php';
1153 1153
         echo EEH_Template::display_template($template_path, $this->_template_args, true);
1154 1154
     }
1155 1155
 
@@ -1181,19 +1181,19 @@  discard block
 block discarded – undo
1181 1181
                 ],
1182 1182
             ]
1183 1183
         );
1184
-        if (! empty($reg_payments)) {
1184
+        if ( ! empty($reg_payments)) {
1185 1185
             foreach ($payments as $payment) {
1186
-                if (! $payment instanceof EE_Payment) {
1186
+                if ( ! $payment instanceof EE_Payment) {
1187 1187
                     continue;
1188
-                } elseif (! isset($existing_reg_payments[ $payment->ID() ])) {
1189
-                    $existing_reg_payments[ $payment->ID() ] = [];
1188
+                } elseif ( ! isset($existing_reg_payments[$payment->ID()])) {
1189
+                    $existing_reg_payments[$payment->ID()] = [];
1190 1190
                 }
1191 1191
                 foreach ($reg_payments as $reg_payment) {
1192 1192
                     if (
1193 1193
                         $reg_payment instanceof EE_Registration_Payment
1194 1194
                         && $reg_payment->payment_ID() === $payment->ID()
1195 1195
                     ) {
1196
-                        $existing_reg_payments[ $payment->ID() ][] = $reg_payment->registration_ID();
1196
+                        $existing_reg_payments[$payment->ID()][] = $reg_payment->registration_ID();
1197 1197
                     }
1198 1198
                 }
1199 1199
             }
@@ -1219,7 +1219,7 @@  discard block
 block discarded – undo
1219 1219
     protected function _get_registrations_to_apply_payment_to()
1220 1220
     {
1221 1221
         // we want any registration with an active status (ie: not deleted or cancelled)
1222
-        $query_params                      = [
1222
+        $query_params = [
1223 1223
             [
1224 1224
                 'STS_ID' => [
1225 1225
                     'IN',
@@ -1231,22 +1231,22 @@  discard block
 block discarded – undo
1231 1231
                 ],
1232 1232
             ],
1233 1233
         ];
1234
-        $registrations_to_apply_payment_to = EEH_HTML::br() . EEH_HTML::div(
1234
+        $registrations_to_apply_payment_to = EEH_HTML::br().EEH_HTML::div(
1235 1235
                 '',
1236 1236
                 'txn-admin-apply-payment-to-registrations-dv',
1237 1237
                 '',
1238 1238
                 'clear: both; margin: 1.5em 0 0; display: none;'
1239 1239
             );
1240
-        $registrations_to_apply_payment_to .= EEH_HTML::br() . EEH_HTML::div('', '', 'admin-primary-mbox-tbl-wrap');
1240
+        $registrations_to_apply_payment_to .= EEH_HTML::br().EEH_HTML::div('', '', 'admin-primary-mbox-tbl-wrap');
1241 1241
         $registrations_to_apply_payment_to .= EEH_HTML::table('', '', 'admin-primary-mbox-tbl striped');
1242 1242
         $registrations_to_apply_payment_to .= EEH_HTML::thead(
1243 1243
             EEH_HTML::tr(
1244
-                EEH_HTML::th(esc_html__('ID', 'event_espresso')) .
1245
-                EEH_HTML::th(esc_html__('Registrant', 'event_espresso')) .
1246
-                EEH_HTML::th(esc_html__('Ticket', 'event_espresso')) .
1247
-                EEH_HTML::th(esc_html__('Event', 'event_espresso')) .
1248
-                EEH_HTML::th(esc_html__('Paid', 'event_espresso'), '', 'txn-admin-payment-paid-td jst-cntr') .
1249
-                EEH_HTML::th(esc_html__('Owing', 'event_espresso'), '', 'txn-admin-payment-owing-td jst-cntr') .
1244
+                EEH_HTML::th(esc_html__('ID', 'event_espresso')).
1245
+                EEH_HTML::th(esc_html__('Registrant', 'event_espresso')).
1246
+                EEH_HTML::th(esc_html__('Ticket', 'event_espresso')).
1247
+                EEH_HTML::th(esc_html__('Event', 'event_espresso')).
1248
+                EEH_HTML::th(esc_html__('Paid', 'event_espresso'), '', 'txn-admin-payment-paid-td jst-cntr').
1249
+                EEH_HTML::th(esc_html__('Owing', 'event_espresso'), '', 'txn-admin-payment-owing-td jst-cntr').
1250 1250
                 EEH_HTML::th(esc_html__('Apply', 'event_espresso'), '', 'jst-cntr')
1251 1251
             )
1252 1252
         );
@@ -1261,36 +1261,36 @@  discard block
 block discarded – undo
1261 1261
                     : esc_html__('Unknown Attendee', 'event_espresso');
1262 1262
                 $owing                             = $registration->final_price() - $registration->paid();
1263 1263
                 $taxable                           = $registration->ticket()->taxable()
1264
-                    ? ' <span class="smaller-text lt-grey-text"> ' . esc_html__('+ tax', 'event_espresso') . '</span>'
1264
+                    ? ' <span class="smaller-text lt-grey-text"> '.esc_html__('+ tax', 'event_espresso').'</span>'
1265 1265
                     : '';
1266 1266
                 $checked                           = empty($existing_reg_payments)
1267 1267
                                                      || in_array($registration->ID(), $existing_reg_payments, true)
1268 1268
                     ? ' checked'
1269 1269
                     : '';
1270
-                $disabled                          = $registration->final_price() > 0
1270
+                $disabled = $registration->final_price() > 0
1271 1271
                     ? ''
1272 1272
                     : ' disabled';
1273 1273
                 $registrations_to_apply_payment_to .= EEH_HTML::tr(
1274
-                    EEH_HTML::td($registration->ID()) .
1275
-                    EEH_HTML::td($attendee_name) .
1274
+                    EEH_HTML::td($registration->ID()).
1275
+                    EEH_HTML::td($attendee_name).
1276 1276
                     EEH_HTML::td(
1277
-                        $registration->ticket()->name() . ' : ' . $registration->ticket()->pretty_price() . $taxable
1278
-                    ) .
1279
-                    EEH_HTML::td($registration->event_name()) .
1280
-                    EEH_HTML::td($registration->pretty_paid(), '', 'txn-admin-payment-paid-td jst-cntr') .
1277
+                        $registration->ticket()->name().' : '.$registration->ticket()->pretty_price().$taxable
1278
+                    ).
1279
+                    EEH_HTML::td($registration->event_name()).
1280
+                    EEH_HTML::td($registration->pretty_paid(), '', 'txn-admin-payment-paid-td jst-cntr').
1281 1281
                     EEH_HTML::td(
1282 1282
                         EEH_Template::format_currency($owing),
1283 1283
                         '',
1284 1284
                         'txn-admin-payment-owing-td jst-cntr'
1285
-                    ) .
1285
+                    ).
1286 1286
                     EEH_HTML::td(
1287
-                        '<input type="checkbox" value="' . $registration->ID()
1287
+                        '<input type="checkbox" value="'.$registration->ID()
1288 1288
                         . '" name="txn_admin_payment[registrations]"'
1289
-                        . $checked . $disabled . '>',
1289
+                        . $checked.$disabled.'>',
1290 1290
                         '',
1291 1291
                         'jst-cntr'
1292 1292
                     ),
1293
-                    'apply-payment-registration-row-' . $registration->ID()
1293
+                    'apply-payment-registration-row-'.$registration->ID()
1294 1294
                 );
1295 1295
             }
1296 1296
         }
@@ -1305,7 +1305,7 @@  discard block
 block discarded – undo
1305 1305
             '',
1306 1306
             'clear description'
1307 1307
         );
1308
-        $registrations_to_apply_payment_to                         .= EEH_HTML::divx();
1308
+        $registrations_to_apply_payment_to .= EEH_HTML::divx();
1309 1309
         $this->_template_args['registrations_to_apply_payment_to'] = $registrations_to_apply_payment_to;
1310 1310
     }
1311 1311
 
@@ -1371,12 +1371,12 @@  discard block
 block discarded – undo
1371 1371
                 [
1372 1372
                     'OR*payment_method_for_payment' => [
1373 1373
                         'PMD_ID'    => ['IN', $payment_methods_of_payments],
1374
-                        'PMD_scope' => ['LIKE', '%' . EEM_Payment_Method::scope_admin . '%'],
1374
+                        'PMD_scope' => ['LIKE', '%'.EEM_Payment_Method::scope_admin.'%'],
1375 1375
                     ],
1376 1376
                 ],
1377 1377
             ];
1378 1378
         } else {
1379
-            $query_args = [['PMD_scope' => ['LIKE', '%' . EEM_Payment_Method::scope_admin . '%']]];
1379
+            $query_args = [['PMD_scope' => ['LIKE', '%'.EEM_Payment_Method::scope_admin.'%']]];
1380 1380
         }
1381 1381
         $this->_template_args['payment_methods'] = EEM_Payment_Method::instance()->get_all($query_args);
1382 1382
     }
@@ -1408,7 +1408,7 @@  discard block
 block discarded – undo
1408 1408
             'Line_Item',
1409 1409
             [['LIN_type' => 'line-item']]
1410 1410
         );
1411
-        if (! empty($line_items)) {
1411
+        if ( ! empty($line_items)) {
1412 1412
             foreach ($line_items as $item) {
1413 1413
                 if ($item instanceof EE_Line_Item) {
1414 1414
                     switch ($item->OBJ_type()) {
@@ -1418,7 +1418,7 @@  discard block
 block discarded – undo
1418 1418
                             $ticket = $item->ticket();
1419 1419
                             // right now we're only handling tickets here.
1420 1420
                             // Cause its expected that only tickets will have attendees right?
1421
-                            if (! $ticket instanceof EE_Ticket) {
1421
+                            if ( ! $ticket instanceof EE_Ticket) {
1422 1422
                                 break;
1423 1423
                             }
1424 1424
                             try {
@@ -1427,45 +1427,45 @@  discard block
 block discarded – undo
1427 1427
                                 EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1428 1428
                                 $event_name = esc_html__('Unknown Event', 'event_espresso');
1429 1429
                             }
1430
-                            $event_name   .= ' - ' . $item->name();
1430
+                            $event_name   .= ' - '.$item->name();
1431 1431
                             $ticket_price = EEH_Template::format_currency($item->unit_price());
1432 1432
                             // now get all of the registrations for this transaction that use this ticket
1433 1433
                             $registrations = $ticket->registrations(
1434 1434
                                 [['TXN_ID' => $this->_transaction->ID()]]
1435 1435
                             );
1436 1436
                             foreach ($registrations as $registration) {
1437
-                                if (! $registration instanceof EE_Registration) {
1437
+                                if ( ! $registration instanceof EE_Registration) {
1438 1438
                                     break;
1439 1439
                                 }
1440
-                                $this->_template_args['event_attendees'][ $registration->ID() ]['STS_ID']
1440
+                                $this->_template_args['event_attendees'][$registration->ID()]['STS_ID']
1441 1441
                                     = $registration->status_ID();
1442
-                                $this->_template_args['event_attendees'][ $registration->ID() ]['att_num']
1442
+                                $this->_template_args['event_attendees'][$registration->ID()]['att_num']
1443 1443
                                     = $registration->count();
1444
-                                $this->_template_args['event_attendees'][ $registration->ID() ]['event_ticket_name']
1444
+                                $this->_template_args['event_attendees'][$registration->ID()]['event_ticket_name']
1445 1445
                                     = $event_name;
1446
-                                $this->_template_args['event_attendees'][ $registration->ID() ]['ticket_price']
1446
+                                $this->_template_args['event_attendees'][$registration->ID()]['ticket_price']
1447 1447
                                     = $ticket_price;
1448 1448
                                 // attendee info
1449 1449
                                 $attendee = $registration->get_first_related('Attendee');
1450 1450
                                 if ($attendee instanceof EE_Attendee) {
1451
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['att_id']
1451
+                                    $this->_template_args['event_attendees'][$registration->ID()]['att_id']
1452 1452
                                         = $attendee->ID();
1453
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['attendee']
1453
+                                    $this->_template_args['event_attendees'][$registration->ID()]['attendee']
1454 1454
                                         = $attendee->full_name();
1455
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['email']
1456
-                                        = '<a href="mailto:' . $attendee->email() . '?subject=' . $event_name
1455
+                                    $this->_template_args['event_attendees'][$registration->ID()]['email']
1456
+                                        = '<a href="mailto:'.$attendee->email().'?subject='.$event_name
1457 1457
                                           . esc_html__(
1458 1458
                                               ' Event',
1459 1459
                                               'event_espresso'
1460 1460
                                           )
1461
-                                          . '">' . $attendee->email() . '</a>';
1462
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['address']
1461
+                                          . '">'.$attendee->email().'</a>';
1462
+                                    $this->_template_args['event_attendees'][$registration->ID()]['address']
1463 1463
                                         = EEH_Address::format($attendee, 'inline', false, false);
1464 1464
                                 } else {
1465
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['att_id']   = '';
1466
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['attendee'] = '';
1467
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['email']    = '';
1468
-                                    $this->_template_args['event_attendees'][ $registration->ID() ]['address']  = '';
1465
+                                    $this->_template_args['event_attendees'][$registration->ID()]['att_id']   = '';
1466
+                                    $this->_template_args['event_attendees'][$registration->ID()]['attendee'] = '';
1467
+                                    $this->_template_args['event_attendees'][$registration->ID()]['email']    = '';
1468
+                                    $this->_template_args['event_attendees'][$registration->ID()]['address']  = '';
1469 1469
                                 }
1470 1470
                             }
1471 1471
                             break;
@@ -1481,7 +1481,7 @@  discard block
 block discarded – undo
1481 1481
                 TXN_ADMIN_URL
1482 1482
             );
1483 1483
             echo EEH_Template::display_template(
1484
-                TXN_TEMPLATE_PATH . 'txn_admin_details_main_meta_box_attendees.template.php',
1484
+                TXN_TEMPLATE_PATH.'txn_admin_details_main_meta_box_attendees.template.php',
1485 1485
                 $this->_template_args,
1486 1486
                 true
1487 1487
             );
@@ -1516,12 +1516,12 @@  discard block
 block discarded – undo
1516 1516
         $primary_att = $this->_transaction->primary_registration() instanceof EE_Registration
1517 1517
             ? $this->_transaction->primary_registration()->get_first_related('Attendee')
1518 1518
             : null;
1519
-        if (! $primary_att instanceof EE_Attendee) {
1519
+        if ( ! $primary_att instanceof EE_Attendee) {
1520 1520
             $this->_template_args['no_attendee_message'] = esc_html__(
1521 1521
                 'There is no attached contact for this transaction.  The transaction either failed due to an error or was abandoned.',
1522 1522
                 'event_espresso'
1523 1523
             );
1524
-            $primary_att                                 = EEM_Attendee::instance()->create_default_object();
1524
+            $primary_att = EEM_Attendee::instance()->create_default_object();
1525 1525
         }
1526 1526
         $this->_template_args['ATT_ID']            = $primary_att->ID();
1527 1527
         $this->_template_args['prime_reg_fname']   = $primary_att->fname();
@@ -1543,7 +1543,7 @@  discard block
 block discarded – undo
1543 1543
                 : '';
1544 1544
         $this->_template_args['formatted_address'] = $formatted_address;
1545 1545
         echo EEH_Template::display_template(
1546
-            TXN_TEMPLATE_PATH . 'txn_admin_details_side_meta_box_registrant.template.php',
1546
+            TXN_TEMPLATE_PATH.'txn_admin_details_side_meta_box_registrant.template.php',
1547 1547
             $this->_template_args,
1548 1548
             true
1549 1549
         );
@@ -1568,7 +1568,7 @@  discard block
 block discarded – undo
1568 1568
             TXN_ADMIN_URL
1569 1569
         );
1570 1570
 
1571
-        $template_path = TXN_TEMPLATE_PATH . 'txn_admin_details_side_meta_box_billing_info.template.php';
1571
+        $template_path = TXN_TEMPLATE_PATH.'txn_admin_details_side_meta_box_billing_info.template.php';
1572 1572
         echo EEH_Template::display_template($template_path, $this->_template_args, true);
1573 1573
     }
1574 1574
 
@@ -1595,7 +1595,7 @@  discard block
 block discarded – undo
1595 1595
         );
1596 1596
         $TXD_ID     = $this->request->getRequestParam('txn_admin_payment[TXN_ID]', 0, 'int');
1597 1597
         $amount     = 0;
1598
-        if (! empty($valid_data) && $has_access) {
1598
+        if ( ! empty($valid_data) && $has_access) {
1599 1599
             $PAY_ID = $valid_data['PAY_ID'];
1600 1600
             // save  the new payment
1601 1601
             $payment = $this->_create_payment_from_request_data($valid_data);
@@ -1609,7 +1609,7 @@  discard block
 block discarded – undo
1609 1609
                 $REG_IDs = $this->_get_REG_IDs_to_apply_payment_to($payment);
1610 1610
                 $this->_remove_existing_registration_payments($payment, $PAY_ID);
1611 1611
                 // apply payment to registrations (if applicable)
1612
-                if (! empty($REG_IDs)) {
1612
+                if ( ! empty($REG_IDs)) {
1613 1613
                     $this->_update_registration_payments($transaction, $payment, $REG_IDs);
1614 1614
                     $this->_maybe_send_notifications();
1615 1615
                     // now process status changes for the same registrations
@@ -1682,14 +1682,14 @@  discard block
 block discarded – undo
1682 1682
      */
1683 1683
     protected function _validate_payment_request_data()
1684 1684
     {
1685
-        if (! $this->request->requestParamIsSet('txn_admin_payment')) {
1685
+        if ( ! $this->request->requestParamIsSet('txn_admin_payment')) {
1686 1686
             return [];
1687 1687
         }
1688 1688
         $payment_form = $this->_generate_payment_form_section();
1689 1689
         try {
1690 1690
             if ($payment_form->was_submitted()) {
1691 1691
                 $payment_form->receive_form_submission();
1692
-                if (! $payment_form->is_valid()) {
1692
+                if ( ! $payment_form->is_valid()) {
1693 1693
                     $submission_error_messages = [];
1694 1694
                     foreach ($payment_form->get_validation_errors_accumulated() as $validation_error) {
1695 1695
                         if ($validation_error instanceof EE_Validation_Error) {
@@ -1877,7 +1877,7 @@  discard block
 block discarded – undo
1877 1877
             ['Y-m-d', 'g:i a']
1878 1878
         );
1879 1879
 
1880
-        if (! $payment->save()) {
1880
+        if ( ! $payment->save()) {
1881 1881
             EE_Error::add_error(
1882 1882
                 sprintf(
1883 1883
                     esc_html__('Payment %1$d has not been successfully saved to the database.', 'event_espresso'),
@@ -1953,7 +1953,7 @@  discard block
 block discarded – undo
1953 1953
             false,
1954 1954
             DataType::BOOL
1955 1955
         );
1956
-        $REG_IDs      = ! $apply_to_all
1956
+        $REG_IDs = ! $apply_to_all
1957 1957
             ? $this->request->getRequestParam(
1958 1958
                 'txn_admin_payment[registrations]',
1959 1959
                 [],
@@ -1967,12 +1967,12 @@  discard block
 block discarded – undo
1967 1967
                 [
1968 1968
                     [
1969 1969
                         'STS_ID' => [
1970
-                            'NOT_IN', [ EEM_Registration::status_id_cancelled ]
1970
+                            'NOT_IN', [EEM_Registration::status_id_cancelled]
1971 1971
                         ]
1972 1972
                     ]
1973 1973
                 ]
1974 1974
             );
1975
-            $REG_IDs       = ! empty($registrations)
1975
+            $REG_IDs = ! empty($registrations)
1976 1976
                 ? array_keys($registrations)
1977 1977
                 : $this->_get_existing_reg_payment_REG_IDs($payment);
1978 1978
         }
@@ -2098,12 +2098,12 @@  discard block
 block discarded – undo
2098 2098
         // but add in some conditions regarding payment,
2099 2099
         // so that we don't apply payments to registrations that are free or have already been paid for
2100 2100
         // but ONLY if the payment is NOT a refund ( ie: the payment amount is not negative )
2101
-        if (! $payment->is_a_refund()) {
2101
+        if ( ! $payment->is_a_refund()) {
2102 2102
             $registration_query_where_params['REG_final_price']  = ['!=', 0];
2103 2103
             $registration_query_where_params['REG_final_price*'] = ['!=', 'REG_paid', true];
2104 2104
         }
2105 2105
         $registrations = $transaction->registrations([$registration_query_where_params]);
2106
-        if (! empty($registrations)) {
2106
+        if ( ! empty($registrations)) {
2107 2107
             /** @type EE_Payment_Processor $payment_processor */
2108 2108
             $payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
2109 2109
             $payment_processor->process_registration_payments($transaction, $payment, $registrations);
@@ -2187,7 +2187,7 @@  discard block
 block discarded – undo
2187 2187
             'pay_status'       => $payment->STS_ID(),
2188 2188
             'PAY_ID'           => $payment->ID(),
2189 2189
             'STS_ID'           => $payment->STS_ID(),
2190
-            'status'           => self::$_pay_status[ $payment->STS_ID() ],
2190
+            'status'           => self::$_pay_status[$payment->STS_ID()],
2191 2191
             'date'             => $payment->timestamp('Y-m-d', 'h:i a'),
2192 2192
             'method'           => strtoupper($payment->source()),
2193 2193
             'PM_ID'            => $payment_method instanceof EE_Payment_Method
@@ -2307,11 +2307,11 @@  discard block
 block discarded – undo
2307 2307
     {
2308 2308
         $registration_payment_data = [];
2309 2309
         // if non empty reg_ids lets get an array of registrations and update the values for the apply_payment/refund rows.
2310
-        if (! empty($REG_IDs)) {
2310
+        if ( ! empty($REG_IDs)) {
2311 2311
             $registrations = EEM_Registration::instance()->get_all([['REG_ID' => ['IN', $REG_IDs]]]);
2312 2312
             foreach ($registrations as $registration) {
2313 2313
                 if ($registration instanceof EE_Registration) {
2314
-                    $registration_payment_data[ $registration->ID() ] = [
2314
+                    $registration_payment_data[$registration->ID()] = [
2315 2315
                         'paid'  => $registration->pretty_paid(),
2316 2316
                         'owing' => EEH_Template::format_currency($registration->final_price() - $registration->paid()),
2317 2317
                     ];
@@ -2368,7 +2368,7 @@  discard block
 block discarded – undo
2368 2368
         $transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
2369 2369
         $redirect_to = $this->request->getRequestParam('redirect_to');
2370 2370
         $query_args  = $redirect_to
2371
-            ? ['action' => $redirect_to, 'TXN_ID' => $TXN_ID,]
2371
+            ? ['action' => $redirect_to, 'TXN_ID' => $TXN_ID, ]
2372 2372
             : [];
2373 2373
         do_action(
2374 2374
             'AHEE__Transactions_Admin_Page___send_payment_reminder__process_admin_payment_reminder',
@@ -2408,8 +2408,8 @@  discard block
 block discarded – undo
2408 2408
         );
2409 2409
 
2410 2410
         // make sure our timestamps start and end right at the boundaries for each day
2411
-        $start_date = date('Y-m-d', strtotime($start_date)) . ' 00:00:00';
2412
-        $end_date   = date('Y-m-d', strtotime($end_date)) . ' 23:59:59';
2411
+        $start_date = date('Y-m-d', strtotime($start_date)).' 00:00:00';
2412
+        $end_date   = date('Y-m-d', strtotime($end_date)).' 23:59:59';
2413 2413
 
2414 2414
 
2415 2415
         // convert to timestamps
@@ -2426,7 +2426,7 @@  discard block
 block discarded – undo
2426 2426
             date('Y-m-d H:i:s', $start_date),
2427 2427
             'Y-m-d H:i:s'
2428 2428
         );
2429
-        $end_date   = EEM_Transaction::instance()->convert_datetime_for_query(
2429
+        $end_date = EEM_Transaction::instance()->convert_datetime_for_query(
2430 2430
             'TXN_timestamp',
2431 2431
             date('Y-m-d H:i:s', $end_date),
2432 2432
             'Y-m-d H:i:s'
@@ -2472,7 +2472,7 @@  discard block
 block discarded – undo
2472 2472
 
2473 2473
         $search_term = $this->request->getRequestParam('s');
2474 2474
         if ($search_term) {
2475
-            $search_term  = '%' . $search_term . '%';
2475
+            $search_term  = '%'.$search_term.'%';
2476 2476
             $_where['OR'] = [
2477 2477
                 'Registration.Event.EVT_name'         => ['LIKE', $search_term],
2478 2478
                 'Registration.Event.EVT_desc'         => ['LIKE', $search_term],
@@ -2500,9 +2500,9 @@  discard block
 block discarded – undo
2500 2500
 
2501 2501
         $status = $this->request->getRequestParam('status');
2502 2502
         // failed transactions
2503
-        $failed     = (! empty($status) && $status === 'failed' && ! $count) || ($count && $view === 'failed');
2504
-        $abandoned  = (! empty($status) && $status === 'abandoned' && ! $count) || ($count && $view === 'abandoned');
2505
-        $incomplete = (! empty($status) && $status === 'incomplete' && ! $count) || ($count && $view === 'incomplete');
2503
+        $failed     = ( ! empty($status) && $status === 'failed' && ! $count) || ($count && $view === 'failed');
2504
+        $abandoned  = ( ! empty($status) && $status === 'abandoned' && ! $count) || ($count && $view === 'abandoned');
2505
+        $incomplete = ( ! empty($status) && $status === 'incomplete' && ! $count) || ($count && $view === 'incomplete');
2506 2506
 
2507 2507
         if ($failed) {
2508 2508
             $_where['STS_ID'] = EEM_Transaction::failed_status_code;
@@ -2551,7 +2551,7 @@  discard block
 block discarded – undo
2551 2551
         $success     = $transaction->recalculateLineItems();
2552 2552
         $redirect_to = $this->request->getRequestParam('redirect_to');
2553 2553
         $query_args  = $redirect_to
2554
-            ? ['action' => $redirect_to, 'TXN_ID' => $TXN_ID,]
2554
+            ? ['action' => $redirect_to, 'TXN_ID' => $TXN_ID, ]
2555 2555
             : [];
2556 2556
         $this->_redirect_after_action(
2557 2557
             $success,
Please login to merge, or discard this patch.
admin_pages/events/Events_Admin_Page.core.php 1 patch
Indentation   +2938 added lines, -2938 removed lines patch added patch discarded remove patch
@@ -18,2945 +18,2945 @@
 block discarded – undo
18 18
  */
19 19
 class Events_Admin_Page extends EE_Admin_Page_CPT
20 20
 {
21
-    /**
22
-     * primary key for the event model
23
-     */
24
-    private int $EVT_ID = 0;
25
-
26
-    /**
27
-     * This will hold the event object for event_details screen.
28
-     *
29
-     * @var EE_Event|null $_event
30
-     */
31
-    protected ?EE_Event $_event = null;
32
-
33
-    /**
34
-     * This will hold the category object for category_details screen.
35
-     */
36
-    protected ?stdClass $_category = null;
37
-
38
-    protected ?EEM_Event $_event_model = null;
39
-
40
-    /**
41
-     * @var EE_Event|EE_CPT_Base|null $_cpt_model_obj
42
-     */
43
-    protected $_cpt_model_obj;
44
-
45
-    protected ?NodeGroupDao $model_obj_node_group_persister = null;
46
-
47
-    protected ?AdvancedEditorAdminFormSection $advanced_editor_admin_form = null;
48
-
49
-
50
-    /**
51
-     * Initialize page props for this admin page group.
52
-     */
53
-    protected function _init_page_props()
54
-    {
55
-        // is there a evt_id in the request?
56
-        $this->EVT_ID = $this->request->getRequestParam('EVT_ID', 0, DataType::INT);
57
-        $this->EVT_ID = $this->request->getRequestParam('post', $this->EVT_ID, DataType::INT);
58
-        $this->EVT_ID = $this->request->getRequestParam('post_ID', $this->EVT_ID, DataType::INT);
59
-
60
-        $this->page_slug        = EVENTS_PG_SLUG;
61
-        $this->page_label       = EVENTS_LABEL;
62
-        $this->_admin_base_url  = EVENTS_ADMIN_URL;
63
-        $this->_admin_base_path = EVENTS_ADMIN;
64
-        $this->_cpt_model_names = [
65
-            'create_new' => 'EEM_Event',
66
-            'edit'       => 'EEM_Event',
67
-        ];
68
-        $this->_cpt_edit_routes = [
69
-            'espresso_events' => 'edit',
70
-        ];
71
-        add_action(
72
-            'AHEE__EE_Admin_Page_CPT__set_model_object__after_set_object',
73
-            [$this, 'verify_event_edit'],
74
-            10,
75
-            2
76
-        );
77
-    }
78
-
79
-
80
-    /**
81
-     * Sets the ajax hooks used for this admin page group.
82
-     */
83
-    protected function _ajax_hooks()
84
-    {
85
-        add_action('wp_ajax_ee_save_timezone_setting', [$this, 'saveTimezoneString']);
86
-    }
87
-
88
-
89
-    /**
90
-     * Sets the page properties for this admin page group.
91
-     */
92
-    protected function _define_page_props()
93
-    {
94
-        $this->_admin_page_title = EVENTS_LABEL;
95
-        $this->_labels           = [
96
-            'buttons'      => [
97
-                'add'             => esc_html__('Add New Event', 'event_espresso'),
98
-                'edit'            => esc_html__('Edit Event', 'event_espresso'),
99
-                'delete'          => esc_html__('Delete Event', 'event_espresso'),
100
-                'add_category'    => esc_html__('Add New Category', 'event_espresso'),
101
-                'edit_category'   => esc_html__('Edit Category', 'event_espresso'),
102
-                'delete_category' => esc_html__('Delete Category', 'event_espresso'),
103
-            ],
104
-            'editor_title' => [
105
-                'espresso_events' => esc_html__('Edit Event', 'event_espresso'),
106
-            ],
107
-            'publishbox'   => [
108
-                'create_new'        => esc_html__('Save New Event', 'event_espresso'),
109
-                'edit'              => esc_html__('Update Event', 'event_espresso'),
110
-                'add_category'      => esc_html__('Save New Category', 'event_espresso'),
111
-                'edit_category'     => esc_html__('Update Category', 'event_espresso'),
112
-                'template_settings' => esc_html__('Update Settings', 'event_espresso'),
113
-            ],
114
-        ];
115
-    }
116
-
117
-
118
-    /**
119
-     * Sets the page routes property for this admin page group.
120
-     */
121
-    protected function _set_page_routes()
122
-    {
123
-        $this->_page_routes = [
124
-            'default'                       => [
125
-                'func'       => [$this, '_events_overview_list_table'],
126
-                'capability' => 'ee_read_events',
127
-            ],
128
-            'create_new'                    => [
129
-                'func'       => [$this, '_create_new_cpt_item'],
130
-                'capability' => 'ee_edit_events',
131
-            ],
132
-            'edit'                          => [
133
-                'func'       => [$this, '_edit_cpt_item'],
134
-                'capability' => 'ee_edit_event',
135
-                'obj_id'     => $this->EVT_ID,
136
-            ],
137
-            'copy_event'                    => [
138
-                'func'       => [$this, '_copy_events'],
139
-                'capability' => 'ee_edit_event',
140
-                'obj_id'     => $this->EVT_ID,
141
-                'noheader'   => true,
142
-            ],
143
-            'trash_event'                   => [
144
-                'func'       => [$this, '_trash_or_restore_event'],
145
-                'args'       => ['event_status' => 'trash'],
146
-                'capability' => 'ee_delete_event',
147
-                'obj_id'     => $this->EVT_ID,
148
-                'noheader'   => true,
149
-            ],
150
-            'trash_events'                  => [
151
-                'func'       => [$this, '_trash_or_restore_events'],
152
-                'args'       => ['event_status' => 'trash'],
153
-                'capability' => 'ee_delete_events',
154
-                'noheader'   => true,
155
-            ],
156
-            'restore_event'                 => [
157
-                'func'       => [$this, '_trash_or_restore_event'],
158
-                'args'       => ['event_status' => 'draft'],
159
-                'capability' => 'ee_delete_event',
160
-                'obj_id'     => $this->EVT_ID,
161
-                'noheader'   => true,
162
-            ],
163
-            'restore_events'                => [
164
-                'func'       => [$this, '_trash_or_restore_events'],
165
-                'args'       => ['event_status' => 'draft'],
166
-                'capability' => 'ee_delete_events',
167
-                'noheader'   => true,
168
-            ],
169
-            'delete_event'                  => [
170
-                'func'       => [$this, '_delete_event'],
171
-                'capability' => 'ee_delete_event',
172
-                'obj_id'     => $this->EVT_ID,
173
-                'noheader'   => true,
174
-            ],
175
-            'delete_events'                 => [
176
-                'func'       => [$this, '_delete_events'],
177
-                'capability' => 'ee_delete_events',
178
-                'noheader'   => true,
179
-            ],
180
-            'view_report'                   => [
181
-                'func'       => [$this, '_view_report'],
182
-                'capability' => 'ee_edit_events',
183
-            ],
184
-            'default_event_settings'        => [
185
-                'func'       => [$this, '_default_event_settings'],
186
-                'capability' => 'manage_options',
187
-            ],
188
-            'update_default_event_settings' => [
189
-                'func'       => [$this, '_update_default_event_settings'],
190
-                'capability' => 'manage_options',
191
-                'noheader'   => true,
192
-            ],
193
-            'template_settings'             => [
194
-                'func'       => [$this, '_template_settings'],
195
-                'capability' => 'manage_options',
196
-            ],
197
-            // event category tab related
198
-            'add_category'                  => [
199
-                'func'       => [$this, '_category_details'],
200
-                'capability' => 'ee_edit_event_category',
201
-                'args'       => ['view' => 'add'],
202
-            ],
203
-            'edit_category'                 => [
204
-                'func'       => [$this, '_category_details'],
205
-                'capability' => 'ee_edit_event_category',
206
-                'args'       => ['view' => 'edit'],
207
-            ],
208
-            'delete_categories'             => [
209
-                'func'       => [$this, '_delete_categories'],
210
-                'capability' => 'ee_delete_event_category',
211
-                'noheader'   => true,
212
-            ],
213
-            'delete_category'               => [
214
-                'func'       => [$this, '_delete_categories'],
215
-                'capability' => 'ee_delete_event_category',
216
-                'noheader'   => true,
217
-            ],
218
-            'insert_category'               => [
219
-                'func'       => [$this, '_insert_or_update_category'],
220
-                'args'       => ['new_category' => true],
221
-                'capability' => 'ee_edit_event_category',
222
-                'noheader'   => true,
223
-            ],
224
-            'update_category'               => [
225
-                'func'       => [$this, '_insert_or_update_category'],
226
-                'args'       => ['new_category' => false],
227
-                'capability' => 'ee_edit_event_category',
228
-                'noheader'   => true,
229
-            ],
230
-            'category_list'                 => [
231
-                'func'       => [$this, '_category_list_table'],
232
-                'capability' => 'ee_manage_event_categories',
233
-            ],
234
-            'preview_deletion'              => [
235
-                'func'       => [$this, 'previewDeletion'],
236
-                'capability' => 'ee_delete_events',
237
-            ],
238
-            'confirm_deletion'              => [
239
-                'func'       => [$this, 'confirmDeletion'],
240
-                'capability' => 'ee_delete_events',
241
-                'noheader'   => true,
242
-            ],
243
-        ];
244
-    }
245
-
246
-
247
-    /**
248
-     * Set the _page_config property for this admin page group.
249
-     */
250
-    protected function _set_page_config()
251
-    {
252
-        $post_id            = $this->request->getRequestParam('post', 0, DataType::INT);
253
-        $EVT_CAT_ID         = $this->request->getRequestParam('EVT_CAT_ID', 0, DataType::INT);
254
-        $this->_page_config = [
255
-            'default'                => [
256
-                'nav'           => [
257
-                    'label' => esc_html__('Overview', 'event_espresso'),
258
-                    'icon'  => 'dashicons-list-view',
259
-                    'order' => 10,
260
-                ],
261
-                'list_table'    => 'Events_Admin_List_Table',
262
-                'help_tabs'     => [
263
-                    'events_overview_help_tab'                       => [
264
-                        'title'    => esc_html__('Events Overview', 'event_espresso'),
265
-                        'filename' => 'events_overview',
266
-                    ],
267
-                    'events_overview_table_column_headings_help_tab' => [
268
-                        'title'    => esc_html__('Events Overview Table Column Headings', 'event_espresso'),
269
-                        'filename' => 'events_overview_table_column_headings',
270
-                    ],
271
-                    'events_overview_filters_help_tab'               => [
272
-                        'title'    => esc_html__('Events Overview Filters', 'event_espresso'),
273
-                        'filename' => 'events_overview_filters',
274
-                    ],
275
-                    'events_overview_view_help_tab'                  => [
276
-                        'title'    => esc_html__('Events Overview Views', 'event_espresso'),
277
-                        'filename' => 'events_overview_views',
278
-                    ],
279
-                    'events_overview_other_help_tab'                 => [
280
-                        'title'    => esc_html__('Events Overview Other', 'event_espresso'),
281
-                        'filename' => 'events_overview_other',
282
-                    ],
283
-                ],
284
-                'require_nonce' => false,
285
-            ],
286
-            'create_new'             => [
287
-                'nav'           => [
288
-                    'label'      => esc_html__('Add New Event', 'event_espresso'),
289
-                    'icon'       => 'dashicons-plus-alt',
290
-                    'order'      => 15,
291
-                    'persistent' => false,
292
-                ],
293
-                'metaboxes'     => ['_register_event_editor_meta_boxes'],
294
-                'help_tabs'     => [
295
-                    'event_editor_help_tab'                            => [
296
-                        'title'    => esc_html__('Event Editor', 'event_espresso'),
297
-                        'filename' => 'event_editor',
298
-                    ],
299
-                    'event_editor_title_richtexteditor_help_tab'       => [
300
-                        'title'    => esc_html__('Event Title & Rich Text Editor', 'event_espresso'),
301
-                        'filename' => 'event_editor_title_richtexteditor',
302
-                    ],
303
-                    'event_editor_venue_details_help_tab'              => [
304
-                        'title'    => esc_html__('Event Venue Details', 'event_espresso'),
305
-                        'filename' => 'event_editor_venue_details',
306
-                    ],
307
-                    'event_editor_event_datetimes_help_tab'            => [
308
-                        'title'    => esc_html__('Event Datetimes', 'event_espresso'),
309
-                        'filename' => 'event_editor_event_datetimes',
310
-                    ],
311
-                    'event_editor_event_tickets_help_tab'              => [
312
-                        'title'    => esc_html__('Event Tickets', 'event_espresso'),
313
-                        'filename' => 'event_editor_event_tickets',
314
-                    ],
315
-                    'event_editor_event_registration_options_help_tab' => [
316
-                        'title'    => esc_html__('Event Registration Options', 'event_espresso'),
317
-                        'filename' => 'event_editor_event_registration_options',
318
-                    ],
319
-                    'event_editor_tags_categories_help_tab'            => [
320
-                        'title'    => esc_html__('Event Tags & Categories', 'event_espresso'),
321
-                        'filename' => 'event_editor_tags_categories',
322
-                    ],
323
-                    'event_editor_questions_registrants_help_tab'      => [
324
-                        'title'    => esc_html__('Questions for Registrants', 'event_espresso'),
325
-                        'filename' => 'event_editor_questions_registrants',
326
-                    ],
327
-                    'event_editor_save_new_event_help_tab'             => [
328
-                        'title'    => esc_html__('Save New Event', 'event_espresso'),
329
-                        'filename' => 'event_editor_save_new_event',
330
-                    ],
331
-                    'event_editor_other_help_tab'                      => [
332
-                        'title'    => esc_html__('Event Other', 'event_espresso'),
333
-                        'filename' => 'event_editor_other',
334
-                    ],
335
-                ],
336
-                'qtips'         => ['EE_Event_Editor_Decaf_Tips'],
337
-                'require_nonce' => false,
338
-            ],
339
-            'edit'                   => [
340
-                'nav'           => [
341
-                    'label'      => esc_html__('Edit Event', 'event_espresso'),
342
-                    'icon'       => 'dashicons-edit',
343
-                    'order'      => 15,
344
-                    'persistent' => false,
345
-                    'url'        => $post_id
346
-                        ? EE_Admin_Page::add_query_args_and_nonce(
347
-                            ['post' => $post_id, 'action' => 'edit'],
348
-                            $this->_current_page_view_url
349
-                        )
350
-                        : $this->_admin_base_url,
351
-                ],
352
-                'metaboxes'     => ['_register_event_editor_meta_boxes'],
353
-                'help_tabs'     => [
354
-                    'event_editor_help_tab'                            => [
355
-                        'title'    => esc_html__('Event Editor', 'event_espresso'),
356
-                        'filename' => 'event_editor',
357
-                    ],
358
-                    'event_editor_title_richtexteditor_help_tab'       => [
359
-                        'title'    => esc_html__('Event Title & Rich Text Editor', 'event_espresso'),
360
-                        'filename' => 'event_editor_title_richtexteditor',
361
-                    ],
362
-                    'event_editor_venue_details_help_tab'              => [
363
-                        'title'    => esc_html__('Event Venue Details', 'event_espresso'),
364
-                        'filename' => 'event_editor_venue_details',
365
-                    ],
366
-                    'event_editor_event_datetimes_help_tab'            => [
367
-                        'title'    => esc_html__('Event Datetimes', 'event_espresso'),
368
-                        'filename' => 'event_editor_event_datetimes',
369
-                    ],
370
-                    'event_editor_event_tickets_help_tab'              => [
371
-                        'title'    => esc_html__('Event Tickets', 'event_espresso'),
372
-                        'filename' => 'event_editor_event_tickets',
373
-                    ],
374
-                    'event_editor_event_registration_options_help_tab' => [
375
-                        'title'    => esc_html__('Event Registration Options', 'event_espresso'),
376
-                        'filename' => 'event_editor_event_registration_options',
377
-                    ],
378
-                    'event_editor_tags_categories_help_tab'            => [
379
-                        'title'    => esc_html__('Event Tags & Categories', 'event_espresso'),
380
-                        'filename' => 'event_editor_tags_categories',
381
-                    ],
382
-                    'event_editor_questions_registrants_help_tab'      => [
383
-                        'title'    => esc_html__('Questions for Registrants', 'event_espresso'),
384
-                        'filename' => 'event_editor_questions_registrants',
385
-                    ],
386
-                    'event_editor_save_new_event_help_tab'             => [
387
-                        'title'    => esc_html__('Save New Event', 'event_espresso'),
388
-                        'filename' => 'event_editor_save_new_event',
389
-                    ],
390
-                    'event_editor_other_help_tab'                      => [
391
-                        'title'    => esc_html__('Event Other', 'event_espresso'),
392
-                        'filename' => 'event_editor_other',
393
-                    ],
394
-                ],
395
-                'require_nonce' => false,
396
-            ],
397
-            'default_event_settings' => [
398
-                'nav'           => [
399
-                    'label' => esc_html__('Default Settings', 'event_espresso'),
400
-                    'icon'  => 'dashicons-admin-generic',
401
-                    'order' => 40,
402
-                ],
403
-                'metaboxes'     => array_merge(['_publish_post_box'], $this->_default_espresso_metaboxes),
404
-                'labels'        => [
405
-                    'publishbox' => esc_html__('Update Settings', 'event_espresso'),
406
-                ],
407
-                'help_tabs'     => [
408
-                    'default_settings_help_tab'        => [
409
-                        'title'    => esc_html__('Default Event Settings', 'event_espresso'),
410
-                        'filename' => 'events_default_settings',
411
-                    ],
412
-                    'default_settings_status_help_tab' => [
413
-                        'title'    => esc_html__('Default Registration Status', 'event_espresso'),
414
-                        'filename' => 'events_default_settings_status',
415
-                    ],
416
-                    'default_maximum_tickets_help_tab' => [
417
-                        'title'    => esc_html__('Default Maximum Tickets Per Order', 'event_espresso'),
418
-                        'filename' => 'events_default_settings_max_tickets',
419
-                    ],
420
-                ],
421
-                'require_nonce' => false,
422
-            ],
423
-            // template settings
424
-            'template_settings'      => [
425
-                'nav'           => [
426
-                    'label' => esc_html__('Templates', 'event_espresso'),
427
-                    'icon'  => 'dashicons-layout',
428
-                    'order' => 30,
429
-                ],
430
-                'metaboxes'     => $this->_default_espresso_metaboxes,
431
-                'help_tabs'     => [
432
-                    'general_settings_templates_help_tab' => [
433
-                        'title'    => esc_html__('Templates', 'event_espresso'),
434
-                        'filename' => 'general_settings_templates',
435
-                    ],
436
-                ],
437
-                'require_nonce' => false,
438
-            ],
439
-            // event category stuff
440
-            'add_category'           => [
441
-                'nav'           => [
442
-                    'label'      => esc_html__('Add Category', 'event_espresso'),
443
-                    'icon'       => 'dashicons-plus-alt',
444
-                    'order'      => 25,
445
-                    'persistent' => false,
446
-                ],
447
-                'help_tabs'     => [
448
-                    'add_category_help_tab' => [
449
-                        'title'    => esc_html__('Add New Event Category', 'event_espresso'),
450
-                        'filename' => 'events_add_category',
451
-                    ],
452
-                ],
453
-                'metaboxes'     => ['_publish_post_box'],
454
-                'require_nonce' => false,
455
-            ],
456
-            'edit_category'          => [
457
-                'nav'           => [
458
-                    'label'      => esc_html__('Edit Category', 'event_espresso'),
459
-                    'icon'       => 'dashicons-edit',
460
-                    'order'      => 25,
461
-                    'persistent' => false,
462
-                    'url'        => $EVT_CAT_ID
463
-                        ? add_query_arg(
464
-                            ['EVT_CAT_ID' => $EVT_CAT_ID],
465
-                            $this->_current_page_view_url
466
-                        )
467
-                        : $this->_admin_base_url,
468
-                ],
469
-                'help_tabs'     => [
470
-                    'edit_category_help_tab' => [
471
-                        'title'    => esc_html__('Edit Event Category', 'event_espresso'),
472
-                        'filename' => 'events_edit_category',
473
-                    ],
474
-                ],
475
-                'metaboxes'     => ['_publish_post_box'],
476
-                'require_nonce' => false,
477
-            ],
478
-            'category_list'          => [
479
-                'nav'           => [
480
-                    'label' => esc_html__('Categories', 'event_espresso'),
481
-                    'icon'  => 'dashicons-networking',
482
-                    'order' => 20,
483
-                ],
484
-                'list_table'    => 'Event_Categories_Admin_List_Table',
485
-                'help_tabs'     => [
486
-                    'events_categories_help_tab'                       => [
487
-                        'title'    => esc_html__('Event Categories', 'event_espresso'),
488
-                        'filename' => 'events_categories',
489
-                    ],
490
-                    'events_categories_table_column_headings_help_tab' => [
491
-                        'title'    => esc_html__('Event Categories Table Column Headings', 'event_espresso'),
492
-                        'filename' => 'events_categories_table_column_headings',
493
-                    ],
494
-                    'events_categories_view_help_tab'                  => [
495
-                        'title'    => esc_html__('Event Categories Views', 'event_espresso'),
496
-                        'filename' => 'events_categories_views',
497
-                    ],
498
-                    'events_categories_other_help_tab'                 => [
499
-                        'title'    => esc_html__('Event Categories Other', 'event_espresso'),
500
-                        'filename' => 'events_categories_other',
501
-                    ],
502
-                ],
503
-                'metaboxes'     => $this->_default_espresso_metaboxes,
504
-                'require_nonce' => false,
505
-            ],
506
-            'preview_deletion'       => [
507
-                'nav'           => [
508
-                    'label'      => esc_html__('Preview Deletion', 'event_espresso'),
509
-                    'icon'       => 'dashicons-remove',
510
-                    'order'      => 15,
511
-                    'persistent' => false,
512
-                    'url'        => '',
513
-                ],
514
-                'require_nonce' => false,
515
-            ],
516
-        ];
517
-    }
518
-
519
-
520
-    /**
521
-     * Used to register any global screen options if necessary for every route in this admin page group.
522
-     */
523
-    protected function _add_screen_options()
524
-    {
525
-    }
526
-
527
-
528
-    /**
529
-     * Implementing the screen options for the 'default' route.
530
-     *
531
-     * @throws InvalidArgumentException
532
-     * @throws InvalidDataTypeException
533
-     * @throws InvalidInterfaceException
534
-     */
535
-    protected function _add_screen_options_default()
536
-    {
537
-        $this->_per_page_screen_option();
538
-    }
539
-
540
-
541
-    /**
542
-     * Implementing screen options for the category list route.
543
-     *
544
-     * @throws InvalidArgumentException
545
-     * @throws InvalidDataTypeException
546
-     * @throws InvalidInterfaceException
547
-     */
548
-    protected function _add_screen_options_category_list()
549
-    {
550
-        $page_title              = $this->_admin_page_title;
551
-        $this->_admin_page_title = esc_html__('Categories', 'event_espresso');
552
-        $this->_per_page_screen_option();
553
-        $this->_admin_page_title = $page_title;
554
-    }
555
-
556
-
557
-    /**
558
-     * Used to register any global feature pointers for the admin page group.
559
-     */
560
-    protected function _add_feature_pointers()
561
-    {
562
-    }
563
-
564
-
565
-    /**
566
-     * Registers and enqueues any global scripts and styles for the entire admin page group.
567
-     */
568
-    public function load_scripts_styles()
569
-    {
570
-        wp_register_style(
571
-            'events-admin-css',
572
-            EVENTS_ASSETS_URL . 'events-admin-page.css',
573
-            [],
574
-            EVENT_ESPRESSO_VERSION
575
-        );
576
-        wp_register_style(
577
-            'ee-cat-admin',
578
-            EVENTS_ASSETS_URL . 'ee-cat-admin.css',
579
-            [],
580
-            EVENT_ESPRESSO_VERSION
581
-        );
582
-        wp_enqueue_style('events-admin-css');
583
-        wp_enqueue_style('ee-cat-admin');
584
-        // scripts
585
-        wp_register_script(
586
-            'event_editor_js',
587
-            EVENTS_ASSETS_URL . 'event_editor.js',
588
-            ['ee_admin_js', 'jquery-ui-slider', 'jquery-ui-timepicker-addon'],
589
-            EVENT_ESPRESSO_VERSION,
590
-            true
591
-        );
592
-    }
593
-
594
-
595
-    /**
596
-     * Enqueuing scripts and styles specific to this view
597
-     */
598
-    public function load_scripts_styles_create_new()
599
-    {
600
-        $this->load_scripts_styles_edit();
601
-    }
602
-
603
-
604
-    /**
605
-     * Enqueuing scripts and styles specific to this view
606
-     */
607
-    public function load_scripts_styles_edit()
608
-    {
609
-        // styles
610
-        wp_enqueue_style('espresso-ui-theme');
611
-        wp_register_style(
612
-            'event-editor-css',
613
-            EVENTS_ASSETS_URL . 'event-editor.css',
614
-            ['ee-admin-css'],
615
-            EVENT_ESPRESSO_VERSION
616
-        );
617
-        wp_enqueue_style('event-editor-css');
618
-        // scripts
619
-        if (! $this->admin_config->useAdvancedEditor()) {
620
-            wp_register_script(
621
-                'event-datetime-metabox',
622
-                EVENTS_ASSETS_URL . 'event-datetime-metabox.js',
623
-                ['event_editor_js', 'ee-datepicker'],
624
-                EVENT_ESPRESSO_VERSION
625
-            );
626
-            wp_enqueue_script('event-datetime-metabox');
627
-        }
628
-    }
629
-
630
-
631
-    /**
632
-     * Populating the _views property for the category list table view.
633
-     */
634
-    protected function _set_list_table_views_category_list()
635
-    {
636
-        $this->_views = [
637
-            'all' => [
638
-                'slug'        => 'all',
639
-                'label'       => esc_html__('All', 'event_espresso'),
640
-                'count'       => 0,
641
-                'bulk_action' => [
642
-                    'delete_categories' => esc_html__('Delete Permanently', 'event_espresso'),
643
-                ],
644
-            ],
645
-        ];
646
-    }
647
-
648
-
649
-    /**
650
-     * For adding anything that fires on the admin_init hook for any route within this admin page group.
651
-     */
652
-    public function admin_init()
653
-    {
654
-        EE_Registry::$i18n_js_strings['image_confirm'] = esc_html__(
655
-            'Do you really want to delete this image? Please remember to update your event to complete the removal.',
656
-            'event_espresso'
657
-        );
658
-    }
659
-
660
-
661
-    /**
662
-     * For adding anything that should be triggered on the admin_notices hook for any route within this admin page
663
-     * group.
664
-     */
665
-    public function admin_notices()
666
-    {
667
-    }
668
-
669
-
670
-    /**
671
-     * For adding anything that should be triggered on the `admin_print_footer_scripts` hook for any route within
672
-     * this admin page group.
673
-     */
674
-    public function admin_footer_scripts()
675
-    {
676
-    }
677
-
678
-
679
-    /**
680
-     * Call this function to verify if an event is public and has tickets for sale.  If it does, then we need to show a
681
-     * warning (via EE_Error::add_error());
682
-     *
683
-     * @param EE_Event|null $event Event object
684
-     * @param string        $req_type
685
-     * @return void
686
-     * @throws EE_Error
687
-     * @throws ReflectionException
688
-     */
689
-    public function verify_event_edit(?EE_Base_Class $event = null, string $req_type = '')
690
-    {
691
-        // don't need to do this when processing
692
-        if (! empty($req_type)) {
693
-            return;
694
-        }
695
-        // no event?
696
-        if (! $event instanceof EE_Event) {
697
-            $event = $this->_cpt_model_obj;
698
-        }
699
-        // STILL no event?
700
-        if (! $event instanceof EE_Event) {
701
-            return;
702
-        }
703
-        // don't need to keep calling this
704
-        remove_action(
705
-            'AHEE__EE_Admin_Page_CPT__set_model_object__after_set_object',
706
-            [$this, 'verify_event_edit']
707
-        );
708
-        $orig_status = $event->status();
709
-        // first check if event is active.
710
-        if (
711
-            $orig_status === EEM_Event::cancelled
712
-            || $orig_status === EEM_Event::postponed
713
-            || $event->is_expired()
714
-            || $event->is_inactive()
715
-        ) {
716
-            return;
717
-        }
718
-        // made it here so it IS active... next check that any of the tickets are sold.
719
-        if ($event->is_sold_out(true)) {
720
-            if ($orig_status !== EEM_Event::sold_out && $event->status() !== $orig_status) {
721
-                EE_Error::add_attention(
722
-                    sprintf(
723
-                        esc_html__(
724
-                            '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.',
725
-                            'event_espresso'
726
-                        ),
727
-                        EEH_Template::pretty_status(EEM_Event::sold_out, false, 'sentence')
728
-                    )
729
-                );
730
-            }
731
-            return;
732
-        }
733
-        if ($orig_status === EEM_Event::sold_out) {
734
-            EE_Error::add_attention(
735
-                sprintf(
736
-                    esc_html__(
737
-                        '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.',
738
-                        'event_espresso'
739
-                    ),
740
-                    EEH_Template::pretty_status($event->status(), false, 'sentence')
741
-                )
742
-            );
743
-        }
744
-        // now we need to determine if the event has any tickets on sale.  If not then we dont' show the error
745
-        if (! $event->tickets_on_sale()) {
746
-            return;
747
-        }
748
-        // made it here so show warning
749
-        $this->_edit_event_warning();
750
-    }
751
-
752
-
753
-    /**
754
-     * This is the text used for when an event is being edited that is public and has tickets for sale.
755
-     * When needed, hook this into a EE_Error::add_error() notice.
756
-     *
757
-     * @access protected
758
-     * @return void
759
-     */
760
-    protected function _edit_event_warning()
761
-    {
762
-        // we don't want to add warnings during these requests
763
-        if ($this->request->getRequestParam('action') === 'editpost') {
764
-            return;
765
-        }
766
-        EE_Error::add_attention(
767
-            sprintf(
768
-                esc_html__(
769
-                    'Your event is open for registration. Making changes may disrupt any transactions in progress. %sLearn more%s',
770
-                    'event_espresso'
771
-                ),
772
-                '<a class="espresso-help-tab-lnk ee-help-tab-link">',
773
-                '</a>'
774
-            )
775
-        );
776
-    }
777
-
778
-
779
-    /**
780
-     * When a user is creating a new event, notify them if they haven't set their timezone.
781
-     * Otherwise, do the normal logic
782
-     *
783
-     * @return void
784
-     * @throws EE_Error
785
-     * @throws InvalidArgumentException
786
-     * @throws InvalidDataTypeException
787
-     * @throws InvalidInterfaceException
788
-     * @throws ReflectionException
789
-     */
790
-    protected function _create_new_cpt_item()
791
-    {
792
-        $has_timezone_string = get_option('timezone_string');
793
-        // only nag them about setting their timezone if it's their first event, and they haven't already done it
794
-        if (! $has_timezone_string && ! EEM_Event::instance()->exists([])) {
795
-            EE_Error::add_attention(
796
-                sprintf(
797
-                    esc_html__(
798
-                        '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',
799
-                        'event_espresso'
800
-                    ),
801
-                    '<br>',
802
-                    '<select id="timezone_string" name="timezone_string" aria-describedby="timezone-description">'
803
-                    . EEH_DTT_Helper::wp_timezone_choice('', EEH_DTT_Helper::get_user_locale())
804
-                    . '</select>',
805
-                    '<button class="button button--secondary timezone-submit">',
806
-                    '</button><span class="spinner"></span>'
807
-                ),
808
-                __FILE__,
809
-                __FUNCTION__,
810
-                __LINE__
811
-            );
812
-        }
813
-        parent::_create_new_cpt_item();
814
-    }
815
-
816
-
817
-    /**
818
-     * Sets the _views property for the default route in this admin page group.
819
-     */
820
-    protected function _set_list_table_views_default()
821
-    {
822
-        $this->_views = [
823
-            'all'   => [
824
-                'slug'        => 'all',
825
-                'label'       => esc_html__('View All Events', 'event_espresso'),
826
-                'count'       => 0,
827
-                'bulk_action' => [
828
-                    'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
829
-                ],
830
-            ],
831
-            'draft' => [
832
-                'slug'        => 'draft',
833
-                'label'       => esc_html__('Draft', 'event_espresso'),
834
-                'count'       => 0,
835
-                'bulk_action' => [
836
-                    'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
837
-                ],
838
-            ],
839
-        ];
840
-        if ($this->capabilities->current_user_can('ee_delete_events', 'espresso_events_trash_events')) {
841
-            $this->_views['trash'] = [
842
-                'slug'        => 'trash',
843
-                'label'       => esc_html__('Trash', 'event_espresso'),
844
-                'count'       => 0,
845
-                'bulk_action' => [
846
-                    'restore_events' => esc_html__('Restore From Trash', 'event_espresso'),
847
-                    'delete_events'  => esc_html__('Delete Permanently', 'event_espresso'),
848
-                ],
849
-            ];
850
-        }
851
-    }
852
-
853
-
854
-    /**
855
-     * Provides the legend item array for the default list table view.
856
-     *
857
-     * @return array
858
-     * @throws EE_Error
859
-     * @throws EE_Error
860
-     */
861
-    protected function _event_legend_items(): array
862
-    {
863
-        $items    = [
864
-            'view_details'   => [
865
-                'class' => 'dashicons dashicons-visibility',
866
-                'desc'  => esc_html__('View Event', 'event_espresso'),
867
-            ],
868
-            'edit_event'     => [
869
-                'class' => 'dashicons dashicons-calendar-alt',
870
-                'desc'  => esc_html__('Edit Event Details', 'event_espresso'),
871
-            ],
872
-            'view_attendees' => [
873
-                'class' => 'dashicons dashicons-groups',
874
-                'desc'  => esc_html__('View Registrations for Event', 'event_espresso'),
875
-            ],
876
-        ];
877
-        $items    = apply_filters('FHEE__Events_Admin_Page___event_legend_items__items', $items);
878
-        $statuses = [
879
-            'sold_out_status'  => [
880
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::sold_out,
881
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::sold_out, false, 'sentence'),
882
-            ],
883
-            'active_status'    => [
884
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::active,
885
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::active, false, 'sentence'),
886
-            ],
887
-            'upcoming_status'  => [
888
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::upcoming,
889
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::upcoming, false, 'sentence'),
890
-            ],
891
-            'postponed_status' => [
892
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::postponed,
893
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::postponed, false, 'sentence'),
894
-            ],
895
-            'cancelled_status' => [
896
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::cancelled,
897
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::cancelled, false, 'sentence'),
898
-            ],
899
-            'expired_status'   => [
900
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::expired,
901
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::expired, false, 'sentence'),
902
-            ],
903
-            'inactive_status'  => [
904
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::inactive,
905
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::inactive, false, 'sentence'),
906
-            ],
907
-        ];
908
-        $statuses = apply_filters('FHEE__Events_Admin_Page__event_legend_items__statuses', $statuses);
909
-        return array_merge($items, $statuses);
910
-    }
911
-
912
-
913
-    /**
914
-     * @return EEM_Event
915
-     * @throws EE_Error
916
-     * @throws InvalidArgumentException
917
-     * @throws InvalidDataTypeException
918
-     * @throws InvalidInterfaceException
919
-     * @throws ReflectionException
920
-     */
921
-    private function _event_model(): EEM_Event
922
-    {
923
-        if (! $this->_event_model instanceof EEM_Event) {
924
-            $this->_event_model = EE_Registry::instance()->load_model('Event');
925
-        }
926
-        return $this->_event_model;
927
-    }
928
-
929
-
930
-    /**
931
-     * Adds extra buttons to the WP CPT permalink field row.
932
-     * Method is called from parent and is hooked into the wp 'get_sample_permalink_html' filter.
933
-     *
934
-     * @param string      $return    the current html
935
-     * @param int         $id        the post id for the page
936
-     * @param string|null $new_title What the title is
937
-     * @param string|null $new_slug  what the slug is
938
-     * @return string            The new html string for the permalink area
939
-     * @deprecated 5.0.0.p
940
-     * @see        TicketSelectorShortcodeButton::addButton
941
-     */
942
-    public function extra_permalink_field_buttons(
943
-        string $return,
944
-        int $id,
945
-        ?string $new_title,
946
-        ?string $new_slug
947
-    ): string {
948
-        return TicketSelectorShortcodeButton::addButton($return, $id, $new_title, $new_slug);
949
-    }
950
-
951
-
952
-    /**
953
-     * _events_overview_list_table
954
-     * This contains the logic for showing the events_overview list
955
-     *
956
-     * @access protected
957
-     * @return void
958
-     * @throws DomainException
959
-     * @throws EE_Error
960
-     * @throws InvalidArgumentException
961
-     * @throws InvalidDataTypeException
962
-     * @throws InvalidInterfaceException
963
-     */
964
-    protected function _events_overview_list_table()
965
-    {
966
-        $after_list_table = [];
967
-        $links_html       = EEH_HTML::div('', '', 'ee-admin-section ee-layout-stack');
968
-        $links_html       .= EEH_HTML::h3(esc_html__('Links', 'event_espresso'));
969
-        $links_html       .= EEH_HTML::div(
970
-            EEH_Template::get_button_or_link(
971
-                get_post_type_archive_link('espresso_events'),
972
-                esc_html__('View Event Archive Page', 'event_espresso'),
973
-                'button button--small button--secondary'
974
-            ),
975
-            '',
976
-            'ee-admin-button-row ee-admin-button-row--align-start'
977
-        );
978
-        $links_html       .= EEH_HTML::divx();
979
-
980
-        $after_list_table['view_event_list_button'] = $links_html;
981
-
982
-        $after_list_table['legend'] = $this->_display_legend($this->_event_legend_items());
983
-        $this->_admin_page_title    .= ' ' . $this->get_action_link_or_button(
984
-                'create_new',
985
-                'add',
986
-                [],
987
-                'add-new-h2'
988
-            );
989
-
990
-        $this->_template_args['after_list_table'] = array_merge(
991
-            (array) $this->_template_args['after_list_table'],
992
-            $after_list_table
993
-        );
994
-        $this->display_admin_list_table_page_with_no_sidebar();
995
-    }
996
-
997
-
998
-    /**
999
-     * this allows for extra misc actions in the default WP publish box
1000
-     *
1001
-     * @return void
1002
-     * @throws DomainException
1003
-     * @throws EE_Error
1004
-     * @throws InvalidArgumentException
1005
-     * @throws InvalidDataTypeException
1006
-     * @throws InvalidInterfaceException
1007
-     * @throws ReflectionException
1008
-     */
1009
-    public function extra_misc_actions_publish_box()
1010
-    {
1011
-        $this->_generate_publish_box_extra_content();
1012
-    }
1013
-
1014
-
1015
-    /**
1016
-     * This is hooked into the WordPress do_action('save_post') hook and runs after the custom post type has been
1017
-     * saved.
1018
-     * Typically you would use this to save any additional data.
1019
-     * Keep in mind also that "save_post" runs on EVERY post update to the database.
1020
-     * ALSO very important.  When a post transitions from scheduled to published,
1021
-     * the save_post action is fired but you will NOT have any _POST data containing any extra info you may have from
1022
-     * other meta saves. So MAKE sure that you handle this accordingly.
1023
-     *
1024
-     * @access protected
1025
-     * @abstract
1026
-     * @param string  $post_id The ID of the cpt that was saved (so you can link relationally)
1027
-     * @param WP_Post $post    The post object of the cpt that was saved.
1028
-     * @return void
1029
-     * @throws EE_Error
1030
-     * @throws InvalidArgumentException
1031
-     * @throws InvalidDataTypeException
1032
-     * @throws InvalidInterfaceException
1033
-     * @throws ReflectionException
1034
-     */
1035
-    protected function _insert_update_cpt_item($post_id, $post)
1036
-    {
1037
-        if ($post instanceof WP_Post && $post->post_type !== 'espresso_events') {
1038
-            // get out we're not processing an event save.
1039
-            return;
1040
-        }
1041
-        $event_values = [
1042
-            'EVT_member_only'     => $this->request->getRequestParam('member_only', false, DataType::BOOL),
1043
-            'EVT_allow_overflow'  => $this->request->getRequestParam('EVT_allow_overflow', false, DataType::BOOL),
1044
-            'EVT_timezone_string' => $this->request->getRequestParam('timezone_string'),
1045
-        ];
1046
-        // check if the new EDTR reg options meta box is being used, and if so, don't run updates for legacy version
1047
-        if (! $this->admin_config->useAdvancedEditor() || ! $this->feature->allowed('use_reg_options_meta_box')) {
1048
-            $event_values['EVT_display_ticket_selector']     = $this->request->getRequestParam(
1049
-                'display_ticket_selector',
1050
-                false,
1051
-                'bool'
1052
-            );
1053
-            $event_values['EVT_additional_limit']            = min(
1054
-                apply_filters('FHEE__EE_Events_Admin__insert_update_cpt_item__EVT_additional_limit_max', 255),
1055
-                $this->request->getRequestParam(
1056
-                    'additional_limit',
1057
-                    EEM_Event::get_default_additional_limit(),
1058
-                    'int'
1059
-                )
1060
-            );
1061
-            $event_values['EVT_default_registration_status'] = $this->request->getRequestParam(
1062
-                'EVT_default_registration_status',
1063
-                EE_Registry::instance()->CFG->registration->default_STS_ID
1064
-            );
1065
-
1066
-            $event_values['EVT_external_URL'] = $this->request->getRequestParam('externalURL');
1067
-            $event_values['EVT_phone']        = $this->request->getRequestParam('event_phone');
1068
-            $event_values['EVT_display_desc'] = $this->request->getRequestParam('display_desc', false, DataType::BOOL);
1069
-        } elseif ($post instanceof WP_Post) {
1070
-            $event_values['EVT_name'] = $post->post_title;
1071
-            $event_values['EVT_desc'] = $post->post_content;
1072
-        }
1073
-        // update event
1074
-        $success = $this->_event_model()->update_by_ID($event_values, $post_id);
1075
-        // get event_object for other metaboxes...
1076
-        // though it would seem to make sense to just use $this->_event_model()->get_one_by_ID( $post_id )..
1077
-        // i have to setup where conditions to override the filters in the model
1078
-        // that filter out auto-draft and inherit statuses so we GET the inherit id!
1079
-        /** @var EE_Event $event */
1080
-        $event = $this->_event_model()->get_one(
1081
-            [
1082
-                [
1083
-                    $this->_event_model()->primary_key_name() => $post_id,
1084
-                    'OR'                                      => [
1085
-                        'status'   => $post->post_status,
1086
-                        // if trying to "Publish" a sold out event, it's status will get switched back to "sold_out" in the db,
1087
-                        // but the returned object here has a status of "publish", so use the original post status as well
1088
-                        'status*1' => $this->request->getRequestParam('original_post_status'),
1089
-                    ],
1090
-                ],
1091
-            ]
1092
-        );
1093
-
1094
-        // the following are default callbacks for event attachment updates
1095
-        // that can be overridden by caffeinated functionality and/or addons.
1096
-        $event_update_callbacks = [];
1097
-        if (! $this->admin_config->useAdvancedEditor()) {
1098
-            $event_update_callbacks['_default_venue_update']   = [$this, '_default_venue_update'];
1099
-            $event_update_callbacks['_default_tickets_update'] = [$this, '_default_tickets_update'];
1100
-        }
1101
-        $event_update_callbacks = apply_filters(
1102
-            'FHEE__Events_Admin_Page___insert_update_cpt_item__event_update_callbacks',
1103
-            $event_update_callbacks
1104
-        );
1105
-
1106
-        $att_success = true;
1107
-        foreach ($event_update_callbacks as $e_callback) {
1108
-            $_success = is_callable($e_callback)
1109
-                ? $e_callback($event, $this->request->requestParams())
1110
-                : false;
1111
-            // if ANY of these updates fail then we want the appropriate global error message
1112
-            $att_success = $_success !== false ? $att_success : false;
1113
-        }
1114
-        // any errors?
1115
-        if ($success && $att_success === false) {
1116
-            EE_Error::add_error(
1117
-                esc_html__(
1118
-                    'Event Details saved successfully but something went wrong with saving attachments.',
1119
-                    'event_espresso'
1120
-                ),
1121
-                __FILE__,
1122
-                __FUNCTION__,
1123
-                __LINE__
1124
-            );
1125
-        } elseif ($success === false) {
1126
-            EE_Error::add_error(
1127
-                esc_html__('Event Details did not save successfully.', 'event_espresso'),
1128
-                __FILE__,
1129
-                __FUNCTION__,
1130
-                __LINE__
1131
-            );
1132
-        }
1133
-    }
1134
-
1135
-
1136
-    /**
1137
-     * @param int $post_id
1138
-     * @param int $revision_id
1139
-     * @throws EE_Error
1140
-     * @throws EE_Error
1141
-     * @throws ReflectionException
1142
-     * @see parent::restore_item()
1143
-     */
1144
-    protected function _restore_cpt_item(int $post_id, int $revision_id)
1145
-    {
1146
-        // copy existing event meta to new post
1147
-        $post_evt = $this->_event_model()->get_one_by_ID($post_id);
1148
-        if ($post_evt instanceof EE_Event) {
1149
-            // meta revision restore
1150
-            $post_evt->restore_revision($revision_id);
1151
-            // related objs restore
1152
-            $post_evt->restore_revision($revision_id, ['Venue', 'Datetime', 'Price']);
1153
-        }
1154
-    }
1155
-
1156
-
1157
-    /**
1158
-     * Attach the venue to the Event
1159
-     *
1160
-     * @param EE_Event $event Event Object to add the venue to
1161
-     * @param array    $data  The request data from the form
1162
-     * @return bool           Success or fail.
1163
-     * @throws EE_Error
1164
-     * @throws ReflectionException
1165
-     */
1166
-    protected function _default_venue_update(EE_Event $event, array $data): bool
1167
-    {
1168
-        require_once(EE_MODELS . 'EEM_Venue.model.php');
1169
-        $venue_model = EE_Registry::instance()->load_model('Venue');
1170
-        $venue_id    = ! empty($data['venue_id']) ? $data['venue_id'] : null;
1171
-        // very important.  If we don't have a venue name...
1172
-        // then we'll get out because not necessary to create empty venue
1173
-        if (empty($data['venue_title'])) {
1174
-            return false;
1175
-        }
1176
-        $venue_array = [
1177
-            'VNU_wp_user'         => $event->get('EVT_wp_user'),
1178
-            'VNU_name'            => $data['venue_title'],
1179
-            'VNU_desc'            => ! empty($data['venue_description']) ? $data['venue_description'] : null,
1180
-            'VNU_identifier'      => ! empty($data['venue_identifier']) ? $data['venue_identifier'] : null,
1181
-            'VNU_short_desc'      => ! empty($data['venue_short_description'])
1182
-                ? $data['venue_short_description']
1183
-                : null,
1184
-            'VNU_address'         => ! empty($data['address']) ? $data['address'] : null,
1185
-            'VNU_address2'        => ! empty($data['address2']) ? $data['address2'] : null,
1186
-            'VNU_city'            => ! empty($data['city']) ? $data['city'] : null,
1187
-            'STA_ID'              => ! empty($data['state']) ? $data['state'] : null,
1188
-            'CNT_ISO'             => ! empty($data['countries']) ? $data['countries'] : null,
1189
-            'VNU_zip'             => ! empty($data['zip']) ? $data['zip'] : null,
1190
-            'VNU_phone'           => ! empty($data['venue_phone']) ? $data['venue_phone'] : null,
1191
-            'VNU_capacity'        => ! empty($data['venue_capacity']) ? $data['venue_capacity'] : null,
1192
-            'VNU_url'             => ! empty($data['venue_url']) ? $data['venue_url'] : null,
1193
-            'VNU_virtual_phone'   => ! empty($data['virtual_phone']) ? $data['virtual_phone'] : null,
1194
-            'VNU_virtual_url'     => ! empty($data['virtual_url']) ? $data['virtual_url'] : null,
1195
-            'VNU_enable_for_gmap' => isset($data['enable_for_gmap']) ? 1 : 0,
1196
-            'status'              => 'publish',
1197
-        ];
1198
-        // if we've got the venue_id then we're just updating the existing venue so let's do that and then get out.
1199
-        if (! empty($venue_id)) {
1200
-            $update_where  = [$venue_model->primary_key_name() => $venue_id];
1201
-            $rows_affected = $venue_model->update($venue_array, [$update_where]);
1202
-            // we've gotta make sure that the venue is always attached to a revision..
1203
-            // add_relation_to should take care of making sure that the relation is already present.
1204
-            $event->_add_relation_to($venue_id, 'Venue');
1205
-            return $rows_affected > 0;
1206
-        }
1207
-        // we insert the venue
1208
-        $venue_id = $venue_model->insert($venue_array);
1209
-        $event->_add_relation_to($venue_id, 'Venue');
1210
-        return ! empty($venue_id);
1211
-        // when we have the ancestor come in it's already been handled by the revision save.
1212
-    }
1213
-
1214
-
1215
-    /**
1216
-     * Handles saving everything related to Tickets (datetimes, tickets, prices)
1217
-     *
1218
-     * @param EE_Event $event The Event object we're attaching data to
1219
-     * @param array    $data  The request data from the form
1220
-     * @return array
1221
-     * @throws EE_Error
1222
-     * @throws ReflectionException
1223
-     * @throws Exception
1224
-     */
1225
-    protected function _default_tickets_update(EE_Event $event, array $data): array
1226
-    {
1227
-        if ($this->admin_config->useAdvancedEditor()) {
1228
-            return [];
1229
-        }
1230
-        $datetime       = null;
1231
-        $saved_tickets  = [];
1232
-        $event_timezone = $event->get_timezone();
1233
-        $date_formats   = ['Y-m-d', 'h:i a'];
1234
-        foreach ($data['edit_event_datetimes'] as $row => $datetime_data) {
1235
-            // trim all values to ensure any excess whitespace is removed.
1236
-            $datetime_data                = array_map('trim', $datetime_data);
1237
-            $datetime_data['DTT_EVT_end'] = ! empty($datetime_data['DTT_EVT_end'])
1238
-                    ? $datetime_data['DTT_EVT_end']
1239
-                    : $datetime_data['DTT_EVT_start'];
1240
-            $datetime_values              = [
1241
-                'DTT_ID'        => ! empty($datetime_data['DTT_ID']) ? $datetime_data['DTT_ID'] : null,
1242
-                'DTT_EVT_start' => $datetime_data['DTT_EVT_start'],
1243
-                'DTT_EVT_end'   => $datetime_data['DTT_EVT_end'],
1244
-                'DTT_reg_limit' => empty($datetime_data['DTT_reg_limit']) ? EE_INF : $datetime_data['DTT_reg_limit'],
1245
-                'DTT_order'     => $row,
1246
-            ];
1247
-            // if we have an id then let's get existing object first and then set the new values.
1248
-            //  Otherwise we instantiate a new object for save.
1249
-            if (! empty($datetime_data['DTT_ID'])) {
1250
-                $datetime = EEM_Datetime::instance($event_timezone)->get_one_by_ID($datetime_data['DTT_ID']);
1251
-                if (! $datetime instanceof EE_Datetime) {
1252
-                    throw new RuntimeException(
1253
-                        sprintf(
1254
-                            esc_html__(
1255
-                                'Something went wrong! A valid Datetime could not be retrieved from the database using the supplied ID: %1$d',
1256
-                                'event_espresso'
1257
-                            ),
1258
-                            $datetime_data['DTT_ID']
1259
-                        )
1260
-                    );
1261
-                }
1262
-                $datetime->set_date_format($date_formats[0]);
1263
-                $datetime->set_time_format($date_formats[1]);
1264
-                foreach ($datetime_values as $field => $value) {
1265
-                    $datetime->set($field, $value);
1266
-                }
1267
-            } else {
1268
-                $datetime = EE_Datetime::new_instance($datetime_values, $event_timezone, $date_formats);
1269
-            }
1270
-            if (! $datetime instanceof EE_Datetime) {
1271
-                throw new RuntimeException(
1272
-                    sprintf(
1273
-                        esc_html__(
1274
-                            'Something went wrong! A valid Datetime could not be generated or retrieved using the supplied data: %1$s',
1275
-                            'event_espresso'
1276
-                        ),
1277
-                        print_r($datetime_values, true)
1278
-                    )
1279
-                );
1280
-            }
1281
-            // before going any further make sure our dates are setup correctly
1282
-            // so that the end date is always equal or greater than the start date.
1283
-            if ($datetime->get_raw('DTT_EVT_start') > $datetime->get_raw('DTT_EVT_end')) {
1284
-                $datetime->set('DTT_EVT_end', $datetime->get('DTT_EVT_start'));
1285
-                $datetime = EEH_DTT_Helper::date_time_add($datetime, 'DTT_EVT_end', 'days');
1286
-            }
1287
-            $datetime->save();
1288
-            $event->_add_relation_to($datetime, 'Datetime');
1289
-        }
1290
-        // no datetimes get deleted so we don't do any of that logic here.
1291
-        // update tickets next
1292
-        $old_tickets = isset($data['ticket_IDs']) ? explode(',', $data['ticket_IDs']) : [];
1293
-
1294
-        // set up some default start and end dates in case those are not present in the incoming data
1295
-        $default_start_date = new DateTime('now', new DateTimeZone($event->get_timezone()));
1296
-        $default_start_date = $default_start_date->format($date_formats[0] . ' ' . $date_formats[1]);
1297
-        // use the start date of the first datetime for the end date
1298
-        $first_datetime   = $event->first_datetime();
1299
-        $default_end_date = $first_datetime->start_date_and_time($date_formats[0], $date_formats[1]);
1300
-
1301
-        // now process the incoming data
1302
-        foreach ($data['edit_tickets'] as $row => $ticket_data) {
1303
-            $update_prices = false;
1304
-            $ticket_price  = $data['edit_prices'][ $row ][1]['PRC_amount'] ?? 0;
1305
-            // trim inputs to ensure any excess whitespace is removed.
1306
-            $ticket_data   = array_map('trim', $ticket_data);
1307
-            $ticket_values = [
1308
-                'TKT_ID'          => ! empty($ticket_data['TKT_ID']) ? $ticket_data['TKT_ID'] : null,
1309
-                'TTM_ID'          => ! empty($ticket_data['TTM_ID']) ? $ticket_data['TTM_ID'] : 0,
1310
-                'TKT_name'        => ! empty($ticket_data['TKT_name']) ? $ticket_data['TKT_name'] : '',
1311
-                'TKT_description' => ! empty($ticket_data['TKT_description']) ? $ticket_data['TKT_description'] : '',
1312
-                'TKT_start_date'  => ! empty($ticket_data['TKT_start_date'])
1313
-                    ? $ticket_data['TKT_start_date']
1314
-                    : $default_start_date,
1315
-                'TKT_end_date'    => ! empty($ticket_data['TKT_end_date'])
1316
-                    ? $ticket_data['TKT_end_date']
1317
-                    : $default_end_date,
1318
-                'TKT_qty'         => ! empty($ticket_data['TKT_qty'])
1319
-                                     || (isset($ticket_data['TKT_qty']) && (int) $ticket_data['TKT_qty'] === 0)
1320
-                    ? $ticket_data['TKT_qty']
1321
-                    : EE_INF,
1322
-                'TKT_uses'        => ! empty($ticket_data['TKT_uses'])
1323
-                                     || (isset($ticket_data['TKT_uses']) && (int) $ticket_data['TKT_uses'] === 0)
1324
-                    ? $ticket_data['TKT_uses']
1325
-                    : EE_INF,
1326
-                'TKT_min'         => ! empty($ticket_data['TKT_min']) ? $ticket_data['TKT_min'] : 0,
1327
-                'TKT_max'         => ! empty($ticket_data['TKT_max']) ? $ticket_data['TKT_max'] : EE_INF,
1328
-                'TKT_order'       => $ticket_data['TKT_order'] ?? $row,
1329
-                'TKT_price'       => $ticket_price,
1330
-                'TKT_row'         => $row,
1331
-            ];
1332
-            // if this is a default ticket, then we need to set the TKT_ID to 0 and update accordingly,
1333
-            // which means in turn that the prices will become new prices as well.
1334
-            if (isset($ticket_data['TKT_is_default']) && $ticket_data['TKT_is_default']) {
1335
-                $ticket_values['TKT_ID']         = 0;
1336
-                $ticket_values['TKT_is_default'] = 0;
1337
-                $update_prices                   = true;
1338
-            }
1339
-            // if we have a TKT_ID then we need to get that existing TKT_obj and update it
1340
-            // we actually do our saves ahead of adding any relations because its entirely possible that this
1341
-            // ticket didn't get removed or added to any datetime in the session but DID have it's items modified.
1342
-            // keep in mind that if the ticket has been sold (and we have changed pricing information),
1343
-            // then we won't be updating the tkt but instead a new tkt will be created and the old one archived.
1344
-            if (! empty($ticket_data['TKT_ID'])) {
1345
-                $existing_ticket = EEM_Ticket::instance($event_timezone)->get_one_by_ID($ticket_data['TKT_ID']);
1346
-                if (! $existing_ticket instanceof EE_Ticket) {
1347
-                    throw new RuntimeException(
1348
-                        sprintf(
1349
-                            esc_html__(
1350
-                                'Something went wrong! A valid Ticket could not be retrieved from the database using the supplied ID: %1$d',
1351
-                                'event_espresso'
1352
-                            ),
1353
-                            $ticket_data['TKT_ID']
1354
-                        )
1355
-                    );
1356
-                }
1357
-                $ticket_sold = $existing_ticket->count_related(
1358
-                        'Registration',
1359
-                        [
1360
-                            [
1361
-                                'STS_ID' => [
1362
-                                    'NOT IN',
1363
-                                    [EEM_Registration::status_id_incomplete],
1364
-                                ],
1365
-                            ],
1366
-                        ]
1367
-                    ) > 0;
1368
-                // let's just check the total price for the existing ticket and determine if it matches the new total price.
1369
-                // if they are different then we create a new ticket (if $ticket_sold)
1370
-                // if they aren't different then we go ahead and modify existing ticket.
1371
-                $create_new_ticket = $ticket_sold
1372
-                                     && $ticket_price !== $existing_ticket->price()
1373
-                                     && ! $existing_ticket->deleted();
1374
-                $existing_ticket->set_date_format($date_formats[0]);
1375
-                $existing_ticket->set_time_format($date_formats[1]);
1376
-                // set new values
1377
-                foreach ($ticket_values as $field => $value) {
1378
-                    if ($field == 'TKT_qty') {
1379
-                        $existing_ticket->set_qty($value);
1380
-                    } elseif ($field == 'TKT_price') {
1381
-                        $existing_ticket->set('TKT_price', $ticket_price);
1382
-                    } else {
1383
-                        $existing_ticket->set($field, $value);
1384
-                    }
1385
-                }
1386
-                $ticket = $existing_ticket;
1387
-                // if $create_new_ticket is false then we can safely update the existing ticket.
1388
-                //  Otherwise we have to create a new ticket.
1389
-                if ($create_new_ticket) {
1390
-                    // archive the old ticket first
1391
-                    $existing_ticket->set('TKT_deleted', 1);
1392
-                    $existing_ticket->save();
1393
-                    // make sure this ticket is still recorded in our $saved_tickets
1394
-                    // so we don't run it through the regular trash routine.
1395
-                    $saved_tickets[ $existing_ticket->ID() ] = $existing_ticket;
1396
-                    // create new ticket that's a copy of the existing except,
1397
-                    // (a new id of course and not archived) AND has the new TKT_price associated with it.
1398
-                    $new_ticket = clone $existing_ticket;
1399
-                    $new_ticket->set('TKT_ID', 0);
1400
-                    $new_ticket->set('TKT_deleted', 0);
1401
-                    $new_ticket->set('TKT_sold', 0);
1402
-                    // now we need to make sure that $new prices are created as well and attached to new ticket.
1403
-                    $update_prices = true;
1404
-                    $ticket        = $new_ticket;
1405
-                }
1406
-            } else {
1407
-                // no TKT_id so a new ticket
1408
-                $ticket_values['TKT_price'] = $ticket_price;
1409
-                $ticket                     = EE_Ticket::new_instance($ticket_values, $event_timezone, $date_formats);
1410
-                $update_prices              = true;
1411
-            }
1412
-            if (! $ticket instanceof EE_Ticket) {
1413
-                throw new RuntimeException(
1414
-                    sprintf(
1415
-                        esc_html__(
1416
-                            'Something went wrong! A valid Ticket could not be generated or retrieved using the supplied data: %1$s',
1417
-                            'event_espresso'
1418
-                        ),
1419
-                        print_r($ticket_values, true)
1420
-                    )
1421
-                );
1422
-            }
1423
-            // cap ticket qty by datetime reg limits
1424
-            $ticket->set_qty(min($ticket->qty(), $ticket->qty('reg_limit')));
1425
-            // update ticket.
1426
-            $ticket->save();
1427
-            // before going any further make sure our dates are setup correctly
1428
-            // so that the end date is always equal or greater than the start date.
1429
-            if ($ticket->get_raw('TKT_start_date') > $ticket->get_raw('TKT_end_date')) {
1430
-                $ticket->set('TKT_end_date', $ticket->get('TKT_start_date'));
1431
-                $ticket = EEH_DTT_Helper::date_time_add($ticket, 'TKT_end_date', 'days');
1432
-                $ticket->save();
1433
-            }
1434
-            // initially let's add the ticket to the datetime
1435
-            $datetime->_add_relation_to($ticket, 'Ticket');
1436
-            $saved_tickets[ $ticket->ID() ] = $ticket;
1437
-            // add prices to ticket
1438
-            $prices_data = isset($data['edit_prices'][ $row ]) && is_array($data['edit_prices'][ $row ])
1439
-                ? $data['edit_prices'][ $row ]
1440
-                : [];
1441
-            $this->_add_prices_to_ticket($prices_data, $ticket, $update_prices);
1442
-        }
1443
-        // however now we need to handle permanently deleting tickets via the ui.
1444
-        // Keep in mind that the ui does not allow deleting/archiving tickets that have ticket sold.
1445
-        // However, it does allow for deleting tickets that have no tickets sold,
1446
-        // in which case we want to get rid of permanently because there is no need to save in db.
1447
-        $old_tickets     = isset($old_tickets[0]) && $old_tickets[0] === '' ? [] : $old_tickets;
1448
-        $tickets_removed = array_diff($old_tickets, array_keys($saved_tickets));
1449
-        foreach ($tickets_removed as $id) {
1450
-            $id = absint($id);
1451
-            // get the ticket for this id
1452
-            $ticket_to_remove = EEM_Ticket::instance()->get_one_by_ID($id);
1453
-            if (! $ticket_to_remove instanceof EE_Ticket) {
1454
-                continue;
1455
-            }
1456
-            // need to get all the related datetimes on this ticket and remove from every single one of them
1457
-            // (remember this process can ONLY kick off if there are NO tickets sold)
1458
-            $related_datetimes = $ticket_to_remove->get_many_related('Datetime');
1459
-            foreach ($related_datetimes as $related_datetime) {
1460
-                $ticket_to_remove->_remove_relation_to($related_datetime, 'Datetime');
1461
-            }
1462
-            // need to do the same for prices (except these prices can also be deleted because again,
1463
-            // tickets can only be trashed if they don't have any TKTs sold (otherwise they are just archived))
1464
-            $ticket_to_remove->delete_related_permanently('Price');
1465
-            // finally let's delete this ticket
1466
-            // (which should not be blocked at this point b/c we've removed all our relationships)
1467
-            $ticket_to_remove->delete_permanently();
1468
-        }
1469
-        return [$datetime, $saved_tickets];
1470
-    }
1471
-
1472
-
1473
-    /**
1474
-     * This attaches a list of given prices to a ticket.
1475
-     * Note we dont' have to worry about ever removing relationships (or archiving prices)
1476
-     * because if there is a change in price information on a ticket, a new ticket is created anyways
1477
-     * so the archived ticket will retain the old price info and prices are automatically "archived" via the ticket.
1478
-     *
1479
-     * @access  private
1480
-     * @param array     $prices_data Array of prices from the form.
1481
-     * @param EE_Ticket $ticket      EE_Ticket object that prices are being attached to.
1482
-     * @param bool      $new_prices  Whether attach existing incoming prices or create new ones.
1483
-     * @return  void
1484
-     * @throws EE_Error
1485
-     * @throws ReflectionException
1486
-     */
1487
-    private function _add_prices_to_ticket(array $prices_data, EE_Ticket $ticket, bool $new_prices = false)
1488
-    {
1489
-        $timezone = $ticket->get_timezone();
1490
-        foreach ($prices_data as $row => $price_data) {
1491
-            $price_values = [
1492
-                'PRC_ID'         => ! empty($price_data['PRC_ID']) ? $price_data['PRC_ID'] : null,
1493
-                'PRT_ID'         => ! empty($price_data['PRT_ID']) ? $price_data['PRT_ID'] : null,
1494
-                'PRC_amount'     => ! empty($price_data['PRC_amount']) ? $price_data['PRC_amount'] : 0,
1495
-                'PRC_name'       => ! empty($price_data['PRC_name']) ? $price_data['PRC_name'] : '',
1496
-                'PRC_desc'       => ! empty($price_data['PRC_desc']) ? $price_data['PRC_desc'] : '',
1497
-                'PRC_is_default' => 0, // make sure prices are NOT set as default from this context
1498
-                'PRC_order'      => $row,
1499
-            ];
1500
-            if ($new_prices || empty($price_values['PRC_ID'])) {
1501
-                $price_values['PRC_ID'] = 0;
1502
-                $price                  = EE_Price::new_instance($price_values, $timezone);
1503
-            } else {
1504
-                $price = EEM_Price::instance($timezone)->get_one_by_ID($price_data['PRC_ID']);
1505
-                // update this price with new values
1506
-                foreach ($price_values as $field => $new_price) {
1507
-                    $price->set($field, $new_price);
1508
-                }
1509
-            }
1510
-            if (! $price instanceof EE_Price) {
1511
-                throw new RuntimeException(
1512
-                    sprintf(
1513
-                        esc_html__(
1514
-                            'Something went wrong! A valid Price could not be generated or retrieved using the supplied data: %1$s',
1515
-                            'event_espresso'
1516
-                        ),
1517
-                        print_r($price_values, true)
1518
-                    )
1519
-                );
1520
-            }
1521
-            $price->save();
1522
-            $ticket->_add_relation_to($price, 'Price');
1523
-        }
1524
-    }
1525
-
1526
-
1527
-    /**
1528
-     * Add in our autosave ajax handlers
1529
-     */
1530
-    protected function _ee_autosave_create_new()
1531
-    {
1532
-    }
1533
-
1534
-
1535
-    /**
1536
-     * More autosave handlers.
1537
-     */
1538
-    protected function _ee_autosave_edit()
1539
-    {
1540
-    }
1541
-
1542
-
1543
-    /**
1544
-     * @throws EE_Error
1545
-     * @throws ReflectionException
1546
-     */
1547
-    private function _generate_publish_box_extra_content()
1548
-    {
1549
-        // load formatter helper
1550
-        // args for getting related registrations
1551
-        $approved_query_args        = [
1552
-            [
1553
-                'REG_deleted' => 0,
1554
-                'STS_ID'      => EEM_Registration::status_id_approved,
1555
-            ],
1556
-        ];
1557
-        $not_approved_query_args    = [
1558
-            [
1559
-                'REG_deleted' => 0,
1560
-                'STS_ID'      => EEM_Registration::status_id_not_approved,
1561
-            ],
1562
-        ];
1563
-        $pending_payment_query_args = [
1564
-            [
1565
-                'REG_deleted' => 0,
1566
-                'STS_ID'      => EEM_Registration::status_id_pending_payment,
1567
-            ],
1568
-        ];
1569
-        // publish box
1570
-        $publish_box_extra_args = [
1571
-            'view_approved_reg_url'        => add_query_arg(
1572
-                [
1573
-                    'action'      => 'default',
1574
-                    'event_id'    => $this->_cpt_model_obj->ID(),
1575
-                    '_reg_status' => EEM_Registration::status_id_approved,
1576
-                    'use_filters' => true,
1577
-                ],
1578
-                REG_ADMIN_URL
1579
-            ),
1580
-            'view_not_approved_reg_url'    => add_query_arg(
1581
-                [
1582
-                    'action'      => 'default',
1583
-                    'event_id'    => $this->_cpt_model_obj->ID(),
1584
-                    '_reg_status' => EEM_Registration::status_id_not_approved,
1585
-                    'use_filters' => true,
1586
-                ],
1587
-                REG_ADMIN_URL
1588
-            ),
1589
-            'view_pending_payment_reg_url' => add_query_arg(
1590
-                [
1591
-                    'action'      => 'default',
1592
-                    'event_id'    => $this->_cpt_model_obj->ID(),
1593
-                    '_reg_status' => EEM_Registration::status_id_pending_payment,
1594
-                    'use_filters' => true,
1595
-                ],
1596
-                REG_ADMIN_URL
1597
-            ),
1598
-            'approved_regs'                => $this->_cpt_model_obj->count_related(
1599
-                'Registration',
1600
-                $approved_query_args
1601
-            ),
1602
-            'not_approved_regs'            => $this->_cpt_model_obj->count_related(
1603
-                'Registration',
1604
-                $not_approved_query_args
1605
-            ),
1606
-            'pending_payment_regs'         => $this->_cpt_model_obj->count_related(
1607
-                'Registration',
1608
-                $pending_payment_query_args
1609
-            ),
1610
-            'misc_pub_section_class'       => apply_filters(
1611
-                'FHEE_Events_Admin_Page___generate_publish_box_extra_content__misc_pub_section_class',
1612
-                'misc-pub-section'
1613
-            ),
1614
-        ];
1615
-        ob_start();
1616
-        do_action(
1617
-            'AHEE__Events_Admin_Page___generate_publish_box_extra_content__event_editor_overview_add',
1618
-            $this->_cpt_model_obj
1619
-        );
1620
-        $publish_box_extra_args['event_editor_overview_add'] = ob_get_clean();
1621
-        // load template
1622
-        EEH_Template::display_template(
1623
-            EVENTS_TEMPLATE_PATH . 'event_publish_box_extras.template.php',
1624
-            $publish_box_extra_args
1625
-        );
1626
-    }
1627
-
1628
-
1629
-    /**
1630
-     * @return EE_Event
1631
-     */
1632
-    public function get_event_object()
1633
-    {
1634
-        return $this->_cpt_model_obj;
1635
-    }
1636
-
1637
-
1638
-
1639
-
1640
-    /** METABOXES * */
1641
-    /**
1642
-     * _register_event_editor_meta_boxes
1643
-     * add all metaboxes related to the event_editor
1644
-     *
1645
-     * @return void
1646
-     * @throws EE_Error
1647
-     * @throws ReflectionException
1648
-     */
1649
-    protected function _register_event_editor_meta_boxes()
1650
-    {
1651
-        $this->verify_cpt_object();
1652
-        $use_advanced_editor = $this->admin_config->useAdvancedEditor();
1653
-        // check if the new EDTR reg options meta box is being used, and if so, don't load the legacy version
1654
-        if (! $use_advanced_editor || ! $this->feature->allowed('use_reg_options_meta_box')) {
1655
-            $this->addMetaBox(
1656
-                'espresso_event_editor_event_options',
1657
-                esc_html__('Event Registration Options', 'event_espresso'),
1658
-                [$this, 'registration_options_meta_box'],
1659
-                $this->page_slug,
1660
-                'side'
1661
-            );
1662
-        }
1663
-        if (! $use_advanced_editor) {
1664
-            $this->addMetaBox(
1665
-                'espresso_event_editor_tickets',
1666
-                esc_html__('Event Datetime & Ticket', 'event_espresso'),
1667
-                [$this, 'ticket_metabox'],
1668
-                $this->page_slug,
1669
-                'normal',
1670
-                'high'
1671
-            );
1672
-        } elseif ($this->feature->allowed('use_reg_options_meta_box')) {
1673
-            add_action(
1674
-                'add_meta_boxes_espresso_events',
1675
-                function () {
1676
-                    global $current_screen;
1677
-                    remove_meta_box('authordiv', $current_screen, 'normal');
1678
-                },
1679
-                99
1680
-            );
1681
-        }
1682
-        // NOTE: if you're looking for other metaboxes in here,
1683
-        // where a metabox has a related management page in the admin
1684
-        // you will find it setup in the related management page's "_Hooks" file.
1685
-        // i.e. messages metabox is found in "espresso_events_Messages_Hooks.class.php".
1686
-    }
1687
-
1688
-
1689
-    /**
1690
-     * @throws DomainException
1691
-     * @throws EE_Error
1692
-     * @throws ReflectionException
1693
-     */
1694
-    public function ticket_metabox()
1695
-    {
1696
-        $existing_datetime_ids = $existing_ticket_ids = [];
1697
-        // defaults for template args
1698
-        $template_args = [
1699
-            'ticket_rows'       => '',
1700
-            'total_ticket_rows' => 1,
1701
-            'trash_icon'        => 'dashicons dashicons-lock',
1702
-            'disabled'          => '',
1703
-        ];
1704
-        $event_id      = is_object($this->_cpt_model_obj) ? $this->_cpt_model_obj->ID() : null;
1705
-        /**
1706
-         * 1. Start with retrieving Datetimes
1707
-         * 2. Fore each datetime get related tickets
1708
-         * 3. For each ticket get related prices
1709
-         */
1710
-        /** @var EEM_Datetime $datetime_model */
1711
-        $datetime_model = EE_Registry::instance()->load_model('Datetime');
1712
-        /** @var EEM_Ticket $datetime_model */
1713
-        $ticket_model = EE_Registry::instance()->load_model('Ticket');
1714
-        $times        = $datetime_model->get_all_event_dates($event_id);
1715
-        /** @type EE_Datetime $first_datetime */
1716
-        $first_datetime = reset($times);
1717
-        // do we get related tickets?
1718
-        if (
1719
-            $first_datetime instanceof EE_Datetime
1720
-            && $first_datetime->ID() !== 0
1721
-        ) {
1722
-            $existing_datetime_ids[] = $first_datetime->get('DTT_ID');
1723
-            $template_args['time']   = $first_datetime;
1724
-            $related_tickets         = $first_datetime->tickets(
1725
-                [
1726
-                    ['OR' => ['TKT_deleted' => 1, 'TKT_deleted*' => 0]],
1727
-                    'default_where_conditions' => 'none',
1728
-                ]
1729
-            );
1730
-            if (! empty($related_tickets)) {
1731
-                $template_args['total_ticket_rows'] = count($related_tickets);
1732
-                $row                                = 0;
1733
-                foreach ($related_tickets as $ticket) {
1734
-                    $existing_ticket_ids[]        = $ticket->get('TKT_ID');
1735
-                    $template_args['ticket_rows'] .= $this->_get_ticket_row($ticket, false, $row);
1736
-                    $row++;
1737
-                }
1738
-            } else {
1739
-                $template_args['total_ticket_rows'] = 1;
1740
-                /** @type EE_Ticket $ticket */
1741
-                $ticket                       = $ticket_model->create_default_object();
1742
-                $template_args['ticket_rows'] .= $this->_get_ticket_row($ticket);
1743
-            }
1744
-        } else {
1745
-            $template_args['time'] = $times[0];
1746
-            /** @type EE_Ticket[] $tickets */
1747
-            $tickets                      = $ticket_model->get_all_default_tickets();
1748
-            $template_args['ticket_rows'] .= $this->_get_ticket_row($tickets[1]);
1749
-            // NOTE: we're just sending the first default row
1750
-            // (decaf can't manage default tickets so this should be sufficient);
1751
-        }
1752
-        $template_args['event_datetime_help_link'] = $this->_get_help_tab_link(
1753
-            'event_editor_event_datetimes_help_tab'
1754
-        );
1755
-        $template_args['ticket_options_help_link'] = $this->_get_help_tab_link('ticket_options_info');
1756
-        $template_args['existing_datetime_ids']    = implode(',', $existing_datetime_ids);
1757
-        $template_args['existing_ticket_ids']      = implode(',', $existing_ticket_ids);
1758
-        $template_args['ticket_js_structure']      = $this->_get_ticket_row(
1759
-            $ticket_model->create_default_object(),
1760
-            true
1761
-        );
1762
-        $template                                  = apply_filters(
1763
-            'FHEE__Events_Admin_Page__ticket_metabox__template',
1764
-            EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_main.template.php'
1765
-        );
1766
-        EEH_Template::display_template($template, $template_args);
1767
-    }
1768
-
1769
-
1770
-    /**
1771
-     * Setup an individual ticket form for the decaf event editor page
21
+	/**
22
+	 * primary key for the event model
23
+	 */
24
+	private int $EVT_ID = 0;
25
+
26
+	/**
27
+	 * This will hold the event object for event_details screen.
28
+	 *
29
+	 * @var EE_Event|null $_event
30
+	 */
31
+	protected ?EE_Event $_event = null;
32
+
33
+	/**
34
+	 * This will hold the category object for category_details screen.
35
+	 */
36
+	protected ?stdClass $_category = null;
37
+
38
+	protected ?EEM_Event $_event_model = null;
39
+
40
+	/**
41
+	 * @var EE_Event|EE_CPT_Base|null $_cpt_model_obj
42
+	 */
43
+	protected $_cpt_model_obj;
44
+
45
+	protected ?NodeGroupDao $model_obj_node_group_persister = null;
46
+
47
+	protected ?AdvancedEditorAdminFormSection $advanced_editor_admin_form = null;
48
+
49
+
50
+	/**
51
+	 * Initialize page props for this admin page group.
52
+	 */
53
+	protected function _init_page_props()
54
+	{
55
+		// is there a evt_id in the request?
56
+		$this->EVT_ID = $this->request->getRequestParam('EVT_ID', 0, DataType::INT);
57
+		$this->EVT_ID = $this->request->getRequestParam('post', $this->EVT_ID, DataType::INT);
58
+		$this->EVT_ID = $this->request->getRequestParam('post_ID', $this->EVT_ID, DataType::INT);
59
+
60
+		$this->page_slug        = EVENTS_PG_SLUG;
61
+		$this->page_label       = EVENTS_LABEL;
62
+		$this->_admin_base_url  = EVENTS_ADMIN_URL;
63
+		$this->_admin_base_path = EVENTS_ADMIN;
64
+		$this->_cpt_model_names = [
65
+			'create_new' => 'EEM_Event',
66
+			'edit'       => 'EEM_Event',
67
+		];
68
+		$this->_cpt_edit_routes = [
69
+			'espresso_events' => 'edit',
70
+		];
71
+		add_action(
72
+			'AHEE__EE_Admin_Page_CPT__set_model_object__after_set_object',
73
+			[$this, 'verify_event_edit'],
74
+			10,
75
+			2
76
+		);
77
+	}
78
+
79
+
80
+	/**
81
+	 * Sets the ajax hooks used for this admin page group.
82
+	 */
83
+	protected function _ajax_hooks()
84
+	{
85
+		add_action('wp_ajax_ee_save_timezone_setting', [$this, 'saveTimezoneString']);
86
+	}
87
+
88
+
89
+	/**
90
+	 * Sets the page properties for this admin page group.
91
+	 */
92
+	protected function _define_page_props()
93
+	{
94
+		$this->_admin_page_title = EVENTS_LABEL;
95
+		$this->_labels           = [
96
+			'buttons'      => [
97
+				'add'             => esc_html__('Add New Event', 'event_espresso'),
98
+				'edit'            => esc_html__('Edit Event', 'event_espresso'),
99
+				'delete'          => esc_html__('Delete Event', 'event_espresso'),
100
+				'add_category'    => esc_html__('Add New Category', 'event_espresso'),
101
+				'edit_category'   => esc_html__('Edit Category', 'event_espresso'),
102
+				'delete_category' => esc_html__('Delete Category', 'event_espresso'),
103
+			],
104
+			'editor_title' => [
105
+				'espresso_events' => esc_html__('Edit Event', 'event_espresso'),
106
+			],
107
+			'publishbox'   => [
108
+				'create_new'        => esc_html__('Save New Event', 'event_espresso'),
109
+				'edit'              => esc_html__('Update Event', 'event_espresso'),
110
+				'add_category'      => esc_html__('Save New Category', 'event_espresso'),
111
+				'edit_category'     => esc_html__('Update Category', 'event_espresso'),
112
+				'template_settings' => esc_html__('Update Settings', 'event_espresso'),
113
+			],
114
+		];
115
+	}
116
+
117
+
118
+	/**
119
+	 * Sets the page routes property for this admin page group.
120
+	 */
121
+	protected function _set_page_routes()
122
+	{
123
+		$this->_page_routes = [
124
+			'default'                       => [
125
+				'func'       => [$this, '_events_overview_list_table'],
126
+				'capability' => 'ee_read_events',
127
+			],
128
+			'create_new'                    => [
129
+				'func'       => [$this, '_create_new_cpt_item'],
130
+				'capability' => 'ee_edit_events',
131
+			],
132
+			'edit'                          => [
133
+				'func'       => [$this, '_edit_cpt_item'],
134
+				'capability' => 'ee_edit_event',
135
+				'obj_id'     => $this->EVT_ID,
136
+			],
137
+			'copy_event'                    => [
138
+				'func'       => [$this, '_copy_events'],
139
+				'capability' => 'ee_edit_event',
140
+				'obj_id'     => $this->EVT_ID,
141
+				'noheader'   => true,
142
+			],
143
+			'trash_event'                   => [
144
+				'func'       => [$this, '_trash_or_restore_event'],
145
+				'args'       => ['event_status' => 'trash'],
146
+				'capability' => 'ee_delete_event',
147
+				'obj_id'     => $this->EVT_ID,
148
+				'noheader'   => true,
149
+			],
150
+			'trash_events'                  => [
151
+				'func'       => [$this, '_trash_or_restore_events'],
152
+				'args'       => ['event_status' => 'trash'],
153
+				'capability' => 'ee_delete_events',
154
+				'noheader'   => true,
155
+			],
156
+			'restore_event'                 => [
157
+				'func'       => [$this, '_trash_or_restore_event'],
158
+				'args'       => ['event_status' => 'draft'],
159
+				'capability' => 'ee_delete_event',
160
+				'obj_id'     => $this->EVT_ID,
161
+				'noheader'   => true,
162
+			],
163
+			'restore_events'                => [
164
+				'func'       => [$this, '_trash_or_restore_events'],
165
+				'args'       => ['event_status' => 'draft'],
166
+				'capability' => 'ee_delete_events',
167
+				'noheader'   => true,
168
+			],
169
+			'delete_event'                  => [
170
+				'func'       => [$this, '_delete_event'],
171
+				'capability' => 'ee_delete_event',
172
+				'obj_id'     => $this->EVT_ID,
173
+				'noheader'   => true,
174
+			],
175
+			'delete_events'                 => [
176
+				'func'       => [$this, '_delete_events'],
177
+				'capability' => 'ee_delete_events',
178
+				'noheader'   => true,
179
+			],
180
+			'view_report'                   => [
181
+				'func'       => [$this, '_view_report'],
182
+				'capability' => 'ee_edit_events',
183
+			],
184
+			'default_event_settings'        => [
185
+				'func'       => [$this, '_default_event_settings'],
186
+				'capability' => 'manage_options',
187
+			],
188
+			'update_default_event_settings' => [
189
+				'func'       => [$this, '_update_default_event_settings'],
190
+				'capability' => 'manage_options',
191
+				'noheader'   => true,
192
+			],
193
+			'template_settings'             => [
194
+				'func'       => [$this, '_template_settings'],
195
+				'capability' => 'manage_options',
196
+			],
197
+			// event category tab related
198
+			'add_category'                  => [
199
+				'func'       => [$this, '_category_details'],
200
+				'capability' => 'ee_edit_event_category',
201
+				'args'       => ['view' => 'add'],
202
+			],
203
+			'edit_category'                 => [
204
+				'func'       => [$this, '_category_details'],
205
+				'capability' => 'ee_edit_event_category',
206
+				'args'       => ['view' => 'edit'],
207
+			],
208
+			'delete_categories'             => [
209
+				'func'       => [$this, '_delete_categories'],
210
+				'capability' => 'ee_delete_event_category',
211
+				'noheader'   => true,
212
+			],
213
+			'delete_category'               => [
214
+				'func'       => [$this, '_delete_categories'],
215
+				'capability' => 'ee_delete_event_category',
216
+				'noheader'   => true,
217
+			],
218
+			'insert_category'               => [
219
+				'func'       => [$this, '_insert_or_update_category'],
220
+				'args'       => ['new_category' => true],
221
+				'capability' => 'ee_edit_event_category',
222
+				'noheader'   => true,
223
+			],
224
+			'update_category'               => [
225
+				'func'       => [$this, '_insert_or_update_category'],
226
+				'args'       => ['new_category' => false],
227
+				'capability' => 'ee_edit_event_category',
228
+				'noheader'   => true,
229
+			],
230
+			'category_list'                 => [
231
+				'func'       => [$this, '_category_list_table'],
232
+				'capability' => 'ee_manage_event_categories',
233
+			],
234
+			'preview_deletion'              => [
235
+				'func'       => [$this, 'previewDeletion'],
236
+				'capability' => 'ee_delete_events',
237
+			],
238
+			'confirm_deletion'              => [
239
+				'func'       => [$this, 'confirmDeletion'],
240
+				'capability' => 'ee_delete_events',
241
+				'noheader'   => true,
242
+			],
243
+		];
244
+	}
245
+
246
+
247
+	/**
248
+	 * Set the _page_config property for this admin page group.
249
+	 */
250
+	protected function _set_page_config()
251
+	{
252
+		$post_id            = $this->request->getRequestParam('post', 0, DataType::INT);
253
+		$EVT_CAT_ID         = $this->request->getRequestParam('EVT_CAT_ID', 0, DataType::INT);
254
+		$this->_page_config = [
255
+			'default'                => [
256
+				'nav'           => [
257
+					'label' => esc_html__('Overview', 'event_espresso'),
258
+					'icon'  => 'dashicons-list-view',
259
+					'order' => 10,
260
+				],
261
+				'list_table'    => 'Events_Admin_List_Table',
262
+				'help_tabs'     => [
263
+					'events_overview_help_tab'                       => [
264
+						'title'    => esc_html__('Events Overview', 'event_espresso'),
265
+						'filename' => 'events_overview',
266
+					],
267
+					'events_overview_table_column_headings_help_tab' => [
268
+						'title'    => esc_html__('Events Overview Table Column Headings', 'event_espresso'),
269
+						'filename' => 'events_overview_table_column_headings',
270
+					],
271
+					'events_overview_filters_help_tab'               => [
272
+						'title'    => esc_html__('Events Overview Filters', 'event_espresso'),
273
+						'filename' => 'events_overview_filters',
274
+					],
275
+					'events_overview_view_help_tab'                  => [
276
+						'title'    => esc_html__('Events Overview Views', 'event_espresso'),
277
+						'filename' => 'events_overview_views',
278
+					],
279
+					'events_overview_other_help_tab'                 => [
280
+						'title'    => esc_html__('Events Overview Other', 'event_espresso'),
281
+						'filename' => 'events_overview_other',
282
+					],
283
+				],
284
+				'require_nonce' => false,
285
+			],
286
+			'create_new'             => [
287
+				'nav'           => [
288
+					'label'      => esc_html__('Add New Event', 'event_espresso'),
289
+					'icon'       => 'dashicons-plus-alt',
290
+					'order'      => 15,
291
+					'persistent' => false,
292
+				],
293
+				'metaboxes'     => ['_register_event_editor_meta_boxes'],
294
+				'help_tabs'     => [
295
+					'event_editor_help_tab'                            => [
296
+						'title'    => esc_html__('Event Editor', 'event_espresso'),
297
+						'filename' => 'event_editor',
298
+					],
299
+					'event_editor_title_richtexteditor_help_tab'       => [
300
+						'title'    => esc_html__('Event Title & Rich Text Editor', 'event_espresso'),
301
+						'filename' => 'event_editor_title_richtexteditor',
302
+					],
303
+					'event_editor_venue_details_help_tab'              => [
304
+						'title'    => esc_html__('Event Venue Details', 'event_espresso'),
305
+						'filename' => 'event_editor_venue_details',
306
+					],
307
+					'event_editor_event_datetimes_help_tab'            => [
308
+						'title'    => esc_html__('Event Datetimes', 'event_espresso'),
309
+						'filename' => 'event_editor_event_datetimes',
310
+					],
311
+					'event_editor_event_tickets_help_tab'              => [
312
+						'title'    => esc_html__('Event Tickets', 'event_espresso'),
313
+						'filename' => 'event_editor_event_tickets',
314
+					],
315
+					'event_editor_event_registration_options_help_tab' => [
316
+						'title'    => esc_html__('Event Registration Options', 'event_espresso'),
317
+						'filename' => 'event_editor_event_registration_options',
318
+					],
319
+					'event_editor_tags_categories_help_tab'            => [
320
+						'title'    => esc_html__('Event Tags & Categories', 'event_espresso'),
321
+						'filename' => 'event_editor_tags_categories',
322
+					],
323
+					'event_editor_questions_registrants_help_tab'      => [
324
+						'title'    => esc_html__('Questions for Registrants', 'event_espresso'),
325
+						'filename' => 'event_editor_questions_registrants',
326
+					],
327
+					'event_editor_save_new_event_help_tab'             => [
328
+						'title'    => esc_html__('Save New Event', 'event_espresso'),
329
+						'filename' => 'event_editor_save_new_event',
330
+					],
331
+					'event_editor_other_help_tab'                      => [
332
+						'title'    => esc_html__('Event Other', 'event_espresso'),
333
+						'filename' => 'event_editor_other',
334
+					],
335
+				],
336
+				'qtips'         => ['EE_Event_Editor_Decaf_Tips'],
337
+				'require_nonce' => false,
338
+			],
339
+			'edit'                   => [
340
+				'nav'           => [
341
+					'label'      => esc_html__('Edit Event', 'event_espresso'),
342
+					'icon'       => 'dashicons-edit',
343
+					'order'      => 15,
344
+					'persistent' => false,
345
+					'url'        => $post_id
346
+						? EE_Admin_Page::add_query_args_and_nonce(
347
+							['post' => $post_id, 'action' => 'edit'],
348
+							$this->_current_page_view_url
349
+						)
350
+						: $this->_admin_base_url,
351
+				],
352
+				'metaboxes'     => ['_register_event_editor_meta_boxes'],
353
+				'help_tabs'     => [
354
+					'event_editor_help_tab'                            => [
355
+						'title'    => esc_html__('Event Editor', 'event_espresso'),
356
+						'filename' => 'event_editor',
357
+					],
358
+					'event_editor_title_richtexteditor_help_tab'       => [
359
+						'title'    => esc_html__('Event Title & Rich Text Editor', 'event_espresso'),
360
+						'filename' => 'event_editor_title_richtexteditor',
361
+					],
362
+					'event_editor_venue_details_help_tab'              => [
363
+						'title'    => esc_html__('Event Venue Details', 'event_espresso'),
364
+						'filename' => 'event_editor_venue_details',
365
+					],
366
+					'event_editor_event_datetimes_help_tab'            => [
367
+						'title'    => esc_html__('Event Datetimes', 'event_espresso'),
368
+						'filename' => 'event_editor_event_datetimes',
369
+					],
370
+					'event_editor_event_tickets_help_tab'              => [
371
+						'title'    => esc_html__('Event Tickets', 'event_espresso'),
372
+						'filename' => 'event_editor_event_tickets',
373
+					],
374
+					'event_editor_event_registration_options_help_tab' => [
375
+						'title'    => esc_html__('Event Registration Options', 'event_espresso'),
376
+						'filename' => 'event_editor_event_registration_options',
377
+					],
378
+					'event_editor_tags_categories_help_tab'            => [
379
+						'title'    => esc_html__('Event Tags & Categories', 'event_espresso'),
380
+						'filename' => 'event_editor_tags_categories',
381
+					],
382
+					'event_editor_questions_registrants_help_tab'      => [
383
+						'title'    => esc_html__('Questions for Registrants', 'event_espresso'),
384
+						'filename' => 'event_editor_questions_registrants',
385
+					],
386
+					'event_editor_save_new_event_help_tab'             => [
387
+						'title'    => esc_html__('Save New Event', 'event_espresso'),
388
+						'filename' => 'event_editor_save_new_event',
389
+					],
390
+					'event_editor_other_help_tab'                      => [
391
+						'title'    => esc_html__('Event Other', 'event_espresso'),
392
+						'filename' => 'event_editor_other',
393
+					],
394
+				],
395
+				'require_nonce' => false,
396
+			],
397
+			'default_event_settings' => [
398
+				'nav'           => [
399
+					'label' => esc_html__('Default Settings', 'event_espresso'),
400
+					'icon'  => 'dashicons-admin-generic',
401
+					'order' => 40,
402
+				],
403
+				'metaboxes'     => array_merge(['_publish_post_box'], $this->_default_espresso_metaboxes),
404
+				'labels'        => [
405
+					'publishbox' => esc_html__('Update Settings', 'event_espresso'),
406
+				],
407
+				'help_tabs'     => [
408
+					'default_settings_help_tab'        => [
409
+						'title'    => esc_html__('Default Event Settings', 'event_espresso'),
410
+						'filename' => 'events_default_settings',
411
+					],
412
+					'default_settings_status_help_tab' => [
413
+						'title'    => esc_html__('Default Registration Status', 'event_espresso'),
414
+						'filename' => 'events_default_settings_status',
415
+					],
416
+					'default_maximum_tickets_help_tab' => [
417
+						'title'    => esc_html__('Default Maximum Tickets Per Order', 'event_espresso'),
418
+						'filename' => 'events_default_settings_max_tickets',
419
+					],
420
+				],
421
+				'require_nonce' => false,
422
+			],
423
+			// template settings
424
+			'template_settings'      => [
425
+				'nav'           => [
426
+					'label' => esc_html__('Templates', 'event_espresso'),
427
+					'icon'  => 'dashicons-layout',
428
+					'order' => 30,
429
+				],
430
+				'metaboxes'     => $this->_default_espresso_metaboxes,
431
+				'help_tabs'     => [
432
+					'general_settings_templates_help_tab' => [
433
+						'title'    => esc_html__('Templates', 'event_espresso'),
434
+						'filename' => 'general_settings_templates',
435
+					],
436
+				],
437
+				'require_nonce' => false,
438
+			],
439
+			// event category stuff
440
+			'add_category'           => [
441
+				'nav'           => [
442
+					'label'      => esc_html__('Add Category', 'event_espresso'),
443
+					'icon'       => 'dashicons-plus-alt',
444
+					'order'      => 25,
445
+					'persistent' => false,
446
+				],
447
+				'help_tabs'     => [
448
+					'add_category_help_tab' => [
449
+						'title'    => esc_html__('Add New Event Category', 'event_espresso'),
450
+						'filename' => 'events_add_category',
451
+					],
452
+				],
453
+				'metaboxes'     => ['_publish_post_box'],
454
+				'require_nonce' => false,
455
+			],
456
+			'edit_category'          => [
457
+				'nav'           => [
458
+					'label'      => esc_html__('Edit Category', 'event_espresso'),
459
+					'icon'       => 'dashicons-edit',
460
+					'order'      => 25,
461
+					'persistent' => false,
462
+					'url'        => $EVT_CAT_ID
463
+						? add_query_arg(
464
+							['EVT_CAT_ID' => $EVT_CAT_ID],
465
+							$this->_current_page_view_url
466
+						)
467
+						: $this->_admin_base_url,
468
+				],
469
+				'help_tabs'     => [
470
+					'edit_category_help_tab' => [
471
+						'title'    => esc_html__('Edit Event Category', 'event_espresso'),
472
+						'filename' => 'events_edit_category',
473
+					],
474
+				],
475
+				'metaboxes'     => ['_publish_post_box'],
476
+				'require_nonce' => false,
477
+			],
478
+			'category_list'          => [
479
+				'nav'           => [
480
+					'label' => esc_html__('Categories', 'event_espresso'),
481
+					'icon'  => 'dashicons-networking',
482
+					'order' => 20,
483
+				],
484
+				'list_table'    => 'Event_Categories_Admin_List_Table',
485
+				'help_tabs'     => [
486
+					'events_categories_help_tab'                       => [
487
+						'title'    => esc_html__('Event Categories', 'event_espresso'),
488
+						'filename' => 'events_categories',
489
+					],
490
+					'events_categories_table_column_headings_help_tab' => [
491
+						'title'    => esc_html__('Event Categories Table Column Headings', 'event_espresso'),
492
+						'filename' => 'events_categories_table_column_headings',
493
+					],
494
+					'events_categories_view_help_tab'                  => [
495
+						'title'    => esc_html__('Event Categories Views', 'event_espresso'),
496
+						'filename' => 'events_categories_views',
497
+					],
498
+					'events_categories_other_help_tab'                 => [
499
+						'title'    => esc_html__('Event Categories Other', 'event_espresso'),
500
+						'filename' => 'events_categories_other',
501
+					],
502
+				],
503
+				'metaboxes'     => $this->_default_espresso_metaboxes,
504
+				'require_nonce' => false,
505
+			],
506
+			'preview_deletion'       => [
507
+				'nav'           => [
508
+					'label'      => esc_html__('Preview Deletion', 'event_espresso'),
509
+					'icon'       => 'dashicons-remove',
510
+					'order'      => 15,
511
+					'persistent' => false,
512
+					'url'        => '',
513
+				],
514
+				'require_nonce' => false,
515
+			],
516
+		];
517
+	}
518
+
519
+
520
+	/**
521
+	 * Used to register any global screen options if necessary for every route in this admin page group.
522
+	 */
523
+	protected function _add_screen_options()
524
+	{
525
+	}
526
+
527
+
528
+	/**
529
+	 * Implementing the screen options for the 'default' route.
530
+	 *
531
+	 * @throws InvalidArgumentException
532
+	 * @throws InvalidDataTypeException
533
+	 * @throws InvalidInterfaceException
534
+	 */
535
+	protected function _add_screen_options_default()
536
+	{
537
+		$this->_per_page_screen_option();
538
+	}
539
+
540
+
541
+	/**
542
+	 * Implementing screen options for the category list route.
543
+	 *
544
+	 * @throws InvalidArgumentException
545
+	 * @throws InvalidDataTypeException
546
+	 * @throws InvalidInterfaceException
547
+	 */
548
+	protected function _add_screen_options_category_list()
549
+	{
550
+		$page_title              = $this->_admin_page_title;
551
+		$this->_admin_page_title = esc_html__('Categories', 'event_espresso');
552
+		$this->_per_page_screen_option();
553
+		$this->_admin_page_title = $page_title;
554
+	}
555
+
556
+
557
+	/**
558
+	 * Used to register any global feature pointers for the admin page group.
559
+	 */
560
+	protected function _add_feature_pointers()
561
+	{
562
+	}
563
+
564
+
565
+	/**
566
+	 * Registers and enqueues any global scripts and styles for the entire admin page group.
567
+	 */
568
+	public function load_scripts_styles()
569
+	{
570
+		wp_register_style(
571
+			'events-admin-css',
572
+			EVENTS_ASSETS_URL . 'events-admin-page.css',
573
+			[],
574
+			EVENT_ESPRESSO_VERSION
575
+		);
576
+		wp_register_style(
577
+			'ee-cat-admin',
578
+			EVENTS_ASSETS_URL . 'ee-cat-admin.css',
579
+			[],
580
+			EVENT_ESPRESSO_VERSION
581
+		);
582
+		wp_enqueue_style('events-admin-css');
583
+		wp_enqueue_style('ee-cat-admin');
584
+		// scripts
585
+		wp_register_script(
586
+			'event_editor_js',
587
+			EVENTS_ASSETS_URL . 'event_editor.js',
588
+			['ee_admin_js', 'jquery-ui-slider', 'jquery-ui-timepicker-addon'],
589
+			EVENT_ESPRESSO_VERSION,
590
+			true
591
+		);
592
+	}
593
+
594
+
595
+	/**
596
+	 * Enqueuing scripts and styles specific to this view
597
+	 */
598
+	public function load_scripts_styles_create_new()
599
+	{
600
+		$this->load_scripts_styles_edit();
601
+	}
602
+
603
+
604
+	/**
605
+	 * Enqueuing scripts and styles specific to this view
606
+	 */
607
+	public function load_scripts_styles_edit()
608
+	{
609
+		// styles
610
+		wp_enqueue_style('espresso-ui-theme');
611
+		wp_register_style(
612
+			'event-editor-css',
613
+			EVENTS_ASSETS_URL . 'event-editor.css',
614
+			['ee-admin-css'],
615
+			EVENT_ESPRESSO_VERSION
616
+		);
617
+		wp_enqueue_style('event-editor-css');
618
+		// scripts
619
+		if (! $this->admin_config->useAdvancedEditor()) {
620
+			wp_register_script(
621
+				'event-datetime-metabox',
622
+				EVENTS_ASSETS_URL . 'event-datetime-metabox.js',
623
+				['event_editor_js', 'ee-datepicker'],
624
+				EVENT_ESPRESSO_VERSION
625
+			);
626
+			wp_enqueue_script('event-datetime-metabox');
627
+		}
628
+	}
629
+
630
+
631
+	/**
632
+	 * Populating the _views property for the category list table view.
633
+	 */
634
+	protected function _set_list_table_views_category_list()
635
+	{
636
+		$this->_views = [
637
+			'all' => [
638
+				'slug'        => 'all',
639
+				'label'       => esc_html__('All', 'event_espresso'),
640
+				'count'       => 0,
641
+				'bulk_action' => [
642
+					'delete_categories' => esc_html__('Delete Permanently', 'event_espresso'),
643
+				],
644
+			],
645
+		];
646
+	}
647
+
648
+
649
+	/**
650
+	 * For adding anything that fires on the admin_init hook for any route within this admin page group.
651
+	 */
652
+	public function admin_init()
653
+	{
654
+		EE_Registry::$i18n_js_strings['image_confirm'] = esc_html__(
655
+			'Do you really want to delete this image? Please remember to update your event to complete the removal.',
656
+			'event_espresso'
657
+		);
658
+	}
659
+
660
+
661
+	/**
662
+	 * For adding anything that should be triggered on the admin_notices hook for any route within this admin page
663
+	 * group.
664
+	 */
665
+	public function admin_notices()
666
+	{
667
+	}
668
+
669
+
670
+	/**
671
+	 * For adding anything that should be triggered on the `admin_print_footer_scripts` hook for any route within
672
+	 * this admin page group.
673
+	 */
674
+	public function admin_footer_scripts()
675
+	{
676
+	}
677
+
678
+
679
+	/**
680
+	 * Call this function to verify if an event is public and has tickets for sale.  If it does, then we need to show a
681
+	 * warning (via EE_Error::add_error());
682
+	 *
683
+	 * @param EE_Event|null $event Event object
684
+	 * @param string        $req_type
685
+	 * @return void
686
+	 * @throws EE_Error
687
+	 * @throws ReflectionException
688
+	 */
689
+	public function verify_event_edit(?EE_Base_Class $event = null, string $req_type = '')
690
+	{
691
+		// don't need to do this when processing
692
+		if (! empty($req_type)) {
693
+			return;
694
+		}
695
+		// no event?
696
+		if (! $event instanceof EE_Event) {
697
+			$event = $this->_cpt_model_obj;
698
+		}
699
+		// STILL no event?
700
+		if (! $event instanceof EE_Event) {
701
+			return;
702
+		}
703
+		// don't need to keep calling this
704
+		remove_action(
705
+			'AHEE__EE_Admin_Page_CPT__set_model_object__after_set_object',
706
+			[$this, 'verify_event_edit']
707
+		);
708
+		$orig_status = $event->status();
709
+		// first check if event is active.
710
+		if (
711
+			$orig_status === EEM_Event::cancelled
712
+			|| $orig_status === EEM_Event::postponed
713
+			|| $event->is_expired()
714
+			|| $event->is_inactive()
715
+		) {
716
+			return;
717
+		}
718
+		// made it here so it IS active... next check that any of the tickets are sold.
719
+		if ($event->is_sold_out(true)) {
720
+			if ($orig_status !== EEM_Event::sold_out && $event->status() !== $orig_status) {
721
+				EE_Error::add_attention(
722
+					sprintf(
723
+						esc_html__(
724
+							'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.',
725
+							'event_espresso'
726
+						),
727
+						EEH_Template::pretty_status(EEM_Event::sold_out, false, 'sentence')
728
+					)
729
+				);
730
+			}
731
+			return;
732
+		}
733
+		if ($orig_status === EEM_Event::sold_out) {
734
+			EE_Error::add_attention(
735
+				sprintf(
736
+					esc_html__(
737
+						'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.',
738
+						'event_espresso'
739
+					),
740
+					EEH_Template::pretty_status($event->status(), false, 'sentence')
741
+				)
742
+			);
743
+		}
744
+		// now we need to determine if the event has any tickets on sale.  If not then we dont' show the error
745
+		if (! $event->tickets_on_sale()) {
746
+			return;
747
+		}
748
+		// made it here so show warning
749
+		$this->_edit_event_warning();
750
+	}
751
+
752
+
753
+	/**
754
+	 * This is the text used for when an event is being edited that is public and has tickets for sale.
755
+	 * When needed, hook this into a EE_Error::add_error() notice.
756
+	 *
757
+	 * @access protected
758
+	 * @return void
759
+	 */
760
+	protected function _edit_event_warning()
761
+	{
762
+		// we don't want to add warnings during these requests
763
+		if ($this->request->getRequestParam('action') === 'editpost') {
764
+			return;
765
+		}
766
+		EE_Error::add_attention(
767
+			sprintf(
768
+				esc_html__(
769
+					'Your event is open for registration. Making changes may disrupt any transactions in progress. %sLearn more%s',
770
+					'event_espresso'
771
+				),
772
+				'<a class="espresso-help-tab-lnk ee-help-tab-link">',
773
+				'</a>'
774
+			)
775
+		);
776
+	}
777
+
778
+
779
+	/**
780
+	 * When a user is creating a new event, notify them if they haven't set their timezone.
781
+	 * Otherwise, do the normal logic
782
+	 *
783
+	 * @return void
784
+	 * @throws EE_Error
785
+	 * @throws InvalidArgumentException
786
+	 * @throws InvalidDataTypeException
787
+	 * @throws InvalidInterfaceException
788
+	 * @throws ReflectionException
789
+	 */
790
+	protected function _create_new_cpt_item()
791
+	{
792
+		$has_timezone_string = get_option('timezone_string');
793
+		// only nag them about setting their timezone if it's their first event, and they haven't already done it
794
+		if (! $has_timezone_string && ! EEM_Event::instance()->exists([])) {
795
+			EE_Error::add_attention(
796
+				sprintf(
797
+					esc_html__(
798
+						'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',
799
+						'event_espresso'
800
+					),
801
+					'<br>',
802
+					'<select id="timezone_string" name="timezone_string" aria-describedby="timezone-description">'
803
+					. EEH_DTT_Helper::wp_timezone_choice('', EEH_DTT_Helper::get_user_locale())
804
+					. '</select>',
805
+					'<button class="button button--secondary timezone-submit">',
806
+					'</button><span class="spinner"></span>'
807
+				),
808
+				__FILE__,
809
+				__FUNCTION__,
810
+				__LINE__
811
+			);
812
+		}
813
+		parent::_create_new_cpt_item();
814
+	}
815
+
816
+
817
+	/**
818
+	 * Sets the _views property for the default route in this admin page group.
819
+	 */
820
+	protected function _set_list_table_views_default()
821
+	{
822
+		$this->_views = [
823
+			'all'   => [
824
+				'slug'        => 'all',
825
+				'label'       => esc_html__('View All Events', 'event_espresso'),
826
+				'count'       => 0,
827
+				'bulk_action' => [
828
+					'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
829
+				],
830
+			],
831
+			'draft' => [
832
+				'slug'        => 'draft',
833
+				'label'       => esc_html__('Draft', 'event_espresso'),
834
+				'count'       => 0,
835
+				'bulk_action' => [
836
+					'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
837
+				],
838
+			],
839
+		];
840
+		if ($this->capabilities->current_user_can('ee_delete_events', 'espresso_events_trash_events')) {
841
+			$this->_views['trash'] = [
842
+				'slug'        => 'trash',
843
+				'label'       => esc_html__('Trash', 'event_espresso'),
844
+				'count'       => 0,
845
+				'bulk_action' => [
846
+					'restore_events' => esc_html__('Restore From Trash', 'event_espresso'),
847
+					'delete_events'  => esc_html__('Delete Permanently', 'event_espresso'),
848
+				],
849
+			];
850
+		}
851
+	}
852
+
853
+
854
+	/**
855
+	 * Provides the legend item array for the default list table view.
856
+	 *
857
+	 * @return array
858
+	 * @throws EE_Error
859
+	 * @throws EE_Error
860
+	 */
861
+	protected function _event_legend_items(): array
862
+	{
863
+		$items    = [
864
+			'view_details'   => [
865
+				'class' => 'dashicons dashicons-visibility',
866
+				'desc'  => esc_html__('View Event', 'event_espresso'),
867
+			],
868
+			'edit_event'     => [
869
+				'class' => 'dashicons dashicons-calendar-alt',
870
+				'desc'  => esc_html__('Edit Event Details', 'event_espresso'),
871
+			],
872
+			'view_attendees' => [
873
+				'class' => 'dashicons dashicons-groups',
874
+				'desc'  => esc_html__('View Registrations for Event', 'event_espresso'),
875
+			],
876
+		];
877
+		$items    = apply_filters('FHEE__Events_Admin_Page___event_legend_items__items', $items);
878
+		$statuses = [
879
+			'sold_out_status'  => [
880
+				'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::sold_out,
881
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::sold_out, false, 'sentence'),
882
+			],
883
+			'active_status'    => [
884
+				'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::active,
885
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::active, false, 'sentence'),
886
+			],
887
+			'upcoming_status'  => [
888
+				'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::upcoming,
889
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::upcoming, false, 'sentence'),
890
+			],
891
+			'postponed_status' => [
892
+				'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::postponed,
893
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::postponed, false, 'sentence'),
894
+			],
895
+			'cancelled_status' => [
896
+				'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::cancelled,
897
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::cancelled, false, 'sentence'),
898
+			],
899
+			'expired_status'   => [
900
+				'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::expired,
901
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::expired, false, 'sentence'),
902
+			],
903
+			'inactive_status'  => [
904
+				'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::inactive,
905
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::inactive, false, 'sentence'),
906
+			],
907
+		];
908
+		$statuses = apply_filters('FHEE__Events_Admin_Page__event_legend_items__statuses', $statuses);
909
+		return array_merge($items, $statuses);
910
+	}
911
+
912
+
913
+	/**
914
+	 * @return EEM_Event
915
+	 * @throws EE_Error
916
+	 * @throws InvalidArgumentException
917
+	 * @throws InvalidDataTypeException
918
+	 * @throws InvalidInterfaceException
919
+	 * @throws ReflectionException
920
+	 */
921
+	private function _event_model(): EEM_Event
922
+	{
923
+		if (! $this->_event_model instanceof EEM_Event) {
924
+			$this->_event_model = EE_Registry::instance()->load_model('Event');
925
+		}
926
+		return $this->_event_model;
927
+	}
928
+
929
+
930
+	/**
931
+	 * Adds extra buttons to the WP CPT permalink field row.
932
+	 * Method is called from parent and is hooked into the wp 'get_sample_permalink_html' filter.
933
+	 *
934
+	 * @param string      $return    the current html
935
+	 * @param int         $id        the post id for the page
936
+	 * @param string|null $new_title What the title is
937
+	 * @param string|null $new_slug  what the slug is
938
+	 * @return string            The new html string for the permalink area
939
+	 * @deprecated 5.0.0.p
940
+	 * @see        TicketSelectorShortcodeButton::addButton
941
+	 */
942
+	public function extra_permalink_field_buttons(
943
+		string $return,
944
+		int $id,
945
+		?string $new_title,
946
+		?string $new_slug
947
+	): string {
948
+		return TicketSelectorShortcodeButton::addButton($return, $id, $new_title, $new_slug);
949
+	}
950
+
951
+
952
+	/**
953
+	 * _events_overview_list_table
954
+	 * This contains the logic for showing the events_overview list
955
+	 *
956
+	 * @access protected
957
+	 * @return void
958
+	 * @throws DomainException
959
+	 * @throws EE_Error
960
+	 * @throws InvalidArgumentException
961
+	 * @throws InvalidDataTypeException
962
+	 * @throws InvalidInterfaceException
963
+	 */
964
+	protected function _events_overview_list_table()
965
+	{
966
+		$after_list_table = [];
967
+		$links_html       = EEH_HTML::div('', '', 'ee-admin-section ee-layout-stack');
968
+		$links_html       .= EEH_HTML::h3(esc_html__('Links', 'event_espresso'));
969
+		$links_html       .= EEH_HTML::div(
970
+			EEH_Template::get_button_or_link(
971
+				get_post_type_archive_link('espresso_events'),
972
+				esc_html__('View Event Archive Page', 'event_espresso'),
973
+				'button button--small button--secondary'
974
+			),
975
+			'',
976
+			'ee-admin-button-row ee-admin-button-row--align-start'
977
+		);
978
+		$links_html       .= EEH_HTML::divx();
979
+
980
+		$after_list_table['view_event_list_button'] = $links_html;
981
+
982
+		$after_list_table['legend'] = $this->_display_legend($this->_event_legend_items());
983
+		$this->_admin_page_title    .= ' ' . $this->get_action_link_or_button(
984
+				'create_new',
985
+				'add',
986
+				[],
987
+				'add-new-h2'
988
+			);
989
+
990
+		$this->_template_args['after_list_table'] = array_merge(
991
+			(array) $this->_template_args['after_list_table'],
992
+			$after_list_table
993
+		);
994
+		$this->display_admin_list_table_page_with_no_sidebar();
995
+	}
996
+
997
+
998
+	/**
999
+	 * this allows for extra misc actions in the default WP publish box
1000
+	 *
1001
+	 * @return void
1002
+	 * @throws DomainException
1003
+	 * @throws EE_Error
1004
+	 * @throws InvalidArgumentException
1005
+	 * @throws InvalidDataTypeException
1006
+	 * @throws InvalidInterfaceException
1007
+	 * @throws ReflectionException
1008
+	 */
1009
+	public function extra_misc_actions_publish_box()
1010
+	{
1011
+		$this->_generate_publish_box_extra_content();
1012
+	}
1013
+
1014
+
1015
+	/**
1016
+	 * This is hooked into the WordPress do_action('save_post') hook and runs after the custom post type has been
1017
+	 * saved.
1018
+	 * Typically you would use this to save any additional data.
1019
+	 * Keep in mind also that "save_post" runs on EVERY post update to the database.
1020
+	 * ALSO very important.  When a post transitions from scheduled to published,
1021
+	 * the save_post action is fired but you will NOT have any _POST data containing any extra info you may have from
1022
+	 * other meta saves. So MAKE sure that you handle this accordingly.
1023
+	 *
1024
+	 * @access protected
1025
+	 * @abstract
1026
+	 * @param string  $post_id The ID of the cpt that was saved (so you can link relationally)
1027
+	 * @param WP_Post $post    The post object of the cpt that was saved.
1028
+	 * @return void
1029
+	 * @throws EE_Error
1030
+	 * @throws InvalidArgumentException
1031
+	 * @throws InvalidDataTypeException
1032
+	 * @throws InvalidInterfaceException
1033
+	 * @throws ReflectionException
1034
+	 */
1035
+	protected function _insert_update_cpt_item($post_id, $post)
1036
+	{
1037
+		if ($post instanceof WP_Post && $post->post_type !== 'espresso_events') {
1038
+			// get out we're not processing an event save.
1039
+			return;
1040
+		}
1041
+		$event_values = [
1042
+			'EVT_member_only'     => $this->request->getRequestParam('member_only', false, DataType::BOOL),
1043
+			'EVT_allow_overflow'  => $this->request->getRequestParam('EVT_allow_overflow', false, DataType::BOOL),
1044
+			'EVT_timezone_string' => $this->request->getRequestParam('timezone_string'),
1045
+		];
1046
+		// check if the new EDTR reg options meta box is being used, and if so, don't run updates for legacy version
1047
+		if (! $this->admin_config->useAdvancedEditor() || ! $this->feature->allowed('use_reg_options_meta_box')) {
1048
+			$event_values['EVT_display_ticket_selector']     = $this->request->getRequestParam(
1049
+				'display_ticket_selector',
1050
+				false,
1051
+				'bool'
1052
+			);
1053
+			$event_values['EVT_additional_limit']            = min(
1054
+				apply_filters('FHEE__EE_Events_Admin__insert_update_cpt_item__EVT_additional_limit_max', 255),
1055
+				$this->request->getRequestParam(
1056
+					'additional_limit',
1057
+					EEM_Event::get_default_additional_limit(),
1058
+					'int'
1059
+				)
1060
+			);
1061
+			$event_values['EVT_default_registration_status'] = $this->request->getRequestParam(
1062
+				'EVT_default_registration_status',
1063
+				EE_Registry::instance()->CFG->registration->default_STS_ID
1064
+			);
1065
+
1066
+			$event_values['EVT_external_URL'] = $this->request->getRequestParam('externalURL');
1067
+			$event_values['EVT_phone']        = $this->request->getRequestParam('event_phone');
1068
+			$event_values['EVT_display_desc'] = $this->request->getRequestParam('display_desc', false, DataType::BOOL);
1069
+		} elseif ($post instanceof WP_Post) {
1070
+			$event_values['EVT_name'] = $post->post_title;
1071
+			$event_values['EVT_desc'] = $post->post_content;
1072
+		}
1073
+		// update event
1074
+		$success = $this->_event_model()->update_by_ID($event_values, $post_id);
1075
+		// get event_object for other metaboxes...
1076
+		// though it would seem to make sense to just use $this->_event_model()->get_one_by_ID( $post_id )..
1077
+		// i have to setup where conditions to override the filters in the model
1078
+		// that filter out auto-draft and inherit statuses so we GET the inherit id!
1079
+		/** @var EE_Event $event */
1080
+		$event = $this->_event_model()->get_one(
1081
+			[
1082
+				[
1083
+					$this->_event_model()->primary_key_name() => $post_id,
1084
+					'OR'                                      => [
1085
+						'status'   => $post->post_status,
1086
+						// if trying to "Publish" a sold out event, it's status will get switched back to "sold_out" in the db,
1087
+						// but the returned object here has a status of "publish", so use the original post status as well
1088
+						'status*1' => $this->request->getRequestParam('original_post_status'),
1089
+					],
1090
+				],
1091
+			]
1092
+		);
1093
+
1094
+		// the following are default callbacks for event attachment updates
1095
+		// that can be overridden by caffeinated functionality and/or addons.
1096
+		$event_update_callbacks = [];
1097
+		if (! $this->admin_config->useAdvancedEditor()) {
1098
+			$event_update_callbacks['_default_venue_update']   = [$this, '_default_venue_update'];
1099
+			$event_update_callbacks['_default_tickets_update'] = [$this, '_default_tickets_update'];
1100
+		}
1101
+		$event_update_callbacks = apply_filters(
1102
+			'FHEE__Events_Admin_Page___insert_update_cpt_item__event_update_callbacks',
1103
+			$event_update_callbacks
1104
+		);
1105
+
1106
+		$att_success = true;
1107
+		foreach ($event_update_callbacks as $e_callback) {
1108
+			$_success = is_callable($e_callback)
1109
+				? $e_callback($event, $this->request->requestParams())
1110
+				: false;
1111
+			// if ANY of these updates fail then we want the appropriate global error message
1112
+			$att_success = $_success !== false ? $att_success : false;
1113
+		}
1114
+		// any errors?
1115
+		if ($success && $att_success === false) {
1116
+			EE_Error::add_error(
1117
+				esc_html__(
1118
+					'Event Details saved successfully but something went wrong with saving attachments.',
1119
+					'event_espresso'
1120
+				),
1121
+				__FILE__,
1122
+				__FUNCTION__,
1123
+				__LINE__
1124
+			);
1125
+		} elseif ($success === false) {
1126
+			EE_Error::add_error(
1127
+				esc_html__('Event Details did not save successfully.', 'event_espresso'),
1128
+				__FILE__,
1129
+				__FUNCTION__,
1130
+				__LINE__
1131
+			);
1132
+		}
1133
+	}
1134
+
1135
+
1136
+	/**
1137
+	 * @param int $post_id
1138
+	 * @param int $revision_id
1139
+	 * @throws EE_Error
1140
+	 * @throws EE_Error
1141
+	 * @throws ReflectionException
1142
+	 * @see parent::restore_item()
1143
+	 */
1144
+	protected function _restore_cpt_item(int $post_id, int $revision_id)
1145
+	{
1146
+		// copy existing event meta to new post
1147
+		$post_evt = $this->_event_model()->get_one_by_ID($post_id);
1148
+		if ($post_evt instanceof EE_Event) {
1149
+			// meta revision restore
1150
+			$post_evt->restore_revision($revision_id);
1151
+			// related objs restore
1152
+			$post_evt->restore_revision($revision_id, ['Venue', 'Datetime', 'Price']);
1153
+		}
1154
+	}
1155
+
1156
+
1157
+	/**
1158
+	 * Attach the venue to the Event
1159
+	 *
1160
+	 * @param EE_Event $event Event Object to add the venue to
1161
+	 * @param array    $data  The request data from the form
1162
+	 * @return bool           Success or fail.
1163
+	 * @throws EE_Error
1164
+	 * @throws ReflectionException
1165
+	 */
1166
+	protected function _default_venue_update(EE_Event $event, array $data): bool
1167
+	{
1168
+		require_once(EE_MODELS . 'EEM_Venue.model.php');
1169
+		$venue_model = EE_Registry::instance()->load_model('Venue');
1170
+		$venue_id    = ! empty($data['venue_id']) ? $data['venue_id'] : null;
1171
+		// very important.  If we don't have a venue name...
1172
+		// then we'll get out because not necessary to create empty venue
1173
+		if (empty($data['venue_title'])) {
1174
+			return false;
1175
+		}
1176
+		$venue_array = [
1177
+			'VNU_wp_user'         => $event->get('EVT_wp_user'),
1178
+			'VNU_name'            => $data['venue_title'],
1179
+			'VNU_desc'            => ! empty($data['venue_description']) ? $data['venue_description'] : null,
1180
+			'VNU_identifier'      => ! empty($data['venue_identifier']) ? $data['venue_identifier'] : null,
1181
+			'VNU_short_desc'      => ! empty($data['venue_short_description'])
1182
+				? $data['venue_short_description']
1183
+				: null,
1184
+			'VNU_address'         => ! empty($data['address']) ? $data['address'] : null,
1185
+			'VNU_address2'        => ! empty($data['address2']) ? $data['address2'] : null,
1186
+			'VNU_city'            => ! empty($data['city']) ? $data['city'] : null,
1187
+			'STA_ID'              => ! empty($data['state']) ? $data['state'] : null,
1188
+			'CNT_ISO'             => ! empty($data['countries']) ? $data['countries'] : null,
1189
+			'VNU_zip'             => ! empty($data['zip']) ? $data['zip'] : null,
1190
+			'VNU_phone'           => ! empty($data['venue_phone']) ? $data['venue_phone'] : null,
1191
+			'VNU_capacity'        => ! empty($data['venue_capacity']) ? $data['venue_capacity'] : null,
1192
+			'VNU_url'             => ! empty($data['venue_url']) ? $data['venue_url'] : null,
1193
+			'VNU_virtual_phone'   => ! empty($data['virtual_phone']) ? $data['virtual_phone'] : null,
1194
+			'VNU_virtual_url'     => ! empty($data['virtual_url']) ? $data['virtual_url'] : null,
1195
+			'VNU_enable_for_gmap' => isset($data['enable_for_gmap']) ? 1 : 0,
1196
+			'status'              => 'publish',
1197
+		];
1198
+		// if we've got the venue_id then we're just updating the existing venue so let's do that and then get out.
1199
+		if (! empty($venue_id)) {
1200
+			$update_where  = [$venue_model->primary_key_name() => $venue_id];
1201
+			$rows_affected = $venue_model->update($venue_array, [$update_where]);
1202
+			// we've gotta make sure that the venue is always attached to a revision..
1203
+			// add_relation_to should take care of making sure that the relation is already present.
1204
+			$event->_add_relation_to($venue_id, 'Venue');
1205
+			return $rows_affected > 0;
1206
+		}
1207
+		// we insert the venue
1208
+		$venue_id = $venue_model->insert($venue_array);
1209
+		$event->_add_relation_to($venue_id, 'Venue');
1210
+		return ! empty($venue_id);
1211
+		// when we have the ancestor come in it's already been handled by the revision save.
1212
+	}
1213
+
1214
+
1215
+	/**
1216
+	 * Handles saving everything related to Tickets (datetimes, tickets, prices)
1217
+	 *
1218
+	 * @param EE_Event $event The Event object we're attaching data to
1219
+	 * @param array    $data  The request data from the form
1220
+	 * @return array
1221
+	 * @throws EE_Error
1222
+	 * @throws ReflectionException
1223
+	 * @throws Exception
1224
+	 */
1225
+	protected function _default_tickets_update(EE_Event $event, array $data): array
1226
+	{
1227
+		if ($this->admin_config->useAdvancedEditor()) {
1228
+			return [];
1229
+		}
1230
+		$datetime       = null;
1231
+		$saved_tickets  = [];
1232
+		$event_timezone = $event->get_timezone();
1233
+		$date_formats   = ['Y-m-d', 'h:i a'];
1234
+		foreach ($data['edit_event_datetimes'] as $row => $datetime_data) {
1235
+			// trim all values to ensure any excess whitespace is removed.
1236
+			$datetime_data                = array_map('trim', $datetime_data);
1237
+			$datetime_data['DTT_EVT_end'] = ! empty($datetime_data['DTT_EVT_end'])
1238
+					? $datetime_data['DTT_EVT_end']
1239
+					: $datetime_data['DTT_EVT_start'];
1240
+			$datetime_values              = [
1241
+				'DTT_ID'        => ! empty($datetime_data['DTT_ID']) ? $datetime_data['DTT_ID'] : null,
1242
+				'DTT_EVT_start' => $datetime_data['DTT_EVT_start'],
1243
+				'DTT_EVT_end'   => $datetime_data['DTT_EVT_end'],
1244
+				'DTT_reg_limit' => empty($datetime_data['DTT_reg_limit']) ? EE_INF : $datetime_data['DTT_reg_limit'],
1245
+				'DTT_order'     => $row,
1246
+			];
1247
+			// if we have an id then let's get existing object first and then set the new values.
1248
+			//  Otherwise we instantiate a new object for save.
1249
+			if (! empty($datetime_data['DTT_ID'])) {
1250
+				$datetime = EEM_Datetime::instance($event_timezone)->get_one_by_ID($datetime_data['DTT_ID']);
1251
+				if (! $datetime instanceof EE_Datetime) {
1252
+					throw new RuntimeException(
1253
+						sprintf(
1254
+							esc_html__(
1255
+								'Something went wrong! A valid Datetime could not be retrieved from the database using the supplied ID: %1$d',
1256
+								'event_espresso'
1257
+							),
1258
+							$datetime_data['DTT_ID']
1259
+						)
1260
+					);
1261
+				}
1262
+				$datetime->set_date_format($date_formats[0]);
1263
+				$datetime->set_time_format($date_formats[1]);
1264
+				foreach ($datetime_values as $field => $value) {
1265
+					$datetime->set($field, $value);
1266
+				}
1267
+			} else {
1268
+				$datetime = EE_Datetime::new_instance($datetime_values, $event_timezone, $date_formats);
1269
+			}
1270
+			if (! $datetime instanceof EE_Datetime) {
1271
+				throw new RuntimeException(
1272
+					sprintf(
1273
+						esc_html__(
1274
+							'Something went wrong! A valid Datetime could not be generated or retrieved using the supplied data: %1$s',
1275
+							'event_espresso'
1276
+						),
1277
+						print_r($datetime_values, true)
1278
+					)
1279
+				);
1280
+			}
1281
+			// before going any further make sure our dates are setup correctly
1282
+			// so that the end date is always equal or greater than the start date.
1283
+			if ($datetime->get_raw('DTT_EVT_start') > $datetime->get_raw('DTT_EVT_end')) {
1284
+				$datetime->set('DTT_EVT_end', $datetime->get('DTT_EVT_start'));
1285
+				$datetime = EEH_DTT_Helper::date_time_add($datetime, 'DTT_EVT_end', 'days');
1286
+			}
1287
+			$datetime->save();
1288
+			$event->_add_relation_to($datetime, 'Datetime');
1289
+		}
1290
+		// no datetimes get deleted so we don't do any of that logic here.
1291
+		// update tickets next
1292
+		$old_tickets = isset($data['ticket_IDs']) ? explode(',', $data['ticket_IDs']) : [];
1293
+
1294
+		// set up some default start and end dates in case those are not present in the incoming data
1295
+		$default_start_date = new DateTime('now', new DateTimeZone($event->get_timezone()));
1296
+		$default_start_date = $default_start_date->format($date_formats[0] . ' ' . $date_formats[1]);
1297
+		// use the start date of the first datetime for the end date
1298
+		$first_datetime   = $event->first_datetime();
1299
+		$default_end_date = $first_datetime->start_date_and_time($date_formats[0], $date_formats[1]);
1300
+
1301
+		// now process the incoming data
1302
+		foreach ($data['edit_tickets'] as $row => $ticket_data) {
1303
+			$update_prices = false;
1304
+			$ticket_price  = $data['edit_prices'][ $row ][1]['PRC_amount'] ?? 0;
1305
+			// trim inputs to ensure any excess whitespace is removed.
1306
+			$ticket_data   = array_map('trim', $ticket_data);
1307
+			$ticket_values = [
1308
+				'TKT_ID'          => ! empty($ticket_data['TKT_ID']) ? $ticket_data['TKT_ID'] : null,
1309
+				'TTM_ID'          => ! empty($ticket_data['TTM_ID']) ? $ticket_data['TTM_ID'] : 0,
1310
+				'TKT_name'        => ! empty($ticket_data['TKT_name']) ? $ticket_data['TKT_name'] : '',
1311
+				'TKT_description' => ! empty($ticket_data['TKT_description']) ? $ticket_data['TKT_description'] : '',
1312
+				'TKT_start_date'  => ! empty($ticket_data['TKT_start_date'])
1313
+					? $ticket_data['TKT_start_date']
1314
+					: $default_start_date,
1315
+				'TKT_end_date'    => ! empty($ticket_data['TKT_end_date'])
1316
+					? $ticket_data['TKT_end_date']
1317
+					: $default_end_date,
1318
+				'TKT_qty'         => ! empty($ticket_data['TKT_qty'])
1319
+									 || (isset($ticket_data['TKT_qty']) && (int) $ticket_data['TKT_qty'] === 0)
1320
+					? $ticket_data['TKT_qty']
1321
+					: EE_INF,
1322
+				'TKT_uses'        => ! empty($ticket_data['TKT_uses'])
1323
+									 || (isset($ticket_data['TKT_uses']) && (int) $ticket_data['TKT_uses'] === 0)
1324
+					? $ticket_data['TKT_uses']
1325
+					: EE_INF,
1326
+				'TKT_min'         => ! empty($ticket_data['TKT_min']) ? $ticket_data['TKT_min'] : 0,
1327
+				'TKT_max'         => ! empty($ticket_data['TKT_max']) ? $ticket_data['TKT_max'] : EE_INF,
1328
+				'TKT_order'       => $ticket_data['TKT_order'] ?? $row,
1329
+				'TKT_price'       => $ticket_price,
1330
+				'TKT_row'         => $row,
1331
+			];
1332
+			// if this is a default ticket, then we need to set the TKT_ID to 0 and update accordingly,
1333
+			// which means in turn that the prices will become new prices as well.
1334
+			if (isset($ticket_data['TKT_is_default']) && $ticket_data['TKT_is_default']) {
1335
+				$ticket_values['TKT_ID']         = 0;
1336
+				$ticket_values['TKT_is_default'] = 0;
1337
+				$update_prices                   = true;
1338
+			}
1339
+			// if we have a TKT_ID then we need to get that existing TKT_obj and update it
1340
+			// we actually do our saves ahead of adding any relations because its entirely possible that this
1341
+			// ticket didn't get removed or added to any datetime in the session but DID have it's items modified.
1342
+			// keep in mind that if the ticket has been sold (and we have changed pricing information),
1343
+			// then we won't be updating the tkt but instead a new tkt will be created and the old one archived.
1344
+			if (! empty($ticket_data['TKT_ID'])) {
1345
+				$existing_ticket = EEM_Ticket::instance($event_timezone)->get_one_by_ID($ticket_data['TKT_ID']);
1346
+				if (! $existing_ticket instanceof EE_Ticket) {
1347
+					throw new RuntimeException(
1348
+						sprintf(
1349
+							esc_html__(
1350
+								'Something went wrong! A valid Ticket could not be retrieved from the database using the supplied ID: %1$d',
1351
+								'event_espresso'
1352
+							),
1353
+							$ticket_data['TKT_ID']
1354
+						)
1355
+					);
1356
+				}
1357
+				$ticket_sold = $existing_ticket->count_related(
1358
+						'Registration',
1359
+						[
1360
+							[
1361
+								'STS_ID' => [
1362
+									'NOT IN',
1363
+									[EEM_Registration::status_id_incomplete],
1364
+								],
1365
+							],
1366
+						]
1367
+					) > 0;
1368
+				// let's just check the total price for the existing ticket and determine if it matches the new total price.
1369
+				// if they are different then we create a new ticket (if $ticket_sold)
1370
+				// if they aren't different then we go ahead and modify existing ticket.
1371
+				$create_new_ticket = $ticket_sold
1372
+									 && $ticket_price !== $existing_ticket->price()
1373
+									 && ! $existing_ticket->deleted();
1374
+				$existing_ticket->set_date_format($date_formats[0]);
1375
+				$existing_ticket->set_time_format($date_formats[1]);
1376
+				// set new values
1377
+				foreach ($ticket_values as $field => $value) {
1378
+					if ($field == 'TKT_qty') {
1379
+						$existing_ticket->set_qty($value);
1380
+					} elseif ($field == 'TKT_price') {
1381
+						$existing_ticket->set('TKT_price', $ticket_price);
1382
+					} else {
1383
+						$existing_ticket->set($field, $value);
1384
+					}
1385
+				}
1386
+				$ticket = $existing_ticket;
1387
+				// if $create_new_ticket is false then we can safely update the existing ticket.
1388
+				//  Otherwise we have to create a new ticket.
1389
+				if ($create_new_ticket) {
1390
+					// archive the old ticket first
1391
+					$existing_ticket->set('TKT_deleted', 1);
1392
+					$existing_ticket->save();
1393
+					// make sure this ticket is still recorded in our $saved_tickets
1394
+					// so we don't run it through the regular trash routine.
1395
+					$saved_tickets[ $existing_ticket->ID() ] = $existing_ticket;
1396
+					// create new ticket that's a copy of the existing except,
1397
+					// (a new id of course and not archived) AND has the new TKT_price associated with it.
1398
+					$new_ticket = clone $existing_ticket;
1399
+					$new_ticket->set('TKT_ID', 0);
1400
+					$new_ticket->set('TKT_deleted', 0);
1401
+					$new_ticket->set('TKT_sold', 0);
1402
+					// now we need to make sure that $new prices are created as well and attached to new ticket.
1403
+					$update_prices = true;
1404
+					$ticket        = $new_ticket;
1405
+				}
1406
+			} else {
1407
+				// no TKT_id so a new ticket
1408
+				$ticket_values['TKT_price'] = $ticket_price;
1409
+				$ticket                     = EE_Ticket::new_instance($ticket_values, $event_timezone, $date_formats);
1410
+				$update_prices              = true;
1411
+			}
1412
+			if (! $ticket instanceof EE_Ticket) {
1413
+				throw new RuntimeException(
1414
+					sprintf(
1415
+						esc_html__(
1416
+							'Something went wrong! A valid Ticket could not be generated or retrieved using the supplied data: %1$s',
1417
+							'event_espresso'
1418
+						),
1419
+						print_r($ticket_values, true)
1420
+					)
1421
+				);
1422
+			}
1423
+			// cap ticket qty by datetime reg limits
1424
+			$ticket->set_qty(min($ticket->qty(), $ticket->qty('reg_limit')));
1425
+			// update ticket.
1426
+			$ticket->save();
1427
+			// before going any further make sure our dates are setup correctly
1428
+			// so that the end date is always equal or greater than the start date.
1429
+			if ($ticket->get_raw('TKT_start_date') > $ticket->get_raw('TKT_end_date')) {
1430
+				$ticket->set('TKT_end_date', $ticket->get('TKT_start_date'));
1431
+				$ticket = EEH_DTT_Helper::date_time_add($ticket, 'TKT_end_date', 'days');
1432
+				$ticket->save();
1433
+			}
1434
+			// initially let's add the ticket to the datetime
1435
+			$datetime->_add_relation_to($ticket, 'Ticket');
1436
+			$saved_tickets[ $ticket->ID() ] = $ticket;
1437
+			// add prices to ticket
1438
+			$prices_data = isset($data['edit_prices'][ $row ]) && is_array($data['edit_prices'][ $row ])
1439
+				? $data['edit_prices'][ $row ]
1440
+				: [];
1441
+			$this->_add_prices_to_ticket($prices_data, $ticket, $update_prices);
1442
+		}
1443
+		// however now we need to handle permanently deleting tickets via the ui.
1444
+		// Keep in mind that the ui does not allow deleting/archiving tickets that have ticket sold.
1445
+		// However, it does allow for deleting tickets that have no tickets sold,
1446
+		// in which case we want to get rid of permanently because there is no need to save in db.
1447
+		$old_tickets     = isset($old_tickets[0]) && $old_tickets[0] === '' ? [] : $old_tickets;
1448
+		$tickets_removed = array_diff($old_tickets, array_keys($saved_tickets));
1449
+		foreach ($tickets_removed as $id) {
1450
+			$id = absint($id);
1451
+			// get the ticket for this id
1452
+			$ticket_to_remove = EEM_Ticket::instance()->get_one_by_ID($id);
1453
+			if (! $ticket_to_remove instanceof EE_Ticket) {
1454
+				continue;
1455
+			}
1456
+			// need to get all the related datetimes on this ticket and remove from every single one of them
1457
+			// (remember this process can ONLY kick off if there are NO tickets sold)
1458
+			$related_datetimes = $ticket_to_remove->get_many_related('Datetime');
1459
+			foreach ($related_datetimes as $related_datetime) {
1460
+				$ticket_to_remove->_remove_relation_to($related_datetime, 'Datetime');
1461
+			}
1462
+			// need to do the same for prices (except these prices can also be deleted because again,
1463
+			// tickets can only be trashed if they don't have any TKTs sold (otherwise they are just archived))
1464
+			$ticket_to_remove->delete_related_permanently('Price');
1465
+			// finally let's delete this ticket
1466
+			// (which should not be blocked at this point b/c we've removed all our relationships)
1467
+			$ticket_to_remove->delete_permanently();
1468
+		}
1469
+		return [$datetime, $saved_tickets];
1470
+	}
1471
+
1472
+
1473
+	/**
1474
+	 * This attaches a list of given prices to a ticket.
1475
+	 * Note we dont' have to worry about ever removing relationships (or archiving prices)
1476
+	 * because if there is a change in price information on a ticket, a new ticket is created anyways
1477
+	 * so the archived ticket will retain the old price info and prices are automatically "archived" via the ticket.
1478
+	 *
1479
+	 * @access  private
1480
+	 * @param array     $prices_data Array of prices from the form.
1481
+	 * @param EE_Ticket $ticket      EE_Ticket object that prices are being attached to.
1482
+	 * @param bool      $new_prices  Whether attach existing incoming prices or create new ones.
1483
+	 * @return  void
1484
+	 * @throws EE_Error
1485
+	 * @throws ReflectionException
1486
+	 */
1487
+	private function _add_prices_to_ticket(array $prices_data, EE_Ticket $ticket, bool $new_prices = false)
1488
+	{
1489
+		$timezone = $ticket->get_timezone();
1490
+		foreach ($prices_data as $row => $price_data) {
1491
+			$price_values = [
1492
+				'PRC_ID'         => ! empty($price_data['PRC_ID']) ? $price_data['PRC_ID'] : null,
1493
+				'PRT_ID'         => ! empty($price_data['PRT_ID']) ? $price_data['PRT_ID'] : null,
1494
+				'PRC_amount'     => ! empty($price_data['PRC_amount']) ? $price_data['PRC_amount'] : 0,
1495
+				'PRC_name'       => ! empty($price_data['PRC_name']) ? $price_data['PRC_name'] : '',
1496
+				'PRC_desc'       => ! empty($price_data['PRC_desc']) ? $price_data['PRC_desc'] : '',
1497
+				'PRC_is_default' => 0, // make sure prices are NOT set as default from this context
1498
+				'PRC_order'      => $row,
1499
+			];
1500
+			if ($new_prices || empty($price_values['PRC_ID'])) {
1501
+				$price_values['PRC_ID'] = 0;
1502
+				$price                  = EE_Price::new_instance($price_values, $timezone);
1503
+			} else {
1504
+				$price = EEM_Price::instance($timezone)->get_one_by_ID($price_data['PRC_ID']);
1505
+				// update this price with new values
1506
+				foreach ($price_values as $field => $new_price) {
1507
+					$price->set($field, $new_price);
1508
+				}
1509
+			}
1510
+			if (! $price instanceof EE_Price) {
1511
+				throw new RuntimeException(
1512
+					sprintf(
1513
+						esc_html__(
1514
+							'Something went wrong! A valid Price could not be generated or retrieved using the supplied data: %1$s',
1515
+							'event_espresso'
1516
+						),
1517
+						print_r($price_values, true)
1518
+					)
1519
+				);
1520
+			}
1521
+			$price->save();
1522
+			$ticket->_add_relation_to($price, 'Price');
1523
+		}
1524
+	}
1525
+
1526
+
1527
+	/**
1528
+	 * Add in our autosave ajax handlers
1529
+	 */
1530
+	protected function _ee_autosave_create_new()
1531
+	{
1532
+	}
1533
+
1534
+
1535
+	/**
1536
+	 * More autosave handlers.
1537
+	 */
1538
+	protected function _ee_autosave_edit()
1539
+	{
1540
+	}
1541
+
1542
+
1543
+	/**
1544
+	 * @throws EE_Error
1545
+	 * @throws ReflectionException
1546
+	 */
1547
+	private function _generate_publish_box_extra_content()
1548
+	{
1549
+		// load formatter helper
1550
+		// args for getting related registrations
1551
+		$approved_query_args        = [
1552
+			[
1553
+				'REG_deleted' => 0,
1554
+				'STS_ID'      => EEM_Registration::status_id_approved,
1555
+			],
1556
+		];
1557
+		$not_approved_query_args    = [
1558
+			[
1559
+				'REG_deleted' => 0,
1560
+				'STS_ID'      => EEM_Registration::status_id_not_approved,
1561
+			],
1562
+		];
1563
+		$pending_payment_query_args = [
1564
+			[
1565
+				'REG_deleted' => 0,
1566
+				'STS_ID'      => EEM_Registration::status_id_pending_payment,
1567
+			],
1568
+		];
1569
+		// publish box
1570
+		$publish_box_extra_args = [
1571
+			'view_approved_reg_url'        => add_query_arg(
1572
+				[
1573
+					'action'      => 'default',
1574
+					'event_id'    => $this->_cpt_model_obj->ID(),
1575
+					'_reg_status' => EEM_Registration::status_id_approved,
1576
+					'use_filters' => true,
1577
+				],
1578
+				REG_ADMIN_URL
1579
+			),
1580
+			'view_not_approved_reg_url'    => add_query_arg(
1581
+				[
1582
+					'action'      => 'default',
1583
+					'event_id'    => $this->_cpt_model_obj->ID(),
1584
+					'_reg_status' => EEM_Registration::status_id_not_approved,
1585
+					'use_filters' => true,
1586
+				],
1587
+				REG_ADMIN_URL
1588
+			),
1589
+			'view_pending_payment_reg_url' => add_query_arg(
1590
+				[
1591
+					'action'      => 'default',
1592
+					'event_id'    => $this->_cpt_model_obj->ID(),
1593
+					'_reg_status' => EEM_Registration::status_id_pending_payment,
1594
+					'use_filters' => true,
1595
+				],
1596
+				REG_ADMIN_URL
1597
+			),
1598
+			'approved_regs'                => $this->_cpt_model_obj->count_related(
1599
+				'Registration',
1600
+				$approved_query_args
1601
+			),
1602
+			'not_approved_regs'            => $this->_cpt_model_obj->count_related(
1603
+				'Registration',
1604
+				$not_approved_query_args
1605
+			),
1606
+			'pending_payment_regs'         => $this->_cpt_model_obj->count_related(
1607
+				'Registration',
1608
+				$pending_payment_query_args
1609
+			),
1610
+			'misc_pub_section_class'       => apply_filters(
1611
+				'FHEE_Events_Admin_Page___generate_publish_box_extra_content__misc_pub_section_class',
1612
+				'misc-pub-section'
1613
+			),
1614
+		];
1615
+		ob_start();
1616
+		do_action(
1617
+			'AHEE__Events_Admin_Page___generate_publish_box_extra_content__event_editor_overview_add',
1618
+			$this->_cpt_model_obj
1619
+		);
1620
+		$publish_box_extra_args['event_editor_overview_add'] = ob_get_clean();
1621
+		// load template
1622
+		EEH_Template::display_template(
1623
+			EVENTS_TEMPLATE_PATH . 'event_publish_box_extras.template.php',
1624
+			$publish_box_extra_args
1625
+		);
1626
+	}
1627
+
1628
+
1629
+	/**
1630
+	 * @return EE_Event
1631
+	 */
1632
+	public function get_event_object()
1633
+	{
1634
+		return $this->_cpt_model_obj;
1635
+	}
1636
+
1637
+
1638
+
1639
+
1640
+	/** METABOXES * */
1641
+	/**
1642
+	 * _register_event_editor_meta_boxes
1643
+	 * add all metaboxes related to the event_editor
1644
+	 *
1645
+	 * @return void
1646
+	 * @throws EE_Error
1647
+	 * @throws ReflectionException
1648
+	 */
1649
+	protected function _register_event_editor_meta_boxes()
1650
+	{
1651
+		$this->verify_cpt_object();
1652
+		$use_advanced_editor = $this->admin_config->useAdvancedEditor();
1653
+		// check if the new EDTR reg options meta box is being used, and if so, don't load the legacy version
1654
+		if (! $use_advanced_editor || ! $this->feature->allowed('use_reg_options_meta_box')) {
1655
+			$this->addMetaBox(
1656
+				'espresso_event_editor_event_options',
1657
+				esc_html__('Event Registration Options', 'event_espresso'),
1658
+				[$this, 'registration_options_meta_box'],
1659
+				$this->page_slug,
1660
+				'side'
1661
+			);
1662
+		}
1663
+		if (! $use_advanced_editor) {
1664
+			$this->addMetaBox(
1665
+				'espresso_event_editor_tickets',
1666
+				esc_html__('Event Datetime & Ticket', 'event_espresso'),
1667
+				[$this, 'ticket_metabox'],
1668
+				$this->page_slug,
1669
+				'normal',
1670
+				'high'
1671
+			);
1672
+		} elseif ($this->feature->allowed('use_reg_options_meta_box')) {
1673
+			add_action(
1674
+				'add_meta_boxes_espresso_events',
1675
+				function () {
1676
+					global $current_screen;
1677
+					remove_meta_box('authordiv', $current_screen, 'normal');
1678
+				},
1679
+				99
1680
+			);
1681
+		}
1682
+		// NOTE: if you're looking for other metaboxes in here,
1683
+		// where a metabox has a related management page in the admin
1684
+		// you will find it setup in the related management page's "_Hooks" file.
1685
+		// i.e. messages metabox is found in "espresso_events_Messages_Hooks.class.php".
1686
+	}
1687
+
1688
+
1689
+	/**
1690
+	 * @throws DomainException
1691
+	 * @throws EE_Error
1692
+	 * @throws ReflectionException
1693
+	 */
1694
+	public function ticket_metabox()
1695
+	{
1696
+		$existing_datetime_ids = $existing_ticket_ids = [];
1697
+		// defaults for template args
1698
+		$template_args = [
1699
+			'ticket_rows'       => '',
1700
+			'total_ticket_rows' => 1,
1701
+			'trash_icon'        => 'dashicons dashicons-lock',
1702
+			'disabled'          => '',
1703
+		];
1704
+		$event_id      = is_object($this->_cpt_model_obj) ? $this->_cpt_model_obj->ID() : null;
1705
+		/**
1706
+		 * 1. Start with retrieving Datetimes
1707
+		 * 2. Fore each datetime get related tickets
1708
+		 * 3. For each ticket get related prices
1709
+		 */
1710
+		/** @var EEM_Datetime $datetime_model */
1711
+		$datetime_model = EE_Registry::instance()->load_model('Datetime');
1712
+		/** @var EEM_Ticket $datetime_model */
1713
+		$ticket_model = EE_Registry::instance()->load_model('Ticket');
1714
+		$times        = $datetime_model->get_all_event_dates($event_id);
1715
+		/** @type EE_Datetime $first_datetime */
1716
+		$first_datetime = reset($times);
1717
+		// do we get related tickets?
1718
+		if (
1719
+			$first_datetime instanceof EE_Datetime
1720
+			&& $first_datetime->ID() !== 0
1721
+		) {
1722
+			$existing_datetime_ids[] = $first_datetime->get('DTT_ID');
1723
+			$template_args['time']   = $first_datetime;
1724
+			$related_tickets         = $first_datetime->tickets(
1725
+				[
1726
+					['OR' => ['TKT_deleted' => 1, 'TKT_deleted*' => 0]],
1727
+					'default_where_conditions' => 'none',
1728
+				]
1729
+			);
1730
+			if (! empty($related_tickets)) {
1731
+				$template_args['total_ticket_rows'] = count($related_tickets);
1732
+				$row                                = 0;
1733
+				foreach ($related_tickets as $ticket) {
1734
+					$existing_ticket_ids[]        = $ticket->get('TKT_ID');
1735
+					$template_args['ticket_rows'] .= $this->_get_ticket_row($ticket, false, $row);
1736
+					$row++;
1737
+				}
1738
+			} else {
1739
+				$template_args['total_ticket_rows'] = 1;
1740
+				/** @type EE_Ticket $ticket */
1741
+				$ticket                       = $ticket_model->create_default_object();
1742
+				$template_args['ticket_rows'] .= $this->_get_ticket_row($ticket);
1743
+			}
1744
+		} else {
1745
+			$template_args['time'] = $times[0];
1746
+			/** @type EE_Ticket[] $tickets */
1747
+			$tickets                      = $ticket_model->get_all_default_tickets();
1748
+			$template_args['ticket_rows'] .= $this->_get_ticket_row($tickets[1]);
1749
+			// NOTE: we're just sending the first default row
1750
+			// (decaf can't manage default tickets so this should be sufficient);
1751
+		}
1752
+		$template_args['event_datetime_help_link'] = $this->_get_help_tab_link(
1753
+			'event_editor_event_datetimes_help_tab'
1754
+		);
1755
+		$template_args['ticket_options_help_link'] = $this->_get_help_tab_link('ticket_options_info');
1756
+		$template_args['existing_datetime_ids']    = implode(',', $existing_datetime_ids);
1757
+		$template_args['existing_ticket_ids']      = implode(',', $existing_ticket_ids);
1758
+		$template_args['ticket_js_structure']      = $this->_get_ticket_row(
1759
+			$ticket_model->create_default_object(),
1760
+			true
1761
+		);
1762
+		$template                                  = apply_filters(
1763
+			'FHEE__Events_Admin_Page__ticket_metabox__template',
1764
+			EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_main.template.php'
1765
+		);
1766
+		EEH_Template::display_template($template, $template_args);
1767
+	}
1768
+
1769
+
1770
+	/**
1771
+	 * Setup an individual ticket form for the decaf event editor page
1772
+	 *
1773
+	 * @access private
1774
+	 * @param EE_Ticket $ticket   the ticket object
1775
+	 * @param boolean   $skeleton whether we're generating a skeleton for js manipulation
1776
+	 * @param int       $row
1777
+	 * @return string generated html for the ticket row.
1778
+	 * @throws EE_Error
1779
+	 * @throws ReflectionException
1780
+	 */
1781
+	private function _get_ticket_row(EE_Ticket $ticket, bool $skeleton = false, int $row = 0): string
1782
+	{
1783
+		$template_args = [
1784
+			'tkt_status_class'    => ' tkt-status-' . $ticket->ticket_status(),
1785
+			'tkt_archive_class'   => $ticket->ticket_status() === EE_Ticket::archived && ! $skeleton ? ' tkt-archived'
1786
+				: '',
1787
+			'ticketrow'           => $skeleton ? 'TICKETNUM' : $row,
1788
+			'TKT_ID'              => $ticket->get('TKT_ID'),
1789
+			'TKT_name'            => $ticket->get('TKT_name'),
1790
+			'TKT_start_date'      => $skeleton ? '' : $ticket->get_date('TKT_start_date', 'Y-m-d h:i a'),
1791
+			'TKT_end_date'        => $skeleton ? '' : $ticket->get_date('TKT_end_date', 'Y-m-d h:i a'),
1792
+			'TKT_is_default'      => $ticket->get('TKT_is_default'),
1793
+			'TKT_qty'             => $ticket->get_pretty('TKT_qty', 'input'),
1794
+			'edit_ticketrow_name' => $skeleton ? 'TICKETNAMEATTR' : 'edit_tickets',
1795
+			'TKT_sold'            => $skeleton ? 0 : $ticket->get('TKT_sold'),
1796
+			'trash_icon'          => ($skeleton || (! $ticket->get('TKT_deleted')))
1797
+									 && (! empty($ticket) && $ticket->get('TKT_sold') === 0)
1798
+				? 'dashicons dashicons-post-trash clickable'
1799
+				: 'dashicons dashicons-lock',
1800
+			'disabled'            => $skeleton || (! empty($ticket) && ! $ticket->get('TKT_deleted')) ? ''
1801
+				: ' disabled=disabled',
1802
+		];
1803
+		$price         = $ticket->ID() !== 0
1804
+			? $ticket->get_first_related('Price', ['default_where_conditions' => 'none'])
1805
+			: null;
1806
+		$price         = $price instanceof EE_Price
1807
+			? $price
1808
+			: EEM_Price::instance()->create_default_object();
1809
+		$price_args    = [
1810
+			'price_currency_symbol' => EE_Registry::instance()->CFG->currency->sign,
1811
+			'PRC_amount'            => $price->get('PRC_amount'),
1812
+			'PRT_ID'                => $price->get('PRT_ID'),
1813
+			'PRC_ID'                => $price->get('PRC_ID'),
1814
+			'PRC_is_default'        => $price->get('PRC_is_default'),
1815
+		];
1816
+		// make sure we have default start and end dates if skeleton
1817
+		// handle rows that should NOT be empty
1818
+		if (empty($template_args['TKT_start_date'])) {
1819
+			// if empty then the start date will be now.
1820
+			$template_args['TKT_start_date'] = date('Y-m-d h:i a', current_time('timestamp'));
1821
+		}
1822
+		if (empty($template_args['TKT_end_date'])) {
1823
+			// get the earliest datetime (if present);
1824
+			$earliest_datetime             = $this->_cpt_model_obj->ID() > 0
1825
+				? $this->_cpt_model_obj->get_first_related(
1826
+					'Datetime',
1827
+					['order_by' => ['DTT_EVT_start' => 'ASC']]
1828
+				)
1829
+				: null;
1830
+			$template_args['TKT_end_date'] = $earliest_datetime instanceof EE_Datetime
1831
+				? $earliest_datetime->get_datetime('DTT_EVT_start', 'Y-m-d', 'h:i a')
1832
+				: date('Y-m-d h:i a', mktime(0, 0, 0, date('m'), date('d') + 7, date('Y')));
1833
+		}
1834
+		$template_args = array_merge($template_args, $price_args);
1835
+		$template      = apply_filters(
1836
+			'FHEE__Events_Admin_Page__get_ticket_row__template',
1837
+			EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_ticket_row.template.php',
1838
+			$ticket
1839
+		);
1840
+		return EEH_Template::display_template($template, $template_args, true);
1841
+	}
1842
+
1843
+
1844
+	/**
1845
+	 * @throws EE_Error
1846
+	 * @throws ReflectionException
1847
+	 */
1848
+	public function registration_options_meta_box()
1849
+	{
1850
+		$yes_no_values             = [
1851
+			['id' => true, 'text' => esc_html__('Yes', 'event_espresso')],
1852
+			['id' => false, 'text' => esc_html__('No', 'event_espresso')],
1853
+		];
1854
+		$default_reg_status_values = EEM_Registration::reg_status_array(
1855
+			[
1856
+				EEM_Registration::status_id_cancelled,
1857
+				EEM_Registration::status_id_declined,
1858
+				EEM_Registration::status_id_incomplete,
1859
+			],
1860
+			true
1861
+		);
1862
+		// $template_args['is_active_select'] = EEH_Form_Fields::select_input('is_active', $yes_no_values, $this->_cpt_model_obj->is_active());
1863
+		$template_args['_event']                          = $this->_cpt_model_obj;
1864
+		$template_args['event']                           = $this->_cpt_model_obj;
1865
+		$template_args['active_status']                   = $this->_cpt_model_obj->pretty_active_status(false);
1866
+		$template_args['additional_limit']                = $this->_cpt_model_obj->additional_limit();
1867
+		$template_args['default_registration_status']     = EEH_Form_Fields::select_input(
1868
+			'default_reg_status',
1869
+			$default_reg_status_values,
1870
+			$this->_cpt_model_obj->default_registration_status(),
1871
+			'',
1872
+			'ee-input-width--reg',
1873
+			false
1874
+		);
1875
+		$template_args['display_description']             = EEH_Form_Fields::select_input(
1876
+			'display_desc',
1877
+			$yes_no_values,
1878
+			$this->_cpt_model_obj->display_description()
1879
+		);
1880
+		$template_args['display_ticket_selector']         = EEH_Form_Fields::select_input(
1881
+			'display_ticket_selector',
1882
+			$yes_no_values,
1883
+			$this->_cpt_model_obj->display_ticket_selector(),
1884
+			'',
1885
+			'ee-input-width--small',
1886
+			false
1887
+		);
1888
+		$template_args['additional_registration_options'] = apply_filters(
1889
+			'FHEE__Events_Admin_Page__registration_options_meta_box__additional_registration_options',
1890
+			'',
1891
+			$template_args,
1892
+			$yes_no_values,
1893
+			$default_reg_status_values
1894
+		);
1895
+		EEH_Template::display_template(
1896
+			EVENTS_TEMPLATE_PATH . 'event_registration_options.template.php',
1897
+			$template_args
1898
+		);
1899
+	}
1900
+
1901
+
1902
+	/**
1903
+	 * _get_events()
1904
+	 * This method simply returns all the events (for the given _view and paging)
1905
+	 *
1906
+	 * @access public
1907
+	 * @param int  $per_page     count of items per page (20 default);
1908
+	 * @param int  $current_page what is the current page being viewed.
1909
+	 * @param bool $count        if TRUE then we just return a count of ALL events matching the given _view.
1910
+	 *                           If FALSE then we return an array of event objects
1911
+	 *                           that match the given _view and paging parameters.
1912
+	 * @return array|int         an array of event objects or a count of them.
1913
+	 * @throws Exception
1914
+	 */
1915
+	public function get_events(int $per_page = 10, int $current_page = 1, bool $count = false)
1916
+	{
1917
+		$EEM_Event   = $this->_event_model();
1918
+		$offset      = ($current_page - 1) * $per_page;
1919
+		$limit       = $count ? null : $offset . ',' . $per_page;
1920
+		$orderby     = $this->request->getRequestParam('orderby', 'EVT_ID');
1921
+		$order       = $this->request->getRequestParam('order', 'DESC');
1922
+		$month_range = $this->request->getRequestParam('month_range');
1923
+		if ($month_range) {
1924
+			$pieces = explode(' ', $month_range, 3);
1925
+			// simulate the FIRST day of the month, that fixes issues for months like February
1926
+			// where PHP doesn't know what to assume for date.
1927
+			// @see https://events.codebasehq.com/projects/event-espresso/tickets/10437
1928
+			$month_r = ! empty($pieces[0]) ? date('m', EEH_DTT_Helper::first_of_month_timestamp($pieces[0])) : '';
1929
+			$year_r  = ! empty($pieces[1]) ? $pieces[1] : '';
1930
+		}
1931
+		$where  = [];
1932
+		$status = $this->request->getRequestParam('status');
1933
+		// determine what post_status our condition will have for the query.
1934
+		switch ($status) {
1935
+			case 'month':
1936
+			case 'today':
1937
+			case null:
1938
+			case 'all':
1939
+				break;
1940
+			case 'draft':
1941
+				$where['status'] = ['IN', ['draft', 'auto-draft']];
1942
+				break;
1943
+			default:
1944
+				$where['status'] = $status;
1945
+		}
1946
+		// categories? The default for all categories is -1
1947
+		$category = $this->request->getRequestParam('EVT_CAT', -1, DataType::INT);
1948
+		if ($category !== -1) {
1949
+			$where['Term_Taxonomy.taxonomy'] = EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY;
1950
+			$where['Term_Taxonomy.term_id']  = $category;
1951
+		}
1952
+		// date where conditions
1953
+		$start_formats = EEM_Datetime::instance()->get_formats_for('DTT_EVT_start');
1954
+		if ($month_range) {
1955
+			$DateTime = new DateTime(
1956
+				$year_r . '-' . $month_r . '-01 00:00:00',
1957
+				new DateTimeZone('UTC')
1958
+			);
1959
+			$start    = $DateTime->getTimestamp();
1960
+			// set the datetime to be the end of the month
1961
+			$DateTime->setDate(
1962
+				$year_r,
1963
+				$month_r,
1964
+				$DateTime->format('t')
1965
+			)->setTime(23, 59, 59);
1966
+			$end                             = $DateTime->getTimestamp();
1967
+			$where['Datetime.DTT_EVT_start'] = ['BETWEEN', [$start, $end]];
1968
+		} elseif ($status === 'today') {
1969
+			$DateTime                        =
1970
+				new DateTime('now', new DateTimeZone(EEM_Event::instance()->get_timezone()));
1971
+			$start                           = $DateTime->setTime(0, 0)->format(implode(' ', $start_formats));
1972
+			$end                             = $DateTime->setTime(23, 59, 59)->format(implode(' ', $start_formats));
1973
+			$where['Datetime.DTT_EVT_start'] = ['BETWEEN', [$start, $end]];
1974
+		} elseif ($status === 'month') {
1975
+			$now                             = date('Y-m-01');
1976
+			$DateTime                        =
1977
+				new DateTime($now, new DateTimeZone(EEM_Event::instance()->get_timezone()));
1978
+			$start                           = $DateTime->setTime(0, 0)->format(implode(' ', $start_formats));
1979
+			$end                             = $DateTime->setDate(date('Y'), date('m'), $DateTime->format('t'))
1980
+														->setTime(23, 59, 59)
1981
+														->format(implode(' ', $start_formats));
1982
+			$where['Datetime.DTT_EVT_start'] = ['BETWEEN', [$start, $end]];
1983
+		}
1984
+		if (! $this->capabilities->current_user_can('ee_read_others_events', 'get_events')) {
1985
+			$where['EVT_wp_user'] = get_current_user_id();
1986
+		} else {
1987
+			if (! isset($where['status'])) {
1988
+				if (! $this->capabilities->current_user_can('ee_read_private_events', 'get_events')) {
1989
+					$where['OR'] = [
1990
+						'status*restrict_private' => ['!=', 'private'],
1991
+						'AND'                     => [
1992
+							'status*inclusive' => ['=', 'private'],
1993
+							'EVT_wp_user'      => get_current_user_id(),
1994
+						],
1995
+					];
1996
+				}
1997
+			}
1998
+		}
1999
+		$wp_user = $this->request->getRequestParam('EVT_wp_user', 0, DataType::INT);
2000
+		if (
2001
+			$wp_user
2002
+			&& $wp_user !== get_current_user_id()
2003
+			&& $this->capabilities->current_user_can('ee_read_others_events', 'get_events')
2004
+		) {
2005
+			$where['EVT_wp_user'] = $wp_user;
2006
+		}
2007
+		// search query handling
2008
+		$search_term = $this->request->getRequestParam('s');
2009
+		if ($search_term) {
2010
+			$search_term = '%' . $search_term . '%';
2011
+			$where['OR'] = [
2012
+				'EVT_name'       => ['LIKE', $search_term],
2013
+				'EVT_desc'       => ['LIKE', $search_term],
2014
+				'EVT_short_desc' => ['LIKE', $search_term],
2015
+			];
2016
+		}
2017
+		// filter events by venue.
2018
+		$venue = $this->request->getRequestParam('venue', 0, DataType::INT);
2019
+		if ($venue) {
2020
+			$where['Venue.VNU_ID'] = $venue;
2021
+		}
2022
+		$request_params = $this->request->requestParams();
2023
+		$where          = apply_filters('FHEE__Events_Admin_Page__get_events__where', $where, $request_params);
2024
+		$query_params   = apply_filters(
2025
+			'FHEE__Events_Admin_Page__get_events__query_params',
2026
+			[
2027
+				$where,
2028
+				'limit'    => $limit,
2029
+				'order_by' => $orderby,
2030
+				'order'    => $order,
2031
+				'group_by' => 'EVT_ID',
2032
+			],
2033
+			$request_params
2034
+		);
2035
+
2036
+		// let's first check if we have special requests coming in.
2037
+		$active_status = $this->request->getRequestParam('active_status');
2038
+		if ($active_status) {
2039
+			switch ($active_status) {
2040
+				case 'upcoming':
2041
+					return $EEM_Event->get_upcoming_events($query_params, $count);
2042
+				case 'expired':
2043
+					return $EEM_Event->get_expired_events($query_params, $count);
2044
+				case 'active':
2045
+					return $EEM_Event->get_active_events($query_params, $count);
2046
+				case 'inactive':
2047
+					return $EEM_Event->get_inactive_events($query_params, $count);
2048
+			}
2049
+		}
2050
+
2051
+		return $count ? $EEM_Event->count([$where], 'EVT_ID', true) : $EEM_Event->get_all($query_params);
2052
+	}
2053
+
2054
+
2055
+	/**
2056
+	 * handling for WordPress CPT actions (trash, restore, delete)
2057
+	 *
2058
+	 * @param string $post_id
2059
+	 * @throws EE_Error
2060
+	 * @throws ReflectionException
2061
+	 */
2062
+	public function trash_cpt_item($post_id)
2063
+	{
2064
+		$this->request->setRequestParam('EVT_ID', $post_id);
2065
+		$this->_trash_or_restore_event('trash', false);
2066
+	}
2067
+
2068
+
2069
+	/**
2070
+	 * @param string $post_id
2071
+	 * @throws EE_Error
2072
+	 * @throws ReflectionException
2073
+	 */
2074
+	public function restore_cpt_item($post_id)
2075
+	{
2076
+		$this->request->setRequestParam('EVT_ID', $post_id);
2077
+		$this->_trash_or_restore_event('draft', false);
2078
+	}
2079
+
2080
+
2081
+	/**
2082
+	 * @param string $post_id
2083
+	 * @throws EE_Error
2084
+	 * @throws EE_Error
2085
+	 */
2086
+	public function delete_cpt_item($post_id)
2087
+	{
2088
+		throw new EE_Error(
2089
+			esc_html__(
2090
+				'Please contact Event Espresso support with the details of the steps taken to produce this error.',
2091
+				'event_espresso'
2092
+			)
2093
+		);
2094
+		// $this->request->setRequestParam('EVT_ID', $post_id);
2095
+		// $this->_delete_event();
2096
+	}
2097
+
2098
+
2099
+	/**
2100
+	 * _trash_or_restore_event
2101
+	 *
2102
+	 * @access protected
2103
+	 * @param string $event_status
2104
+	 * @param bool   $redirect_after
2105
+	 * @throws EE_Error
2106
+	 * @throws EE_Error
2107
+	 * @throws ReflectionException
2108
+	 */
2109
+	protected function _trash_or_restore_event(string $event_status = 'trash', bool $redirect_after = true)
2110
+	{
2111
+		// loop thru events
2112
+		if ($this->EVT_ID) {
2113
+			// clean status
2114
+			$event_status = sanitize_key($event_status);
2115
+			// grab status
2116
+			if (! empty($event_status)) {
2117
+				$success = $this->_change_event_status($this->EVT_ID, $event_status);
2118
+			} else {
2119
+				$success = false;
2120
+				$msg     = esc_html__(
2121
+					'An error occurred. The event could not be moved to the trash because a valid event status was not not supplied.',
2122
+					'event_espresso'
2123
+				);
2124
+				EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2125
+			}
2126
+		} else {
2127
+			$success = false;
2128
+			$msg     = esc_html__(
2129
+				'An error occurred. The event could not be moved to the trash because a valid event ID was not not supplied.',
2130
+				'event_espresso'
2131
+			);
2132
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2133
+		}
2134
+		$action = $event_status === 'trash' ? 'moved to the trash' : 'restored from the trash';
2135
+		if ($redirect_after) {
2136
+			$this->_redirect_after_action($success, 'Event', $action, ['action' => 'default']);
2137
+		}
2138
+	}
2139
+
2140
+
2141
+	/**
2142
+	 * _trash_or_restore_events
2143
+	 *
2144
+	 * @access protected
2145
+	 * @param string $event_status
2146
+	 * @return void
2147
+	 * @throws EE_Error
2148
+	 * @throws EE_Error
2149
+	 * @throws ReflectionException
2150
+	 */
2151
+	protected function _trash_or_restore_events(string $event_status = 'trash')
2152
+	{
2153
+		// clean status
2154
+		$event_status = sanitize_key($event_status);
2155
+		// grab status
2156
+		if (! empty($event_status)) {
2157
+			$success = true;
2158
+			// determine the event id and set to array.
2159
+			$EVT_IDs = $this->request->getRequestParam('EVT_IDs', [], 'int', true);
2160
+			// loop thru events
2161
+			foreach ($EVT_IDs as $EVT_ID) {
2162
+				if ($EVT_ID = absint($EVT_ID)) {
2163
+					$results = $this->_change_event_status($EVT_ID, $event_status);
2164
+					$success = $results !== false ? $success : false;
2165
+				} else {
2166
+					$msg = sprintf(
2167
+						esc_html__(
2168
+							'An error occurred. Event #%d could not be moved to the trash because a valid event ID was not not supplied.',
2169
+							'event_espresso'
2170
+						),
2171
+						$EVT_ID
2172
+					);
2173
+					EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2174
+					$success = false;
2175
+				}
2176
+			}
2177
+		} else {
2178
+			$success = false;
2179
+			$msg     = esc_html__(
2180
+				'An error occurred. The event could not be moved to the trash because a valid event status was not not supplied.',
2181
+				'event_espresso'
2182
+			);
2183
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2184
+		}
2185
+		// in order to force a pluralized result message we need to send back a success status greater than 1
2186
+		$success = $success ? 2 : false;
2187
+		$action  = $event_status === 'trash' ? 'moved to the trash' : 'restored from the trash';
2188
+		$this->_redirect_after_action($success, 'Events', $action, ['action' => 'default']);
2189
+	}
2190
+
2191
+
2192
+	/**
2193
+	 * @param int    $EVT_ID
2194
+	 * @param string $event_status
2195
+	 * @return bool
2196
+	 * @throws EE_Error
2197
+	 * @throws ReflectionException
2198
+	 */
2199
+	private function _change_event_status(int $EVT_ID = 0, string $event_status = ''): bool
2200
+	{
2201
+		// grab event id
2202
+		if (! $EVT_ID) {
2203
+			$msg = esc_html__(
2204
+				'An error occurred. No Event ID or an invalid Event ID was received.',
2205
+				'event_espresso'
2206
+			);
2207
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2208
+			return false;
2209
+		}
2210
+		$this->_cpt_model_obj = EEM_Event::instance()->get_one_by_ID($EVT_ID);
2211
+		// clean status
2212
+		$event_status = sanitize_key($event_status);
2213
+		// grab status
2214
+		if (empty($event_status)) {
2215
+			$msg = esc_html__(
2216
+				'An error occurred. No Event Status or an invalid Event Status was received.',
2217
+				'event_espresso'
2218
+			);
2219
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2220
+			return false;
2221
+		}
2222
+		// was event trashed or restored ?
2223
+		switch ($event_status) {
2224
+			case 'draft':
2225
+				$action = 'restored from the trash';
2226
+				$hook   = 'AHEE_event_restored_from_trash';
2227
+				break;
2228
+			case 'trash':
2229
+				$action = 'moved to the trash';
2230
+				$hook   = 'AHEE_event_moved_to_trash';
2231
+				break;
2232
+			default:
2233
+				$action = 'updated';
2234
+				$hook   = false;
2235
+		}
2236
+		// use class to change status
2237
+		$this->_cpt_model_obj->set_status($event_status);
2238
+		$success = $this->_cpt_model_obj->save();
2239
+		if (! $success) {
2240
+			$msg = sprintf(esc_html__('An error occurred. The event could not be %s.', 'event_espresso'), $action);
2241
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2242
+			return false;
2243
+		}
2244
+		if ($hook) {
2245
+			do_action($hook);
2246
+			// fake the action hook in EE_Soft_Delete_Base_Class::delete_or_restore()
2247
+			// because events side step that and it otherwise won't get called
2248
+			do_action(
2249
+				'AHEE__EE_Soft_Delete_Base_Class__delete_or_restore__after',
2250
+				$this->_cpt_model_obj,
2251
+				$hook === 'AHEE_event_moved_to_trash',
2252
+				$success
2253
+			);
2254
+		}
2255
+		return true;
2256
+	}
2257
+
2258
+
2259
+	/**
2260
+	 * @param array $event_ids
2261
+	 * @return array
2262
+	 * @since   4.10.23.p
2263
+	 */
2264
+	private function cleanEventIds(array $event_ids): array
2265
+	{
2266
+		return array_map('absint', $event_ids);
2267
+	}
2268
+
2269
+
2270
+	/**
2271
+	 * @return array
2272
+	 * @since   4.10.23.p
2273
+	 */
2274
+	private function getEventIdsFromRequest(): array
2275
+	{
2276
+		if ($this->request->requestParamIsSet('EVT_IDs')) {
2277
+			return $this->request->getRequestParam('EVT_IDs', [], 'int', true);
2278
+		} else {
2279
+			return $this->request->getRequestParam('EVT_ID', [], 'int', true);
2280
+		}
2281
+	}
2282
+
2283
+
2284
+	/**
2285
+	 * @param bool $preview_delete
2286
+	 * @throws EE_Error
2287
+	 * @throws ReflectionException
2288
+	 */
2289
+	protected function _delete_event(bool $preview_delete = true)
2290
+	{
2291
+		$this->_delete_events($preview_delete);
2292
+	}
2293
+
2294
+
2295
+	/**
2296
+	 * Gets the tree traversal batch persister.
2297
+	 *
2298
+	 * @return NodeGroupDao
2299
+	 * @throws InvalidArgumentException
2300
+	 * @throws InvalidDataTypeException
2301
+	 * @throws InvalidInterfaceException
2302
+	 * @since 4.10.12.p
2303
+	 */
2304
+	protected function getModelObjNodeGroupPersister(): NodeGroupDao
2305
+	{
2306
+		if (! $this->model_obj_node_group_persister instanceof NodeGroupDao) {
2307
+			$this->model_obj_node_group_persister =
2308
+				$this->getLoader()->load('\EventEspresso\core\services\orm\tree_traversal\NodeGroupDao');
2309
+		}
2310
+		return $this->model_obj_node_group_persister;
2311
+	}
2312
+
2313
+
2314
+	/**
2315
+	 * @param bool $preview_delete
2316
+	 * @return void
2317
+	 * @throws EE_Error
2318
+	 * @throws ReflectionException
2319
+	 */
2320
+	protected function _delete_events(bool $preview_delete = true)
2321
+	{
2322
+		$event_ids = $this->getEventIdsFromRequest();
2323
+		if ($preview_delete) {
2324
+			$this->generateDeletionPreview($event_ids);
2325
+		} else {
2326
+			foreach ($event_ids as $event_id) {
2327
+				$event = EEM_Event::instance()->get_one_by_ID($event_id);
2328
+				if ($event instanceof EE_Event) {
2329
+					$event->delete_permanently();
2330
+				}
2331
+			}
2332
+		}
2333
+	}
2334
+
2335
+
2336
+	/**
2337
+	 * @param array $event_ids
2338
+	 */
2339
+	protected function generateDeletionPreview(array $event_ids)
2340
+	{
2341
+		$event_ids = $this->cleanEventIds($event_ids);
2342
+		// Set a code we can use to reference this deletion task in the batch jobs and preview page.
2343
+		$deletion_job_code = $this->getModelObjNodeGroupPersister()->generateGroupCode();
2344
+		$return_url        = EE_Admin_Page::add_query_args_and_nonce(
2345
+			[
2346
+				'action'            => 'preview_deletion',
2347
+				'deletion_job_code' => $deletion_job_code,
2348
+			],
2349
+			$this->_admin_base_url
2350
+		);
2351
+		EEH_URL::safeRedirectAndExit(
2352
+			EE_Admin_Page::add_query_args_and_nonce(
2353
+				[
2354
+					'page'              => EED_Batch::PAGE_SLUG,
2355
+					'batch'             => EED_Batch::batch_job,
2356
+					'EVT_IDs'           => $event_ids,
2357
+					'deletion_job_code' => $deletion_job_code,
2358
+					'job_handler'       => urlencode('EventEspresso\core\libraries\batch\JobHandlers\PreviewEventDeletion'),
2359
+					'return_url'        => urlencode($return_url),
2360
+				],
2361
+				admin_url()
2362
+			)
2363
+		);
2364
+	}
2365
+
2366
+
2367
+	/**
2368
+	 * Checks for a POST submission
2369
+	 *
2370
+	 * @since 4.10.12.p
2371
+	 */
2372
+	protected function confirmDeletion()
2373
+	{
2374
+		$deletion_redirect_logic = $this->getLoader()->getShared(
2375
+			'EventEspresso\core\domain\services\admin\events\data\ConfirmDeletion'
2376
+		);
2377
+		$deletion_redirect_logic->handle($this->get_request_data(), $this->admin_base_url());
2378
+	}
2379
+
2380
+
2381
+	/**
2382
+	 * A page for users to preview what exactly will be deleted, and confirm they want to delete it.
2383
+	 *
2384
+	 * @throws EE_Error
2385
+	 * @since 4.10.12.p
2386
+	 */
2387
+	protected function previewDeletion()
2388
+	{
2389
+		$preview_deletion_logic = $this->getLoader()->getShared(
2390
+			'EventEspresso\core\domain\services\admin\events\data\PreviewDeletion'
2391
+		);
2392
+		$this->set_template_args($preview_deletion_logic->handle($this->get_request_data(), $this->admin_base_url()));
2393
+		$this->display_admin_page_with_no_sidebar();
2394
+	}
2395
+
2396
+
2397
+	/**
2398
+	 * get total number of events
2399
+	 *
2400
+	 * @access public
2401
+	 * @return int
2402
+	 * @throws EE_Error
2403
+	 * @throws EE_Error
2404
+	 * @throws ReflectionException
2405
+	 */
2406
+	public function total_events(): int
2407
+	{
2408
+		return EEM_Event::instance()->count(
2409
+			['caps' => 'read_admin'],
2410
+			'EVT_ID',
2411
+			true
2412
+		);
2413
+	}
2414
+
2415
+
2416
+	/**
2417
+	 * get total number of draft events
2418
+	 *
2419
+	 * @access public
2420
+	 * @return int
2421
+	 * @throws EE_Error
2422
+	 * @throws EE_Error
2423
+	 * @throws ReflectionException
2424
+	 */
2425
+	public function total_events_draft(): int
2426
+	{
2427
+		return EEM_Event::instance()->count(
2428
+			[
2429
+				['status' => ['IN', ['draft', 'auto-draft']]],
2430
+				'caps' => 'read_admin',
2431
+			],
2432
+			'EVT_ID',
2433
+			true
2434
+		);
2435
+	}
2436
+
2437
+
2438
+	/**
2439
+	 * get total number of trashed events
2440
+	 *
2441
+	 * @access public
2442
+	 * @return int
2443
+	 * @throws EE_Error
2444
+	 * @throws EE_Error
2445
+	 * @throws ReflectionException
2446
+	 */
2447
+	public function total_trashed_events(): int
2448
+	{
2449
+		return EEM_Event::instance()->count(
2450
+			[
2451
+				['status' => 'trash'],
2452
+				'caps' => 'read_admin',
2453
+			],
2454
+			'EVT_ID',
2455
+			true
2456
+		);
2457
+	}
2458
+
2459
+
2460
+	/**
2461
+	 *    _default_event_settings
2462
+	 *    This generates the Default Settings Tab
2463
+	 *
2464
+	 * @return void
2465
+	 * @throws DomainException
2466
+	 * @throws EE_Error
2467
+	 * @throws InvalidArgumentException
2468
+	 * @throws InvalidDataTypeException
2469
+	 * @throws InvalidInterfaceException
2470
+	 * @throws ReflectionException
2471
+	 */
2472
+	protected function _default_event_settings()
2473
+	{
2474
+		$this->_set_add_edit_form_tags('update_default_event_settings');
2475
+		$this->_set_publish_post_box_vars();
2476
+		$this->_template_args['admin_page_content'] = EEH_HTML::div(
2477
+			$this->_default_event_settings_form()->get_html(),
2478
+			'',
2479
+			'padding'
2480
+		);
2481
+		$this->display_admin_page_with_sidebar();
2482
+	}
2483
+
2484
+
2485
+	/**
2486
+	 * Return the form for event settings.
2487
+	 *
2488
+	 * @return EE_Form_Section_Proper
2489
+	 * @throws EE_Error
2490
+	 * @throws ReflectionException
2491
+	 */
2492
+	protected function _default_event_settings_form(): EE_Form_Section_Proper
2493
+	{
2494
+		$registration_config              = EE_Registry::instance()->CFG->registration;
2495
+		$registration_stati_for_selection = EEM_Registration::reg_status_array(
2496
+		// exclude
2497
+			[
2498
+				EEM_Registration::status_id_cancelled,
2499
+				EEM_Registration::status_id_declined,
2500
+				EEM_Registration::status_id_incomplete,
2501
+				EEM_Registration::status_id_wait_list,
2502
+			],
2503
+			true
2504
+		);
2505
+		// setup Advanced Editor ???
2506
+		if (
2507
+			$this->raw_req_action === 'default_event_settings'
2508
+			|| $this->raw_req_action === 'update_default_event_settings'
2509
+		) {
2510
+			$this->advanced_editor_admin_form = $this->loader->getShared(AdvancedEditorAdminFormSection::class);
2511
+		}
2512
+		return new EE_Form_Section_Proper(
2513
+			[
2514
+				'name'            => 'update_default_event_settings',
2515
+				'html_id'         => 'update_default_event_settings',
2516
+				'html_class'      => 'form-table',
2517
+				'layout_strategy' => new EE_Admin_Two_Column_Layout(),
2518
+				'subsections'     => apply_filters(
2519
+					'FHEE__Events_Admin_Page___default_event_settings_form__form_subsections',
2520
+					[
2521
+						'defaults_section_header' => new EE_Form_Section_HTML(
2522
+							EEH_HTML::h2(
2523
+								esc_html__('Default Settings', 'event_espresso'),
2524
+								'',
2525
+								'ee-admin-settings-hdr'
2526
+							)
2527
+						),
2528
+						'default_reg_status'      => new EE_Select_Input(
2529
+							$registration_stati_for_selection,
2530
+							[
2531
+								'default'         => isset($registration_config->default_STS_ID)
2532
+													 && array_key_exists(
2533
+														 $registration_config->default_STS_ID,
2534
+														 $registration_stati_for_selection
2535
+													 )
2536
+									? sanitize_text_field($registration_config->default_STS_ID)
2537
+									: EEM_Registration::status_id_pending_payment,
2538
+								'html_label_text' => esc_html__('Default Registration Status', 'event_espresso')
2539
+													 . EEH_Template::get_help_tab_link(
2540
+										'default_settings_status_help_tab'
2541
+									),
2542
+								'html_help_text'  => esc_html__(
2543
+									'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.',
2544
+									'event_espresso'
2545
+								),
2546
+							]
2547
+						),
2548
+						'default_max_tickets'     => new EE_Integer_Input(
2549
+							[
2550
+								'default'         => $registration_config->default_maximum_number_of_tickets
2551
+													 ?? EEM_Event::get_default_additional_limit(),
2552
+								'html_label_text' => esc_html__(
2553
+														 'Default Maximum Tickets Allowed Per Order:',
2554
+														 'event_espresso'
2555
+													 )
2556
+													 . EEH_Template::get_help_tab_link(
2557
+										'default_maximum_tickets_help_tab"'
2558
+									),
2559
+								'html_help_text'  => esc_html__(
2560
+									'This setting allows you to indicate what will be the default for the maximum number of tickets per order when creating new events.',
2561
+									'event_espresso'
2562
+								),
2563
+							]
2564
+						),
2565
+					]
2566
+				),
2567
+			]
2568
+		);
2569
+	}
2570
+
2571
+
2572
+	/**
2573
+	 * @return void
2574
+	 * @throws EE_Error
2575
+	 * @throws InvalidArgumentException
2576
+	 * @throws InvalidDataTypeException
2577
+	 * @throws InvalidInterfaceException
2578
+	 * @throws ReflectionException
2579
+	 */
2580
+	protected function _update_default_event_settings()
2581
+	{
2582
+		$form = $this->_default_event_settings_form();
2583
+		if ($form->was_submitted()) {
2584
+			$form->receive_form_submission();
2585
+			if ($form->is_valid()) {
2586
+				$registration_config = EE_Registry::instance()->CFG->registration;
2587
+				$valid_data          = $form->valid_data();
2588
+				if (isset($valid_data['default_reg_status'])) {
2589
+					$registration_config->default_STS_ID = $valid_data['default_reg_status'];
2590
+				}
2591
+				if (isset($valid_data['default_max_tickets'])) {
2592
+					$registration_config->default_maximum_number_of_tickets = $valid_data['default_max_tickets'];
2593
+				}
2594
+				do_action(
2595
+					'AHEE__Events_Admin_Page___update_default_event_settings',
2596
+					$valid_data,
2597
+					EE_Registry::instance()->CFG,
2598
+					$this
2599
+				);
2600
+				// update because data was valid!
2601
+				EE_Registry::instance()->CFG->update_espresso_config();
2602
+				EE_Error::overwrite_success();
2603
+				EE_Error::add_success(
2604
+					esc_html__('Default Event Settings were updated', 'event_espresso')
2605
+				);
2606
+			}
2607
+		}
2608
+		$this->_redirect_after_action(0, '', '', ['action' => 'default_event_settings'], true);
2609
+	}
2610
+
2611
+
2612
+	/*************        Templates        *************
1772 2613
      *
1773
-     * @access private
1774
-     * @param EE_Ticket $ticket   the ticket object
1775
-     * @param boolean   $skeleton whether we're generating a skeleton for js manipulation
1776
-     * @param int       $row
1777
-     * @return string generated html for the ticket row.
1778
-     * @throws EE_Error
1779
-     * @throws ReflectionException
1780
-     */
1781
-    private function _get_ticket_row(EE_Ticket $ticket, bool $skeleton = false, int $row = 0): string
1782
-    {
1783
-        $template_args = [
1784
-            'tkt_status_class'    => ' tkt-status-' . $ticket->ticket_status(),
1785
-            'tkt_archive_class'   => $ticket->ticket_status() === EE_Ticket::archived && ! $skeleton ? ' tkt-archived'
1786
-                : '',
1787
-            'ticketrow'           => $skeleton ? 'TICKETNUM' : $row,
1788
-            'TKT_ID'              => $ticket->get('TKT_ID'),
1789
-            'TKT_name'            => $ticket->get('TKT_name'),
1790
-            'TKT_start_date'      => $skeleton ? '' : $ticket->get_date('TKT_start_date', 'Y-m-d h:i a'),
1791
-            'TKT_end_date'        => $skeleton ? '' : $ticket->get_date('TKT_end_date', 'Y-m-d h:i a'),
1792
-            'TKT_is_default'      => $ticket->get('TKT_is_default'),
1793
-            'TKT_qty'             => $ticket->get_pretty('TKT_qty', 'input'),
1794
-            'edit_ticketrow_name' => $skeleton ? 'TICKETNAMEATTR' : 'edit_tickets',
1795
-            'TKT_sold'            => $skeleton ? 0 : $ticket->get('TKT_sold'),
1796
-            'trash_icon'          => ($skeleton || (! $ticket->get('TKT_deleted')))
1797
-                                     && (! empty($ticket) && $ticket->get('TKT_sold') === 0)
1798
-                ? 'dashicons dashicons-post-trash clickable'
1799
-                : 'dashicons dashicons-lock',
1800
-            'disabled'            => $skeleton || (! empty($ticket) && ! $ticket->get('TKT_deleted')) ? ''
1801
-                : ' disabled=disabled',
1802
-        ];
1803
-        $price         = $ticket->ID() !== 0
1804
-            ? $ticket->get_first_related('Price', ['default_where_conditions' => 'none'])
1805
-            : null;
1806
-        $price         = $price instanceof EE_Price
1807
-            ? $price
1808
-            : EEM_Price::instance()->create_default_object();
1809
-        $price_args    = [
1810
-            'price_currency_symbol' => EE_Registry::instance()->CFG->currency->sign,
1811
-            'PRC_amount'            => $price->get('PRC_amount'),
1812
-            'PRT_ID'                => $price->get('PRT_ID'),
1813
-            'PRC_ID'                => $price->get('PRC_ID'),
1814
-            'PRC_is_default'        => $price->get('PRC_is_default'),
1815
-        ];
1816
-        // make sure we have default start and end dates if skeleton
1817
-        // handle rows that should NOT be empty
1818
-        if (empty($template_args['TKT_start_date'])) {
1819
-            // if empty then the start date will be now.
1820
-            $template_args['TKT_start_date'] = date('Y-m-d h:i a', current_time('timestamp'));
1821
-        }
1822
-        if (empty($template_args['TKT_end_date'])) {
1823
-            // get the earliest datetime (if present);
1824
-            $earliest_datetime             = $this->_cpt_model_obj->ID() > 0
1825
-                ? $this->_cpt_model_obj->get_first_related(
1826
-                    'Datetime',
1827
-                    ['order_by' => ['DTT_EVT_start' => 'ASC']]
1828
-                )
1829
-                : null;
1830
-            $template_args['TKT_end_date'] = $earliest_datetime instanceof EE_Datetime
1831
-                ? $earliest_datetime->get_datetime('DTT_EVT_start', 'Y-m-d', 'h:i a')
1832
-                : date('Y-m-d h:i a', mktime(0, 0, 0, date('m'), date('d') + 7, date('Y')));
1833
-        }
1834
-        $template_args = array_merge($template_args, $price_args);
1835
-        $template      = apply_filters(
1836
-            'FHEE__Events_Admin_Page__get_ticket_row__template',
1837
-            EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_ticket_row.template.php',
1838
-            $ticket
1839
-        );
1840
-        return EEH_Template::display_template($template, $template_args, true);
1841
-    }
1842
-
1843
-
1844
-    /**
1845
-     * @throws EE_Error
1846
-     * @throws ReflectionException
1847
-     */
1848
-    public function registration_options_meta_box()
1849
-    {
1850
-        $yes_no_values             = [
1851
-            ['id' => true, 'text' => esc_html__('Yes', 'event_espresso')],
1852
-            ['id' => false, 'text' => esc_html__('No', 'event_espresso')],
1853
-        ];
1854
-        $default_reg_status_values = EEM_Registration::reg_status_array(
1855
-            [
1856
-                EEM_Registration::status_id_cancelled,
1857
-                EEM_Registration::status_id_declined,
1858
-                EEM_Registration::status_id_incomplete,
1859
-            ],
1860
-            true
1861
-        );
1862
-        // $template_args['is_active_select'] = EEH_Form_Fields::select_input('is_active', $yes_no_values, $this->_cpt_model_obj->is_active());
1863
-        $template_args['_event']                          = $this->_cpt_model_obj;
1864
-        $template_args['event']                           = $this->_cpt_model_obj;
1865
-        $template_args['active_status']                   = $this->_cpt_model_obj->pretty_active_status(false);
1866
-        $template_args['additional_limit']                = $this->_cpt_model_obj->additional_limit();
1867
-        $template_args['default_registration_status']     = EEH_Form_Fields::select_input(
1868
-            'default_reg_status',
1869
-            $default_reg_status_values,
1870
-            $this->_cpt_model_obj->default_registration_status(),
1871
-            '',
1872
-            'ee-input-width--reg',
1873
-            false
1874
-        );
1875
-        $template_args['display_description']             = EEH_Form_Fields::select_input(
1876
-            'display_desc',
1877
-            $yes_no_values,
1878
-            $this->_cpt_model_obj->display_description()
1879
-        );
1880
-        $template_args['display_ticket_selector']         = EEH_Form_Fields::select_input(
1881
-            'display_ticket_selector',
1882
-            $yes_no_values,
1883
-            $this->_cpt_model_obj->display_ticket_selector(),
1884
-            '',
1885
-            'ee-input-width--small',
1886
-            false
1887
-        );
1888
-        $template_args['additional_registration_options'] = apply_filters(
1889
-            'FHEE__Events_Admin_Page__registration_options_meta_box__additional_registration_options',
1890
-            '',
1891
-            $template_args,
1892
-            $yes_no_values,
1893
-            $default_reg_status_values
1894
-        );
1895
-        EEH_Template::display_template(
1896
-            EVENTS_TEMPLATE_PATH . 'event_registration_options.template.php',
1897
-            $template_args
1898
-        );
1899
-    }
1900
-
1901
-
1902
-    /**
1903
-     * _get_events()
1904
-     * This method simply returns all the events (for the given _view and paging)
1905
-     *
1906
-     * @access public
1907
-     * @param int  $per_page     count of items per page (20 default);
1908
-     * @param int  $current_page what is the current page being viewed.
1909
-     * @param bool $count        if TRUE then we just return a count of ALL events matching the given _view.
1910
-     *                           If FALSE then we return an array of event objects
1911
-     *                           that match the given _view and paging parameters.
1912
-     * @return array|int         an array of event objects or a count of them.
1913
-     * @throws Exception
1914
-     */
1915
-    public function get_events(int $per_page = 10, int $current_page = 1, bool $count = false)
1916
-    {
1917
-        $EEM_Event   = $this->_event_model();
1918
-        $offset      = ($current_page - 1) * $per_page;
1919
-        $limit       = $count ? null : $offset . ',' . $per_page;
1920
-        $orderby     = $this->request->getRequestParam('orderby', 'EVT_ID');
1921
-        $order       = $this->request->getRequestParam('order', 'DESC');
1922
-        $month_range = $this->request->getRequestParam('month_range');
1923
-        if ($month_range) {
1924
-            $pieces = explode(' ', $month_range, 3);
1925
-            // simulate the FIRST day of the month, that fixes issues for months like February
1926
-            // where PHP doesn't know what to assume for date.
1927
-            // @see https://events.codebasehq.com/projects/event-espresso/tickets/10437
1928
-            $month_r = ! empty($pieces[0]) ? date('m', EEH_DTT_Helper::first_of_month_timestamp($pieces[0])) : '';
1929
-            $year_r  = ! empty($pieces[1]) ? $pieces[1] : '';
1930
-        }
1931
-        $where  = [];
1932
-        $status = $this->request->getRequestParam('status');
1933
-        // determine what post_status our condition will have for the query.
1934
-        switch ($status) {
1935
-            case 'month':
1936
-            case 'today':
1937
-            case null:
1938
-            case 'all':
1939
-                break;
1940
-            case 'draft':
1941
-                $where['status'] = ['IN', ['draft', 'auto-draft']];
1942
-                break;
1943
-            default:
1944
-                $where['status'] = $status;
1945
-        }
1946
-        // categories? The default for all categories is -1
1947
-        $category = $this->request->getRequestParam('EVT_CAT', -1, DataType::INT);
1948
-        if ($category !== -1) {
1949
-            $where['Term_Taxonomy.taxonomy'] = EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY;
1950
-            $where['Term_Taxonomy.term_id']  = $category;
1951
-        }
1952
-        // date where conditions
1953
-        $start_formats = EEM_Datetime::instance()->get_formats_for('DTT_EVT_start');
1954
-        if ($month_range) {
1955
-            $DateTime = new DateTime(
1956
-                $year_r . '-' . $month_r . '-01 00:00:00',
1957
-                new DateTimeZone('UTC')
1958
-            );
1959
-            $start    = $DateTime->getTimestamp();
1960
-            // set the datetime to be the end of the month
1961
-            $DateTime->setDate(
1962
-                $year_r,
1963
-                $month_r,
1964
-                $DateTime->format('t')
1965
-            )->setTime(23, 59, 59);
1966
-            $end                             = $DateTime->getTimestamp();
1967
-            $where['Datetime.DTT_EVT_start'] = ['BETWEEN', [$start, $end]];
1968
-        } elseif ($status === 'today') {
1969
-            $DateTime                        =
1970
-                new DateTime('now', new DateTimeZone(EEM_Event::instance()->get_timezone()));
1971
-            $start                           = $DateTime->setTime(0, 0)->format(implode(' ', $start_formats));
1972
-            $end                             = $DateTime->setTime(23, 59, 59)->format(implode(' ', $start_formats));
1973
-            $where['Datetime.DTT_EVT_start'] = ['BETWEEN', [$start, $end]];
1974
-        } elseif ($status === 'month') {
1975
-            $now                             = date('Y-m-01');
1976
-            $DateTime                        =
1977
-                new DateTime($now, new DateTimeZone(EEM_Event::instance()->get_timezone()));
1978
-            $start                           = $DateTime->setTime(0, 0)->format(implode(' ', $start_formats));
1979
-            $end                             = $DateTime->setDate(date('Y'), date('m'), $DateTime->format('t'))
1980
-                                                        ->setTime(23, 59, 59)
1981
-                                                        ->format(implode(' ', $start_formats));
1982
-            $where['Datetime.DTT_EVT_start'] = ['BETWEEN', [$start, $end]];
1983
-        }
1984
-        if (! $this->capabilities->current_user_can('ee_read_others_events', 'get_events')) {
1985
-            $where['EVT_wp_user'] = get_current_user_id();
1986
-        } else {
1987
-            if (! isset($where['status'])) {
1988
-                if (! $this->capabilities->current_user_can('ee_read_private_events', 'get_events')) {
1989
-                    $where['OR'] = [
1990
-                        'status*restrict_private' => ['!=', 'private'],
1991
-                        'AND'                     => [
1992
-                            'status*inclusive' => ['=', 'private'],
1993
-                            'EVT_wp_user'      => get_current_user_id(),
1994
-                        ],
1995
-                    ];
1996
-                }
1997
-            }
1998
-        }
1999
-        $wp_user = $this->request->getRequestParam('EVT_wp_user', 0, DataType::INT);
2000
-        if (
2001
-            $wp_user
2002
-            && $wp_user !== get_current_user_id()
2003
-            && $this->capabilities->current_user_can('ee_read_others_events', 'get_events')
2004
-        ) {
2005
-            $where['EVT_wp_user'] = $wp_user;
2006
-        }
2007
-        // search query handling
2008
-        $search_term = $this->request->getRequestParam('s');
2009
-        if ($search_term) {
2010
-            $search_term = '%' . $search_term . '%';
2011
-            $where['OR'] = [
2012
-                'EVT_name'       => ['LIKE', $search_term],
2013
-                'EVT_desc'       => ['LIKE', $search_term],
2014
-                'EVT_short_desc' => ['LIKE', $search_term],
2015
-            ];
2016
-        }
2017
-        // filter events by venue.
2018
-        $venue = $this->request->getRequestParam('venue', 0, DataType::INT);
2019
-        if ($venue) {
2020
-            $where['Venue.VNU_ID'] = $venue;
2021
-        }
2022
-        $request_params = $this->request->requestParams();
2023
-        $where          = apply_filters('FHEE__Events_Admin_Page__get_events__where', $where, $request_params);
2024
-        $query_params   = apply_filters(
2025
-            'FHEE__Events_Admin_Page__get_events__query_params',
2026
-            [
2027
-                $where,
2028
-                'limit'    => $limit,
2029
-                'order_by' => $orderby,
2030
-                'order'    => $order,
2031
-                'group_by' => 'EVT_ID',
2032
-            ],
2033
-            $request_params
2034
-        );
2035
-
2036
-        // let's first check if we have special requests coming in.
2037
-        $active_status = $this->request->getRequestParam('active_status');
2038
-        if ($active_status) {
2039
-            switch ($active_status) {
2040
-                case 'upcoming':
2041
-                    return $EEM_Event->get_upcoming_events($query_params, $count);
2042
-                case 'expired':
2043
-                    return $EEM_Event->get_expired_events($query_params, $count);
2044
-                case 'active':
2045
-                    return $EEM_Event->get_active_events($query_params, $count);
2046
-                case 'inactive':
2047
-                    return $EEM_Event->get_inactive_events($query_params, $count);
2048
-            }
2049
-        }
2050
-
2051
-        return $count ? $EEM_Event->count([$where], 'EVT_ID', true) : $EEM_Event->get_all($query_params);
2052
-    }
2053
-
2054
-
2055
-    /**
2056
-     * handling for WordPress CPT actions (trash, restore, delete)
2057
-     *
2058
-     * @param string $post_id
2059
-     * @throws EE_Error
2060
-     * @throws ReflectionException
2061
-     */
2062
-    public function trash_cpt_item($post_id)
2063
-    {
2064
-        $this->request->setRequestParam('EVT_ID', $post_id);
2065
-        $this->_trash_or_restore_event('trash', false);
2066
-    }
2067
-
2068
-
2069
-    /**
2070
-     * @param string $post_id
2071
-     * @throws EE_Error
2072
-     * @throws ReflectionException
2073
-     */
2074
-    public function restore_cpt_item($post_id)
2075
-    {
2076
-        $this->request->setRequestParam('EVT_ID', $post_id);
2077
-        $this->_trash_or_restore_event('draft', false);
2078
-    }
2079
-
2080
-
2081
-    /**
2082
-     * @param string $post_id
2083
-     * @throws EE_Error
2084
-     * @throws EE_Error
2085
-     */
2086
-    public function delete_cpt_item($post_id)
2087
-    {
2088
-        throw new EE_Error(
2089
-            esc_html__(
2090
-                'Please contact Event Espresso support with the details of the steps taken to produce this error.',
2091
-                'event_espresso'
2092
-            )
2093
-        );
2094
-        // $this->request->setRequestParam('EVT_ID', $post_id);
2095
-        // $this->_delete_event();
2096
-    }
2097
-
2098
-
2099
-    /**
2100
-     * _trash_or_restore_event
2101
-     *
2102
-     * @access protected
2103
-     * @param string $event_status
2104
-     * @param bool   $redirect_after
2105
-     * @throws EE_Error
2106
-     * @throws EE_Error
2107
-     * @throws ReflectionException
2108
-     */
2109
-    protected function _trash_or_restore_event(string $event_status = 'trash', bool $redirect_after = true)
2110
-    {
2111
-        // loop thru events
2112
-        if ($this->EVT_ID) {
2113
-            // clean status
2114
-            $event_status = sanitize_key($event_status);
2115
-            // grab status
2116
-            if (! empty($event_status)) {
2117
-                $success = $this->_change_event_status($this->EVT_ID, $event_status);
2118
-            } else {
2119
-                $success = false;
2120
-                $msg     = esc_html__(
2121
-                    'An error occurred. The event could not be moved to the trash because a valid event status was not not supplied.',
2122
-                    'event_espresso'
2123
-                );
2124
-                EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2125
-            }
2126
-        } else {
2127
-            $success = false;
2128
-            $msg     = esc_html__(
2129
-                'An error occurred. The event could not be moved to the trash because a valid event ID was not not supplied.',
2130
-                'event_espresso'
2131
-            );
2132
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2133
-        }
2134
-        $action = $event_status === 'trash' ? 'moved to the trash' : 'restored from the trash';
2135
-        if ($redirect_after) {
2136
-            $this->_redirect_after_action($success, 'Event', $action, ['action' => 'default']);
2137
-        }
2138
-    }
2139
-
2140
-
2141
-    /**
2142
-     * _trash_or_restore_events
2143
-     *
2144
-     * @access protected
2145
-     * @param string $event_status
2146
-     * @return void
2147
-     * @throws EE_Error
2148
-     * @throws EE_Error
2149
-     * @throws ReflectionException
2150
-     */
2151
-    protected function _trash_or_restore_events(string $event_status = 'trash')
2152
-    {
2153
-        // clean status
2154
-        $event_status = sanitize_key($event_status);
2155
-        // grab status
2156
-        if (! empty($event_status)) {
2157
-            $success = true;
2158
-            // determine the event id and set to array.
2159
-            $EVT_IDs = $this->request->getRequestParam('EVT_IDs', [], 'int', true);
2160
-            // loop thru events
2161
-            foreach ($EVT_IDs as $EVT_ID) {
2162
-                if ($EVT_ID = absint($EVT_ID)) {
2163
-                    $results = $this->_change_event_status($EVT_ID, $event_status);
2164
-                    $success = $results !== false ? $success : false;
2165
-                } else {
2166
-                    $msg = sprintf(
2167
-                        esc_html__(
2168
-                            'An error occurred. Event #%d could not be moved to the trash because a valid event ID was not not supplied.',
2169
-                            'event_espresso'
2170
-                        ),
2171
-                        $EVT_ID
2172
-                    );
2173
-                    EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2174
-                    $success = false;
2175
-                }
2176
-            }
2177
-        } else {
2178
-            $success = false;
2179
-            $msg     = esc_html__(
2180
-                'An error occurred. The event could not be moved to the trash because a valid event status was not not supplied.',
2181
-                'event_espresso'
2182
-            );
2183
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2184
-        }
2185
-        // in order to force a pluralized result message we need to send back a success status greater than 1
2186
-        $success = $success ? 2 : false;
2187
-        $action  = $event_status === 'trash' ? 'moved to the trash' : 'restored from the trash';
2188
-        $this->_redirect_after_action($success, 'Events', $action, ['action' => 'default']);
2189
-    }
2190
-
2191
-
2192
-    /**
2193
-     * @param int    $EVT_ID
2194
-     * @param string $event_status
2195
-     * @return bool
2196
-     * @throws EE_Error
2197
-     * @throws ReflectionException
2198
-     */
2199
-    private function _change_event_status(int $EVT_ID = 0, string $event_status = ''): bool
2200
-    {
2201
-        // grab event id
2202
-        if (! $EVT_ID) {
2203
-            $msg = esc_html__(
2204
-                'An error occurred. No Event ID or an invalid Event ID was received.',
2205
-                'event_espresso'
2206
-            );
2207
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2208
-            return false;
2209
-        }
2210
-        $this->_cpt_model_obj = EEM_Event::instance()->get_one_by_ID($EVT_ID);
2211
-        // clean status
2212
-        $event_status = sanitize_key($event_status);
2213
-        // grab status
2214
-        if (empty($event_status)) {
2215
-            $msg = esc_html__(
2216
-                'An error occurred. No Event Status or an invalid Event Status was received.',
2217
-                'event_espresso'
2218
-            );
2219
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2220
-            return false;
2221
-        }
2222
-        // was event trashed or restored ?
2223
-        switch ($event_status) {
2224
-            case 'draft':
2225
-                $action = 'restored from the trash';
2226
-                $hook   = 'AHEE_event_restored_from_trash';
2227
-                break;
2228
-            case 'trash':
2229
-                $action = 'moved to the trash';
2230
-                $hook   = 'AHEE_event_moved_to_trash';
2231
-                break;
2232
-            default:
2233
-                $action = 'updated';
2234
-                $hook   = false;
2235
-        }
2236
-        // use class to change status
2237
-        $this->_cpt_model_obj->set_status($event_status);
2238
-        $success = $this->_cpt_model_obj->save();
2239
-        if (! $success) {
2240
-            $msg = sprintf(esc_html__('An error occurred. The event could not be %s.', 'event_espresso'), $action);
2241
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2242
-            return false;
2243
-        }
2244
-        if ($hook) {
2245
-            do_action($hook);
2246
-            // fake the action hook in EE_Soft_Delete_Base_Class::delete_or_restore()
2247
-            // because events side step that and it otherwise won't get called
2248
-            do_action(
2249
-                'AHEE__EE_Soft_Delete_Base_Class__delete_or_restore__after',
2250
-                $this->_cpt_model_obj,
2251
-                $hook === 'AHEE_event_moved_to_trash',
2252
-                $success
2253
-            );
2254
-        }
2255
-        return true;
2256
-    }
2257
-
2258
-
2259
-    /**
2260
-     * @param array $event_ids
2261
-     * @return array
2262
-     * @since   4.10.23.p
2263
-     */
2264
-    private function cleanEventIds(array $event_ids): array
2265
-    {
2266
-        return array_map('absint', $event_ids);
2267
-    }
2268
-
2269
-
2270
-    /**
2271
-     * @return array
2272
-     * @since   4.10.23.p
2273
-     */
2274
-    private function getEventIdsFromRequest(): array
2275
-    {
2276
-        if ($this->request->requestParamIsSet('EVT_IDs')) {
2277
-            return $this->request->getRequestParam('EVT_IDs', [], 'int', true);
2278
-        } else {
2279
-            return $this->request->getRequestParam('EVT_ID', [], 'int', true);
2280
-        }
2281
-    }
2282
-
2283
-
2284
-    /**
2285
-     * @param bool $preview_delete
2286
-     * @throws EE_Error
2287
-     * @throws ReflectionException
2288
-     */
2289
-    protected function _delete_event(bool $preview_delete = true)
2290
-    {
2291
-        $this->_delete_events($preview_delete);
2292
-    }
2293
-
2294
-
2295
-    /**
2296
-     * Gets the tree traversal batch persister.
2297
-     *
2298
-     * @return NodeGroupDao
2299
-     * @throws InvalidArgumentException
2300
-     * @throws InvalidDataTypeException
2301
-     * @throws InvalidInterfaceException
2302
-     * @since 4.10.12.p
2303
-     */
2304
-    protected function getModelObjNodeGroupPersister(): NodeGroupDao
2305
-    {
2306
-        if (! $this->model_obj_node_group_persister instanceof NodeGroupDao) {
2307
-            $this->model_obj_node_group_persister =
2308
-                $this->getLoader()->load('\EventEspresso\core\services\orm\tree_traversal\NodeGroupDao');
2309
-        }
2310
-        return $this->model_obj_node_group_persister;
2311
-    }
2312
-
2313
-
2314
-    /**
2315
-     * @param bool $preview_delete
2316
-     * @return void
2317
-     * @throws EE_Error
2318
-     * @throws ReflectionException
2319
-     */
2320
-    protected function _delete_events(bool $preview_delete = true)
2321
-    {
2322
-        $event_ids = $this->getEventIdsFromRequest();
2323
-        if ($preview_delete) {
2324
-            $this->generateDeletionPreview($event_ids);
2325
-        } else {
2326
-            foreach ($event_ids as $event_id) {
2327
-                $event = EEM_Event::instance()->get_one_by_ID($event_id);
2328
-                if ($event instanceof EE_Event) {
2329
-                    $event->delete_permanently();
2330
-                }
2331
-            }
2332
-        }
2333
-    }
2334
-
2335
-
2336
-    /**
2337
-     * @param array $event_ids
2338
-     */
2339
-    protected function generateDeletionPreview(array $event_ids)
2340
-    {
2341
-        $event_ids = $this->cleanEventIds($event_ids);
2342
-        // Set a code we can use to reference this deletion task in the batch jobs and preview page.
2343
-        $deletion_job_code = $this->getModelObjNodeGroupPersister()->generateGroupCode();
2344
-        $return_url        = EE_Admin_Page::add_query_args_and_nonce(
2345
-            [
2346
-                'action'            => 'preview_deletion',
2347
-                'deletion_job_code' => $deletion_job_code,
2348
-            ],
2349
-            $this->_admin_base_url
2350
-        );
2351
-        EEH_URL::safeRedirectAndExit(
2352
-            EE_Admin_Page::add_query_args_and_nonce(
2353
-                [
2354
-                    'page'              => EED_Batch::PAGE_SLUG,
2355
-                    'batch'             => EED_Batch::batch_job,
2356
-                    'EVT_IDs'           => $event_ids,
2357
-                    'deletion_job_code' => $deletion_job_code,
2358
-                    'job_handler'       => urlencode('EventEspresso\core\libraries\batch\JobHandlers\PreviewEventDeletion'),
2359
-                    'return_url'        => urlencode($return_url),
2360
-                ],
2361
-                admin_url()
2362
-            )
2363
-        );
2364
-    }
2365
-
2366
-
2367
-    /**
2368
-     * Checks for a POST submission
2369
-     *
2370
-     * @since 4.10.12.p
2371
-     */
2372
-    protected function confirmDeletion()
2373
-    {
2374
-        $deletion_redirect_logic = $this->getLoader()->getShared(
2375
-            'EventEspresso\core\domain\services\admin\events\data\ConfirmDeletion'
2376
-        );
2377
-        $deletion_redirect_logic->handle($this->get_request_data(), $this->admin_base_url());
2378
-    }
2379
-
2380
-
2381
-    /**
2382
-     * A page for users to preview what exactly will be deleted, and confirm they want to delete it.
2383
-     *
2384
-     * @throws EE_Error
2385
-     * @since 4.10.12.p
2386
-     */
2387
-    protected function previewDeletion()
2388
-    {
2389
-        $preview_deletion_logic = $this->getLoader()->getShared(
2390
-            'EventEspresso\core\domain\services\admin\events\data\PreviewDeletion'
2391
-        );
2392
-        $this->set_template_args($preview_deletion_logic->handle($this->get_request_data(), $this->admin_base_url()));
2393
-        $this->display_admin_page_with_no_sidebar();
2394
-    }
2395
-
2396
-
2397
-    /**
2398
-     * get total number of events
2399
-     *
2400
-     * @access public
2401
-     * @return int
2402
-     * @throws EE_Error
2403
-     * @throws EE_Error
2404
-     * @throws ReflectionException
2405
-     */
2406
-    public function total_events(): int
2407
-    {
2408
-        return EEM_Event::instance()->count(
2409
-            ['caps' => 'read_admin'],
2410
-            'EVT_ID',
2411
-            true
2412
-        );
2413
-    }
2414
-
2415
-
2416
-    /**
2417
-     * get total number of draft events
2418
-     *
2419
-     * @access public
2420
-     * @return int
2421
-     * @throws EE_Error
2422
-     * @throws EE_Error
2423
-     * @throws ReflectionException
2424
-     */
2425
-    public function total_events_draft(): int
2426
-    {
2427
-        return EEM_Event::instance()->count(
2428
-            [
2429
-                ['status' => ['IN', ['draft', 'auto-draft']]],
2430
-                'caps' => 'read_admin',
2431
-            ],
2432
-            'EVT_ID',
2433
-            true
2434
-        );
2435
-    }
2436
-
2437
-
2438
-    /**
2439
-     * get total number of trashed events
2440
-     *
2441
-     * @access public
2442
-     * @return int
2443
-     * @throws EE_Error
2444
-     * @throws EE_Error
2445
-     * @throws ReflectionException
2446
-     */
2447
-    public function total_trashed_events(): int
2448
-    {
2449
-        return EEM_Event::instance()->count(
2450
-            [
2451
-                ['status' => 'trash'],
2452
-                'caps' => 'read_admin',
2453
-            ],
2454
-            'EVT_ID',
2455
-            true
2456
-        );
2457
-    }
2458
-
2459
-
2460
-    /**
2461
-     *    _default_event_settings
2462
-     *    This generates the Default Settings Tab
2463
-     *
2464
-     * @return void
2465
-     * @throws DomainException
2466
-     * @throws EE_Error
2467
-     * @throws InvalidArgumentException
2468
-     * @throws InvalidDataTypeException
2469
-     * @throws InvalidInterfaceException
2470
-     * @throws ReflectionException
2471
-     */
2472
-    protected function _default_event_settings()
2473
-    {
2474
-        $this->_set_add_edit_form_tags('update_default_event_settings');
2475
-        $this->_set_publish_post_box_vars();
2476
-        $this->_template_args['admin_page_content'] = EEH_HTML::div(
2477
-            $this->_default_event_settings_form()->get_html(),
2478
-            '',
2479
-            'padding'
2480
-        );
2481
-        $this->display_admin_page_with_sidebar();
2482
-    }
2483
-
2484
-
2485
-    /**
2486
-     * Return the form for event settings.
2487
-     *
2488
-     * @return EE_Form_Section_Proper
2489
-     * @throws EE_Error
2490
-     * @throws ReflectionException
2491
-     */
2492
-    protected function _default_event_settings_form(): EE_Form_Section_Proper
2493
-    {
2494
-        $registration_config              = EE_Registry::instance()->CFG->registration;
2495
-        $registration_stati_for_selection = EEM_Registration::reg_status_array(
2496
-        // exclude
2497
-            [
2498
-                EEM_Registration::status_id_cancelled,
2499
-                EEM_Registration::status_id_declined,
2500
-                EEM_Registration::status_id_incomplete,
2501
-                EEM_Registration::status_id_wait_list,
2502
-            ],
2503
-            true
2504
-        );
2505
-        // setup Advanced Editor ???
2506
-        if (
2507
-            $this->raw_req_action === 'default_event_settings'
2508
-            || $this->raw_req_action === 'update_default_event_settings'
2509
-        ) {
2510
-            $this->advanced_editor_admin_form = $this->loader->getShared(AdvancedEditorAdminFormSection::class);
2511
-        }
2512
-        return new EE_Form_Section_Proper(
2513
-            [
2514
-                'name'            => 'update_default_event_settings',
2515
-                'html_id'         => 'update_default_event_settings',
2516
-                'html_class'      => 'form-table',
2517
-                'layout_strategy' => new EE_Admin_Two_Column_Layout(),
2518
-                'subsections'     => apply_filters(
2519
-                    'FHEE__Events_Admin_Page___default_event_settings_form__form_subsections',
2520
-                    [
2521
-                        'defaults_section_header' => new EE_Form_Section_HTML(
2522
-                            EEH_HTML::h2(
2523
-                                esc_html__('Default Settings', 'event_espresso'),
2524
-                                '',
2525
-                                'ee-admin-settings-hdr'
2526
-                            )
2527
-                        ),
2528
-                        'default_reg_status'      => new EE_Select_Input(
2529
-                            $registration_stati_for_selection,
2530
-                            [
2531
-                                'default'         => isset($registration_config->default_STS_ID)
2532
-                                                     && array_key_exists(
2533
-                                                         $registration_config->default_STS_ID,
2534
-                                                         $registration_stati_for_selection
2535
-                                                     )
2536
-                                    ? sanitize_text_field($registration_config->default_STS_ID)
2537
-                                    : EEM_Registration::status_id_pending_payment,
2538
-                                'html_label_text' => esc_html__('Default Registration Status', 'event_espresso')
2539
-                                                     . EEH_Template::get_help_tab_link(
2540
-                                        'default_settings_status_help_tab'
2541
-                                    ),
2542
-                                'html_help_text'  => esc_html__(
2543
-                                    '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.',
2544
-                                    'event_espresso'
2545
-                                ),
2546
-                            ]
2547
-                        ),
2548
-                        'default_max_tickets'     => new EE_Integer_Input(
2549
-                            [
2550
-                                'default'         => $registration_config->default_maximum_number_of_tickets
2551
-                                                     ?? EEM_Event::get_default_additional_limit(),
2552
-                                'html_label_text' => esc_html__(
2553
-                                                         'Default Maximum Tickets Allowed Per Order:',
2554
-                                                         'event_espresso'
2555
-                                                     )
2556
-                                                     . EEH_Template::get_help_tab_link(
2557
-                                        'default_maximum_tickets_help_tab"'
2558
-                                    ),
2559
-                                'html_help_text'  => esc_html__(
2560
-                                    'This setting allows you to indicate what will be the default for the maximum number of tickets per order when creating new events.',
2561
-                                    'event_espresso'
2562
-                                ),
2563
-                            ]
2564
-                        ),
2565
-                    ]
2566
-                ),
2567
-            ]
2568
-        );
2569
-    }
2570
-
2571
-
2572
-    /**
2573
-     * @return void
2574
-     * @throws EE_Error
2575
-     * @throws InvalidArgumentException
2576
-     * @throws InvalidDataTypeException
2577
-     * @throws InvalidInterfaceException
2578
-     * @throws ReflectionException
2579
-     */
2580
-    protected function _update_default_event_settings()
2581
-    {
2582
-        $form = $this->_default_event_settings_form();
2583
-        if ($form->was_submitted()) {
2584
-            $form->receive_form_submission();
2585
-            if ($form->is_valid()) {
2586
-                $registration_config = EE_Registry::instance()->CFG->registration;
2587
-                $valid_data          = $form->valid_data();
2588
-                if (isset($valid_data['default_reg_status'])) {
2589
-                    $registration_config->default_STS_ID = $valid_data['default_reg_status'];
2590
-                }
2591
-                if (isset($valid_data['default_max_tickets'])) {
2592
-                    $registration_config->default_maximum_number_of_tickets = $valid_data['default_max_tickets'];
2593
-                }
2594
-                do_action(
2595
-                    'AHEE__Events_Admin_Page___update_default_event_settings',
2596
-                    $valid_data,
2597
-                    EE_Registry::instance()->CFG,
2598
-                    $this
2599
-                );
2600
-                // update because data was valid!
2601
-                EE_Registry::instance()->CFG->update_espresso_config();
2602
-                EE_Error::overwrite_success();
2603
-                EE_Error::add_success(
2604
-                    esc_html__('Default Event Settings were updated', 'event_espresso')
2605
-                );
2606
-            }
2607
-        }
2608
-        $this->_redirect_after_action(0, '', '', ['action' => 'default_event_settings'], true);
2609
-    }
2610
-
2611
-
2612
-    /*************        Templates        *************
2613
-     *
2614
-     * @throws EE_Error
2615
-     */
2616
-    protected function _template_settings()
2617
-    {
2618
-        $this->_admin_page_title              = esc_html__('Template Settings (Preview)', 'event_espresso');
2619
-        $this->_template_args['preview_img']  = '<img src="'
2620
-                                                . EVENTS_ASSETS_URL
2621
-                                                . '/images/'
2622
-                                                . 'caffeinated_template_features.jpg" alt="'
2623
-                                                . esc_attr__('Template Settings Preview screenshot', 'event_espresso')
2624
-                                                . '" />';
2625
-        $this->_template_args['preview_text'] = '<strong>'
2626
-                                                . esc_html__(
2627
-                                                    '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.',
2628
-                                                    'event_espresso'
2629
-                                                ) . '</strong>';
2630
-        $this->display_admin_caf_preview_page('template_settings_tab');
2631
-    }
2632
-
2633
-
2634
-    /** Event Category Stuff **/
2635
-    /**
2636
-     * set the _category property with the category object for the loaded page.
2637
-     *
2638
-     * @access private
2639
-     * @return void
2640
-     */
2641
-    private function _set_category_object()
2642
-    {
2643
-        if (isset($this->_category->id) && ! empty($this->_category->id)) {
2644
-            return;
2645
-        } //already have the category object so get out.
2646
-        // set default category object
2647
-        $this->_set_empty_category_object();
2648
-        // only set if we've got an id
2649
-        $category_ID = $this->request->getRequestParam('EVT_CAT_ID', 0, DataType::INT);
2650
-        if (! $category_ID) {
2651
-            return;
2652
-        }
2653
-        $term = get_term($category_ID, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY);
2654
-        if (! empty($term)) {
2655
-            $this->_category->category_name       = $term->name;
2656
-            $this->_category->category_identifier = $term->slug;
2657
-            $this->_category->category_desc       = $term->description;
2658
-            $this->_category->id                  = $term->term_id;
2659
-            $this->_category->parent              = $term->parent;
2660
-        }
2661
-    }
2662
-
2663
-
2664
-    /**
2665
-     * Clears out category properties.
2666
-     */
2667
-    private function _set_empty_category_object()
2668
-    {
2669
-        $this->_category                = new stdClass();
2670
-        $this->_category->category_name = $this->_category->category_identifier = $this->_category->category_desc = '';
2671
-        $this->_category->id            = $this->_category->parent = 0;
2672
-    }
2673
-
2674
-
2675
-    /**
2676
-     * @throws DomainException
2677
-     * @throws EE_Error
2678
-     * @throws InvalidArgumentException
2679
-     * @throws InvalidDataTypeException
2680
-     * @throws InvalidInterfaceException
2681
-     */
2682
-    protected function _category_list_table()
2683
-    {
2684
-        $this->_search_btn_label = esc_html__('Categories', 'event_espresso');
2685
-        $this->_admin_page_title .= ' ';
2686
-        $this->_admin_page_title .= $this->get_action_link_or_button(
2687
-            'add_category',
2688
-            'add_category',
2689
-            [],
2690
-            'add-new-h2'
2691
-        );
2692
-        $this->display_admin_list_table_page_with_sidebar();
2693
-    }
2694
-
2695
-
2696
-    /**
2697
-     * Output category details view.
2698
-     *
2699
-     * @throws EE_Error
2700
-     * @throws EE_Error
2701
-     */
2702
-    protected function _category_details($view)
2703
-    {
2704
-        $route = $view === 'edit' ? 'update_category' : 'insert_category';
2705
-        $this->_set_add_edit_form_tags($route);
2706
-        $this->_set_category_object();
2707
-        $id            = ! empty($this->_category->id) ? $this->_category->id : '';
2708
-        $delete_action = 'delete_category';
2709
-        // custom redirect
2710
-        $redirect = EE_Admin_Page::add_query_args_and_nonce(
2711
-            ['action' => 'category_list'],
2712
-            $this->_admin_base_url
2713
-        );
2714
-        $this->_set_publish_post_box_vars('EVT_CAT_ID', $id, $delete_action, $redirect);
2715
-        // take care of contents
2716
-        $this->_template_args['admin_page_content'] = $this->_category_details_content();
2717
-        $this->display_admin_page_with_sidebar();
2718
-    }
2719
-
2720
-
2721
-    /**
2722
-     * Output category details content.
2723
-     *
2724
-     * @throws DomainException
2725
-     */
2726
-    protected function _category_details_content(): string
2727
-    {
2728
-        $editor_args['category_desc'] = [
2729
-            'type'          => 'wp_editor',
2730
-            'value'         => EEH_Formatter::admin_format_content($this->_category->category_desc),
2731
-            'class'         => 'my_editor_custom',
2732
-            'wpeditor_args' => ['media_buttons' => false],
2733
-        ];
2734
-        $_wp_editor                   = $this->_generate_admin_form_fields($editor_args, 'array');
2735
-        $all_terms                    = get_terms(
2736
-            [EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY],
2737
-            ['hide_empty' => 0, 'exclude' => [$this->_category->id]]
2738
-        );
2739
-        // setup category select for term parents.
2740
-        $category_select_values[] = [
2741
-            'text' => esc_html__('No Parent', 'event_espresso'),
2742
-            'id'   => 0,
2743
-        ];
2744
-        foreach ($all_terms as $term) {
2745
-            $category_select_values[] = [
2746
-                'text' => $term->name,
2747
-                'id'   => $term->term_id,
2748
-            ];
2749
-        }
2750
-        $category_select = EEH_Form_Fields::select_input(
2751
-            'category_parent',
2752
-            $category_select_values,
2753
-            $this->_category->parent
2754
-        );
2755
-        $template_args   = [
2756
-            'category'                 => $this->_category,
2757
-            'category_select'          => $category_select,
2758
-            'unique_id_info_help_link' => $this->_get_help_tab_link('unique_id_info'),
2759
-            'category_desc_editor'     => $_wp_editor['category_desc']['field'],
2760
-            'disable'                  => '',
2761
-            'disabled_message'         => false,
2762
-        ];
2763
-        $template        = EVENTS_TEMPLATE_PATH . 'event_category_details.template.php';
2764
-        return EEH_Template::display_template($template, $template_args, true);
2765
-    }
2766
-
2767
-
2768
-    /**
2769
-     * Handles deleting categories.
2770
-     *
2771
-     * @throws EE_Error
2772
-     */
2773
-    protected function _delete_categories()
2774
-    {
2775
-        $category_IDs = $this->request->getRequestParam('EVT_CAT_ID', 0, 'int', true);
2776
-        foreach ($category_IDs as $category_ID) {
2777
-            $this->_delete_category($category_ID);
2778
-        }
2779
-        // doesn't matter what page we're coming from... we're going to the same place after delete.
2780
-        $query_args = [
2781
-            'action' => 'category_list',
2782
-        ];
2783
-        $this->_redirect_after_action(0, '', '', $query_args);
2784
-    }
2785
-
2786
-
2787
-    /**
2788
-     * Handles deleting specific category.
2789
-     *
2790
-     * @param int $cat_id
2791
-     */
2792
-    protected function _delete_category(int $cat_id)
2793
-    {
2794
-        $cat_id = absint($cat_id);
2795
-        wp_delete_term($cat_id, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY);
2796
-    }
2797
-
2798
-
2799
-    /**
2800
-     * Handles triggering the update or insertion of a new category.
2801
-     *
2802
-     * @param bool $new_category true means we're triggering the insert of a new category.
2803
-     * @throws EE_Error
2804
-     * @throws EE_Error
2805
-     */
2806
-    protected function _insert_or_update_category(bool $new_category)
2807
-    {
2808
-        $cat_id  = $this->_insert_category($new_category);
2809
-        $success = 0; // we already have a success message so lets not send another.
2810
-        if ($cat_id) {
2811
-            $query_args = [
2812
-                'action'     => 'edit_category',
2813
-                'EVT_CAT_ID' => $cat_id,
2814
-            ];
2815
-        } else {
2816
-            $query_args = ['action' => 'add_category'];
2817
-        }
2818
-        $this->_redirect_after_action($success, '', '', $query_args, true);
2819
-    }
2820
-
2821
-
2822
-    /**
2823
-     * Inserts or updates category
2824
-     *
2825
-     * @param bool $new_category (true indicates we're updating a category).
2826
-     * @return bool|mixed|string
2827
-     */
2828
-    private function _insert_category(bool $new_category)
2829
-    {
2830
-        $category_ID         = $this->request->getRequestParam('EVT_CAT_ID', 0, DataType::INT);
2831
-        $category_name       = $this->request->getRequestParam('category_name', '');
2832
-        $category_desc       = $this->request->getRequestParam('category_desc', '', DataType::HTML);
2833
-        $category_parent     = $this->request->getRequestParam('category_parent', 0, DataType::INT);
2834
-        $category_identifier = $this->request->getRequestParam('category_identifier', '');
2835
-
2836
-        if (empty($category_name)) {
2837
-            $msg = esc_html__('You must add a name for the category.', 'event_espresso');
2838
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2839
-            return 0;
2840
-        }
2841
-        $term_args = [
2842
-            'name'        => $category_name,
2843
-            'description' => $category_desc,
2844
-            'parent'      => $category_parent,
2845
-        ];
2846
-        // was the category_identifier input disabled?
2847
-        if ($category_identifier) {
2848
-            $term_args['slug'] = $category_identifier;
2849
-        }
2850
-        $insert_ids = $new_category
2851
-            ? wp_insert_term($category_name, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY, $term_args)
2852
-            : wp_update_term($category_ID, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY, $term_args);
2853
-
2854
-        if ($insert_ids instanceof WP_Error) {
2855
-            EE_Error::add_error($insert_ids->get_error_message(), __FILE__, __FUNCTION__, __LINE__);
2856
-            return 0;
2857
-        }
2858
-        $category_ID = $insert_ids['term_id'] ?? 0;
2859
-        if (! $category_ID) {
2860
-            EE_Error::add_error(
2861
-                esc_html__(
2862
-                    'An error occurred and the category has not been saved to the database.',
2863
-                    'event_espresso'
2864
-                ),
2865
-                __FILE__,
2866
-                __FUNCTION__,
2867
-                __LINE__
2868
-            );
2869
-            return 0;
2870
-        }
2871
-        EE_Error::add_success(
2872
-            sprintf(
2873
-                esc_html__('The category %s was successfully saved', 'event_espresso'),
2874
-                $category_name
2875
-            )
2876
-        );
2877
-        return $category_ID;
2878
-    }
2879
-
2880
-
2881
-    /**
2882
-     * Gets categories or count of categories matching the arguments in the request.
2883
-     *
2884
-     * @param int  $per_page
2885
-     * @param int  $current_page
2886
-     * @param bool $count
2887
-     * @return EE_Term_Taxonomy[]|int
2888
-     * @throws EE_Error
2889
-     * @throws ReflectionException
2890
-     */
2891
-    public function get_categories(int $per_page = 10, int $current_page = 1, bool $count = false)
2892
-    {
2893
-        // testing term stuff
2894
-        $orderby     = $this->request->getRequestParam('orderby', 'Term.term_id');
2895
-        $order       = $this->request->getRequestParam('order', 'DESC');
2896
-        $limit       = ($current_page - 1) * $per_page;
2897
-        $where       = ['taxonomy' => EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY];
2898
-        $search_term = $this->request->getRequestParam('s');
2899
-        if ($search_term) {
2900
-            $search_term = '%' . $search_term . '%';
2901
-            $where['OR'] = [
2902
-                'Term.name'   => ['LIKE', $search_term],
2903
-                'description' => ['LIKE', $search_term],
2904
-            ];
2905
-        }
2906
-        $query_params = [
2907
-            $where,
2908
-            'order_by'   => [$orderby => $order],
2909
-            'limit'      => $limit . ',' . $per_page,
2910
-            'force_join' => ['Term'],
2911
-        ];
2912
-        return $count
2913
-            ? EEM_Term_Taxonomy::instance()->count($query_params, 'term_id')
2914
-            : EEM_Term_Taxonomy::instance()->get_all($query_params);
2915
-    }
2916
-
2917
-    /* end category stuff */
2918
-
2919
-
2920
-    /**************/
2921
-
2922
-
2923
-    /**
2924
-     * Callback for the `ee_save_timezone_setting` ajax action.
2925
-     *
2926
-     * @throws EE_Error
2927
-     * @throws InvalidArgumentException
2928
-     * @throws InvalidDataTypeException
2929
-     * @throws InvalidInterfaceException
2930
-     */
2931
-    public function saveTimezoneString()
2932
-    {
2933
-        $timezone_string = $this->request->getRequestParam('timezone_selected');
2934
-        if (empty($timezone_string) || ! EEH_DTT_Helper::validate_timezone($timezone_string, false)) {
2935
-            EE_Error::add_error(
2936
-                esc_html__('An invalid timezone string submitted.', 'event_espresso'),
2937
-                __FILE__,
2938
-                __FUNCTION__,
2939
-                __LINE__
2940
-            );
2941
-            $this->_template_args['error'] = true;
2942
-            $this->_return_json();
2943
-        }
2944
-
2945
-        update_option('timezone_string', $timezone_string);
2946
-        EE_Error::add_success(
2947
-            esc_html__('Your timezone string was updated.', 'event_espresso')
2948
-        );
2949
-        $this->_template_args['success'] = true;
2950
-        $this->_return_json(true, ['action' => 'create_new']);
2951
-    }
2952
-
2953
-
2954
-    /**
2955 2614
      * @throws EE_Error
2956
-     * @deprecated 4.10.25.p
2957 2615
      */
2958
-    public function save_timezonestring_setting()
2959
-    {
2960
-        $this->saveTimezoneString();
2961
-    }
2616
+	protected function _template_settings()
2617
+	{
2618
+		$this->_admin_page_title              = esc_html__('Template Settings (Preview)', 'event_espresso');
2619
+		$this->_template_args['preview_img']  = '<img src="'
2620
+												. EVENTS_ASSETS_URL
2621
+												. '/images/'
2622
+												. 'caffeinated_template_features.jpg" alt="'
2623
+												. esc_attr__('Template Settings Preview screenshot', 'event_espresso')
2624
+												. '" />';
2625
+		$this->_template_args['preview_text'] = '<strong>'
2626
+												. esc_html__(
2627
+													'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.',
2628
+													'event_espresso'
2629
+												) . '</strong>';
2630
+		$this->display_admin_caf_preview_page('template_settings_tab');
2631
+	}
2632
+
2633
+
2634
+	/** Event Category Stuff **/
2635
+	/**
2636
+	 * set the _category property with the category object for the loaded page.
2637
+	 *
2638
+	 * @access private
2639
+	 * @return void
2640
+	 */
2641
+	private function _set_category_object()
2642
+	{
2643
+		if (isset($this->_category->id) && ! empty($this->_category->id)) {
2644
+			return;
2645
+		} //already have the category object so get out.
2646
+		// set default category object
2647
+		$this->_set_empty_category_object();
2648
+		// only set if we've got an id
2649
+		$category_ID = $this->request->getRequestParam('EVT_CAT_ID', 0, DataType::INT);
2650
+		if (! $category_ID) {
2651
+			return;
2652
+		}
2653
+		$term = get_term($category_ID, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY);
2654
+		if (! empty($term)) {
2655
+			$this->_category->category_name       = $term->name;
2656
+			$this->_category->category_identifier = $term->slug;
2657
+			$this->_category->category_desc       = $term->description;
2658
+			$this->_category->id                  = $term->term_id;
2659
+			$this->_category->parent              = $term->parent;
2660
+		}
2661
+	}
2662
+
2663
+
2664
+	/**
2665
+	 * Clears out category properties.
2666
+	 */
2667
+	private function _set_empty_category_object()
2668
+	{
2669
+		$this->_category                = new stdClass();
2670
+		$this->_category->category_name = $this->_category->category_identifier = $this->_category->category_desc = '';
2671
+		$this->_category->id            = $this->_category->parent = 0;
2672
+	}
2673
+
2674
+
2675
+	/**
2676
+	 * @throws DomainException
2677
+	 * @throws EE_Error
2678
+	 * @throws InvalidArgumentException
2679
+	 * @throws InvalidDataTypeException
2680
+	 * @throws InvalidInterfaceException
2681
+	 */
2682
+	protected function _category_list_table()
2683
+	{
2684
+		$this->_search_btn_label = esc_html__('Categories', 'event_espresso');
2685
+		$this->_admin_page_title .= ' ';
2686
+		$this->_admin_page_title .= $this->get_action_link_or_button(
2687
+			'add_category',
2688
+			'add_category',
2689
+			[],
2690
+			'add-new-h2'
2691
+		);
2692
+		$this->display_admin_list_table_page_with_sidebar();
2693
+	}
2694
+
2695
+
2696
+	/**
2697
+	 * Output category details view.
2698
+	 *
2699
+	 * @throws EE_Error
2700
+	 * @throws EE_Error
2701
+	 */
2702
+	protected function _category_details($view)
2703
+	{
2704
+		$route = $view === 'edit' ? 'update_category' : 'insert_category';
2705
+		$this->_set_add_edit_form_tags($route);
2706
+		$this->_set_category_object();
2707
+		$id            = ! empty($this->_category->id) ? $this->_category->id : '';
2708
+		$delete_action = 'delete_category';
2709
+		// custom redirect
2710
+		$redirect = EE_Admin_Page::add_query_args_and_nonce(
2711
+			['action' => 'category_list'],
2712
+			$this->_admin_base_url
2713
+		);
2714
+		$this->_set_publish_post_box_vars('EVT_CAT_ID', $id, $delete_action, $redirect);
2715
+		// take care of contents
2716
+		$this->_template_args['admin_page_content'] = $this->_category_details_content();
2717
+		$this->display_admin_page_with_sidebar();
2718
+	}
2719
+
2720
+
2721
+	/**
2722
+	 * Output category details content.
2723
+	 *
2724
+	 * @throws DomainException
2725
+	 */
2726
+	protected function _category_details_content(): string
2727
+	{
2728
+		$editor_args['category_desc'] = [
2729
+			'type'          => 'wp_editor',
2730
+			'value'         => EEH_Formatter::admin_format_content($this->_category->category_desc),
2731
+			'class'         => 'my_editor_custom',
2732
+			'wpeditor_args' => ['media_buttons' => false],
2733
+		];
2734
+		$_wp_editor                   = $this->_generate_admin_form_fields($editor_args, 'array');
2735
+		$all_terms                    = get_terms(
2736
+			[EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY],
2737
+			['hide_empty' => 0, 'exclude' => [$this->_category->id]]
2738
+		);
2739
+		// setup category select for term parents.
2740
+		$category_select_values[] = [
2741
+			'text' => esc_html__('No Parent', 'event_espresso'),
2742
+			'id'   => 0,
2743
+		];
2744
+		foreach ($all_terms as $term) {
2745
+			$category_select_values[] = [
2746
+				'text' => $term->name,
2747
+				'id'   => $term->term_id,
2748
+			];
2749
+		}
2750
+		$category_select = EEH_Form_Fields::select_input(
2751
+			'category_parent',
2752
+			$category_select_values,
2753
+			$this->_category->parent
2754
+		);
2755
+		$template_args   = [
2756
+			'category'                 => $this->_category,
2757
+			'category_select'          => $category_select,
2758
+			'unique_id_info_help_link' => $this->_get_help_tab_link('unique_id_info'),
2759
+			'category_desc_editor'     => $_wp_editor['category_desc']['field'],
2760
+			'disable'                  => '',
2761
+			'disabled_message'         => false,
2762
+		];
2763
+		$template        = EVENTS_TEMPLATE_PATH . 'event_category_details.template.php';
2764
+		return EEH_Template::display_template($template, $template_args, true);
2765
+	}
2766
+
2767
+
2768
+	/**
2769
+	 * Handles deleting categories.
2770
+	 *
2771
+	 * @throws EE_Error
2772
+	 */
2773
+	protected function _delete_categories()
2774
+	{
2775
+		$category_IDs = $this->request->getRequestParam('EVT_CAT_ID', 0, 'int', true);
2776
+		foreach ($category_IDs as $category_ID) {
2777
+			$this->_delete_category($category_ID);
2778
+		}
2779
+		// doesn't matter what page we're coming from... we're going to the same place after delete.
2780
+		$query_args = [
2781
+			'action' => 'category_list',
2782
+		];
2783
+		$this->_redirect_after_action(0, '', '', $query_args);
2784
+	}
2785
+
2786
+
2787
+	/**
2788
+	 * Handles deleting specific category.
2789
+	 *
2790
+	 * @param int $cat_id
2791
+	 */
2792
+	protected function _delete_category(int $cat_id)
2793
+	{
2794
+		$cat_id = absint($cat_id);
2795
+		wp_delete_term($cat_id, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY);
2796
+	}
2797
+
2798
+
2799
+	/**
2800
+	 * Handles triggering the update or insertion of a new category.
2801
+	 *
2802
+	 * @param bool $new_category true means we're triggering the insert of a new category.
2803
+	 * @throws EE_Error
2804
+	 * @throws EE_Error
2805
+	 */
2806
+	protected function _insert_or_update_category(bool $new_category)
2807
+	{
2808
+		$cat_id  = $this->_insert_category($new_category);
2809
+		$success = 0; // we already have a success message so lets not send another.
2810
+		if ($cat_id) {
2811
+			$query_args = [
2812
+				'action'     => 'edit_category',
2813
+				'EVT_CAT_ID' => $cat_id,
2814
+			];
2815
+		} else {
2816
+			$query_args = ['action' => 'add_category'];
2817
+		}
2818
+		$this->_redirect_after_action($success, '', '', $query_args, true);
2819
+	}
2820
+
2821
+
2822
+	/**
2823
+	 * Inserts or updates category
2824
+	 *
2825
+	 * @param bool $new_category (true indicates we're updating a category).
2826
+	 * @return bool|mixed|string
2827
+	 */
2828
+	private function _insert_category(bool $new_category)
2829
+	{
2830
+		$category_ID         = $this->request->getRequestParam('EVT_CAT_ID', 0, DataType::INT);
2831
+		$category_name       = $this->request->getRequestParam('category_name', '');
2832
+		$category_desc       = $this->request->getRequestParam('category_desc', '', DataType::HTML);
2833
+		$category_parent     = $this->request->getRequestParam('category_parent', 0, DataType::INT);
2834
+		$category_identifier = $this->request->getRequestParam('category_identifier', '');
2835
+
2836
+		if (empty($category_name)) {
2837
+			$msg = esc_html__('You must add a name for the category.', 'event_espresso');
2838
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2839
+			return 0;
2840
+		}
2841
+		$term_args = [
2842
+			'name'        => $category_name,
2843
+			'description' => $category_desc,
2844
+			'parent'      => $category_parent,
2845
+		];
2846
+		// was the category_identifier input disabled?
2847
+		if ($category_identifier) {
2848
+			$term_args['slug'] = $category_identifier;
2849
+		}
2850
+		$insert_ids = $new_category
2851
+			? wp_insert_term($category_name, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY, $term_args)
2852
+			: wp_update_term($category_ID, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY, $term_args);
2853
+
2854
+		if ($insert_ids instanceof WP_Error) {
2855
+			EE_Error::add_error($insert_ids->get_error_message(), __FILE__, __FUNCTION__, __LINE__);
2856
+			return 0;
2857
+		}
2858
+		$category_ID = $insert_ids['term_id'] ?? 0;
2859
+		if (! $category_ID) {
2860
+			EE_Error::add_error(
2861
+				esc_html__(
2862
+					'An error occurred and the category has not been saved to the database.',
2863
+					'event_espresso'
2864
+				),
2865
+				__FILE__,
2866
+				__FUNCTION__,
2867
+				__LINE__
2868
+			);
2869
+			return 0;
2870
+		}
2871
+		EE_Error::add_success(
2872
+			sprintf(
2873
+				esc_html__('The category %s was successfully saved', 'event_espresso'),
2874
+				$category_name
2875
+			)
2876
+		);
2877
+		return $category_ID;
2878
+	}
2879
+
2880
+
2881
+	/**
2882
+	 * Gets categories or count of categories matching the arguments in the request.
2883
+	 *
2884
+	 * @param int  $per_page
2885
+	 * @param int  $current_page
2886
+	 * @param bool $count
2887
+	 * @return EE_Term_Taxonomy[]|int
2888
+	 * @throws EE_Error
2889
+	 * @throws ReflectionException
2890
+	 */
2891
+	public function get_categories(int $per_page = 10, int $current_page = 1, bool $count = false)
2892
+	{
2893
+		// testing term stuff
2894
+		$orderby     = $this->request->getRequestParam('orderby', 'Term.term_id');
2895
+		$order       = $this->request->getRequestParam('order', 'DESC');
2896
+		$limit       = ($current_page - 1) * $per_page;
2897
+		$where       = ['taxonomy' => EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY];
2898
+		$search_term = $this->request->getRequestParam('s');
2899
+		if ($search_term) {
2900
+			$search_term = '%' . $search_term . '%';
2901
+			$where['OR'] = [
2902
+				'Term.name'   => ['LIKE', $search_term],
2903
+				'description' => ['LIKE', $search_term],
2904
+			];
2905
+		}
2906
+		$query_params = [
2907
+			$where,
2908
+			'order_by'   => [$orderby => $order],
2909
+			'limit'      => $limit . ',' . $per_page,
2910
+			'force_join' => ['Term'],
2911
+		];
2912
+		return $count
2913
+			? EEM_Term_Taxonomy::instance()->count($query_params, 'term_id')
2914
+			: EEM_Term_Taxonomy::instance()->get_all($query_params);
2915
+	}
2916
+
2917
+	/* end category stuff */
2918
+
2919
+
2920
+	/**************/
2921
+
2922
+
2923
+	/**
2924
+	 * Callback for the `ee_save_timezone_setting` ajax action.
2925
+	 *
2926
+	 * @throws EE_Error
2927
+	 * @throws InvalidArgumentException
2928
+	 * @throws InvalidDataTypeException
2929
+	 * @throws InvalidInterfaceException
2930
+	 */
2931
+	public function saveTimezoneString()
2932
+	{
2933
+		$timezone_string = $this->request->getRequestParam('timezone_selected');
2934
+		if (empty($timezone_string) || ! EEH_DTT_Helper::validate_timezone($timezone_string, false)) {
2935
+			EE_Error::add_error(
2936
+				esc_html__('An invalid timezone string submitted.', 'event_espresso'),
2937
+				__FILE__,
2938
+				__FUNCTION__,
2939
+				__LINE__
2940
+			);
2941
+			$this->_template_args['error'] = true;
2942
+			$this->_return_json();
2943
+		}
2944
+
2945
+		update_option('timezone_string', $timezone_string);
2946
+		EE_Error::add_success(
2947
+			esc_html__('Your timezone string was updated.', 'event_espresso')
2948
+		);
2949
+		$this->_template_args['success'] = true;
2950
+		$this->_return_json(true, ['action' => 'create_new']);
2951
+	}
2952
+
2953
+
2954
+	/**
2955
+	 * @throws EE_Error
2956
+	 * @deprecated 4.10.25.p
2957
+	 */
2958
+	public function save_timezonestring_setting()
2959
+	{
2960
+		$this->saveTimezoneString();
2961
+	}
2962 2962
 }
Please login to merge, or discard this patch.
admin_pages/registrations/Registrations_Admin_Page.core.php 1 patch
Indentation   +3662 added lines, -3662 removed lines patch added patch discarded remove patch
@@ -21,2207 +21,2207 @@  discard block
 block discarded – undo
21 21
  */
22 22
 class Registrations_Admin_Page extends EE_Admin_Page_CPT
23 23
 {
24
-    /**
25
-     * @var EE_Registration
26
-     */
27
-    private $_registration;
28
-
29
-    /**
30
-     * @var EE_Event
31
-     */
32
-    private $_reg_event;
33
-
34
-    /**
35
-     * @var EE_Session
36
-     */
37
-    private $_session;
38
-
39
-    /**
40
-     * @var array
41
-     */
42
-    private static $_reg_status;
43
-
44
-    /**
45
-     * Form for displaying the custom questions for this registration.
46
-     * This gets used a few times throughout the request so its best to cache it
47
-     *
48
-     * @var EE_Registration_Custom_Questions_Form
49
-     */
50
-    protected $_reg_custom_questions_form;
51
-
52
-    /**
53
-     * @var EEM_Registration $registration_model
54
-     */
55
-    private $registration_model;
56
-
57
-    /**
58
-     * @var EEM_Attendee $attendee_model
59
-     */
60
-    private $attendee_model;
61
-
62
-    /**
63
-     * @var EEM_Event $event_model
64
-     */
65
-    private $event_model;
66
-
67
-    /**
68
-     * @var EEM_Status $status_model
69
-     */
70
-    private $status_model;
71
-
72
-
73
-    /**
74
-     * @param bool $routing
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
-        $this->cpt_editpost_route = 'edit_attendee';
84
-        add_action('wp_loaded', [$this, 'wp_loaded']);
85
-    }
86
-
87
-
88
-    /**
89
-     * @return EEM_Registration
90
-     * @throws InvalidArgumentException
91
-     * @throws InvalidDataTypeException
92
-     * @throws InvalidInterfaceException
93
-     * @since 4.10.2.p
94
-     */
95
-    protected function getRegistrationModel()
96
-    {
97
-        if (! $this->registration_model instanceof EEM_Registration) {
98
-            $this->registration_model = $this->loader->getShared('EEM_Registration');
99
-        }
100
-        return $this->registration_model;
101
-    }
102
-
103
-
104
-    /**
105
-     * @return EEM_Attendee
106
-     * @throws InvalidArgumentException
107
-     * @throws InvalidDataTypeException
108
-     * @throws InvalidInterfaceException
109
-     * @since 4.10.2.p
110
-     */
111
-    protected function getAttendeeModel()
112
-    {
113
-        if (! $this->attendee_model instanceof EEM_Attendee) {
114
-            $this->attendee_model = $this->loader->getShared('EEM_Attendee');
115
-        }
116
-        return $this->attendee_model;
117
-    }
118
-
119
-
120
-    /**
121
-     * @return EEM_Event
122
-     * @throws InvalidArgumentException
123
-     * @throws InvalidDataTypeException
124
-     * @throws InvalidInterfaceException
125
-     * @since 4.10.2.p
126
-     */
127
-    protected function getEventModel()
128
-    {
129
-        if (! $this->event_model instanceof EEM_Event) {
130
-            $this->event_model = $this->loader->getShared('EEM_Event');
131
-        }
132
-        return $this->event_model;
133
-    }
134
-
135
-
136
-    /**
137
-     * @return EEM_Status
138
-     * @throws InvalidArgumentException
139
-     * @throws InvalidDataTypeException
140
-     * @throws InvalidInterfaceException
141
-     * @since 4.10.2.p
142
-     */
143
-    protected function getStatusModel()
144
-    {
145
-        if (! $this->status_model instanceof EEM_Status) {
146
-            $this->status_model = $this->loader->getShared('EEM_Status');
147
-        }
148
-        return $this->status_model;
149
-    }
150
-
151
-
152
-    public function wp_loaded()
153
-    {
154
-        // when adding a new registration...
155
-        $action = $this->request->getRequestParam('action');
156
-        if ($action === 'new_registration') {
157
-            EE_System::do_not_cache();
158
-            if ($this->request->getRequestParam('processing_registration', 0, 'int') !== 1) {
159
-                // and it's NOT the attendee information reg step
160
-                // force cookie expiration by setting time to last week
161
-                setcookie('ee_registration_added', 0, time() - WEEK_IN_SECONDS, '/');
162
-                // and update the global
163
-                $_COOKIE['ee_registration_added'] = 0;
164
-            }
165
-        }
166
-    }
167
-
168
-
169
-    protected function _init_page_props()
170
-    {
171
-        $this->page_slug        = REG_PG_SLUG;
172
-        $this->_admin_base_url  = REG_ADMIN_URL;
173
-        $this->_admin_base_path = REG_ADMIN;
174
-        $this->page_label       = esc_html__('Registrations', 'event_espresso');
175
-        $this->_cpt_routes      = [
176
-            'add_new_attendee' => 'espresso_attendees',
177
-            'edit_attendee'    => 'espresso_attendees',
178
-            'insert_attendee'  => 'espresso_attendees',
179
-            'update_attendee'  => 'espresso_attendees',
180
-        ];
181
-        $this->_cpt_model_names = [
182
-            'add_new_attendee' => 'EEM_Attendee',
183
-            'edit_attendee'    => 'EEM_Attendee',
184
-        ];
185
-        $this->_cpt_edit_routes = [
186
-            'espresso_attendees' => 'edit_attendee',
187
-        ];
188
-        $this->_pagenow_map     = [
189
-            'add_new_attendee' => 'post-new.php',
190
-            'edit_attendee'    => 'post.php',
191
-            'trash'            => 'post.php',
192
-        ];
193
-        add_action('edit_form_after_title', [$this, 'after_title_form_fields'], 10);
194
-        // add filters so that the comment urls don't take users to a confusing 404 page
195
-        add_filter('get_comment_link', [$this, 'clear_comment_link'], 10, 2);
196
-    }
197
-
198
-
199
-    /**
200
-     * @param string     $link    The comment permalink with '#comment-$id' appended.
201
-     * @param WP_Comment $comment The current comment object.
202
-     * @return string
203
-     */
204
-    public function clear_comment_link($link, WP_Comment $comment)
205
-    {
206
-        // gotta make sure this only happens on this route
207
-        $post_type = get_post_type($comment->comment_post_ID);
208
-        if ($post_type === 'espresso_attendees') {
209
-            return '#commentsdiv';
210
-        }
211
-        return $link;
212
-    }
213
-
214
-
215
-    protected function _ajax_hooks()
216
-    {
217
-        // todo: all hooks for registrations ajax goes in here
218
-        add_action('wp_ajax_toggle_checkin_status', [$this, 'toggle_checkin_status']);
219
-    }
220
-
221
-
222
-    protected function _define_page_props()
223
-    {
224
-        $this->_admin_page_title = $this->page_label;
225
-        $this->_labels           = [
226
-            'buttons'                      => [
227
-                'add-registrant'      => esc_html__('Add New Registration', 'event_espresso'),
228
-                'add-attendee'        => esc_html__('Add Contact', 'event_espresso'),
229
-                'edit'                => esc_html__('Edit Contact', 'event_espresso'),
230
-                'csv_reg_report'      => esc_html__('Registrations CSV Report', 'event_espresso'),
231
-                'contact_list_report' => esc_html__('Contact List Report', 'event_espresso'),
232
-                'contact_list_export' => esc_html__('Export Data', 'event_espresso'),
233
-            ],
234
-            'publishbox'                   => [
235
-                'add_new_attendee' => esc_html__('Add Contact Record', 'event_espresso'),
236
-                'edit_attendee'    => esc_html__('Update Contact Record', 'event_espresso'),
237
-            ],
238
-            'hide_add_button_on_cpt_route' => [
239
-                'edit_attendee' => true,
240
-            ],
241
-        ];
242
-    }
243
-
244
-
245
-    /**
246
-     * grab url requests and route them
247
-     *
248
-     * @return void
249
-     * @throws EE_Error
250
-     */
251
-    public function _set_page_routes()
252
-    {
253
-        $this->_get_registration_status_array();
254
-        $REG_ID             = $this->request->getRequestParam('_REG_ID', 0, 'int');
255
-        $REG_ID             = $this->request->getRequestParam('reg_status_change_form[REG_ID]', $REG_ID, 'int');
256
-        $ATT_ID             = $this->request->getRequestParam('ATT_ID', 0, 'int');
257
-        $ATT_ID             = $this->request->getRequestParam('post', $ATT_ID, 'int');
258
-        $this->_page_routes = [
259
-            'default'                             => [
260
-                'func'       => [$this, '_registrations_overview_list_table'],
261
-                'capability' => 'ee_read_registrations',
262
-            ],
263
-            'view_registration'                   => [
264
-                'func'       => [$this, '_registration_details'],
265
-                'capability' => 'ee_read_registration',
266
-                'obj_id'     => $REG_ID,
267
-            ],
268
-            'edit_registration'                   => [
269
-                'func'               => '_update_attendee_registration_form',
270
-                'noheader'           => true,
271
-                'headers_sent_route' => 'view_registration',
272
-                'capability'         => 'ee_edit_registration',
273
-                'obj_id'             => $REG_ID,
274
-                '_REG_ID'            => $REG_ID,
275
-            ],
276
-            'trash_registrations'                 => [
277
-                'func'       => '_trash_or_restore_registrations',
278
-                'args'       => ['trash' => true],
279
-                'noheader'   => true,
280
-                'capability' => 'ee_delete_registrations',
281
-            ],
282
-            'restore_registrations'               => [
283
-                'func'       => '_trash_or_restore_registrations',
284
-                'args'       => ['trash' => false],
285
-                'noheader'   => true,
286
-                'capability' => 'ee_delete_registrations',
287
-            ],
288
-            'delete_registrations'                => [
289
-                'func'       => '_delete_registrations',
290
-                'noheader'   => true,
291
-                'capability' => 'ee_delete_registrations',
292
-            ],
293
-            'new_registration'                    => [
294
-                'func'       => 'new_registration',
295
-                'capability' => 'ee_edit_registrations',
296
-            ],
297
-            'process_reg_step'                    => [
298
-                'func'       => 'process_reg_step',
299
-                'noheader'   => true,
300
-                'capability' => 'ee_edit_registrations',
301
-            ],
302
-            'redirect_to_txn'                     => [
303
-                'func'       => 'redirect_to_txn',
304
-                'noheader'   => true,
305
-                'capability' => 'ee_edit_registrations',
306
-            ],
307
-            'change_reg_status'                   => [
308
-                'func'       => '_change_reg_status',
309
-                'noheader'   => true,
310
-                'capability' => 'ee_edit_registration',
311
-                'obj_id'     => $REG_ID,
312
-            ],
313
-            'approve_registration'                => [
314
-                'func'       => 'approve_registration',
315
-                'noheader'   => true,
316
-                'capability' => 'ee_edit_registration',
317
-                'obj_id'     => $REG_ID,
318
-            ],
319
-            'approve_and_notify_registration'     => [
320
-                'func'       => 'approve_registration',
321
-                'noheader'   => true,
322
-                'args'       => [true],
323
-                'capability' => 'ee_edit_registration',
324
-                'obj_id'     => $REG_ID,
325
-            ],
326
-            'approve_registrations'               => [
327
-                'func'       => 'bulk_action_on_registrations',
328
-                'noheader'   => true,
329
-                'capability' => 'ee_edit_registrations',
330
-                'args'       => ['approve'],
331
-            ],
332
-            'approve_and_notify_registrations'    => [
333
-                'func'       => 'bulk_action_on_registrations',
334
-                'noheader'   => true,
335
-                'capability' => 'ee_edit_registrations',
336
-                'args'       => ['approve', true],
337
-            ],
338
-            'decline_registration'                => [
339
-                'func'       => 'decline_registration',
340
-                'noheader'   => true,
341
-                'capability' => 'ee_edit_registration',
342
-                'obj_id'     => $REG_ID,
343
-            ],
344
-            'decline_and_notify_registration'     => [
345
-                'func'       => 'decline_registration',
346
-                'noheader'   => true,
347
-                'args'       => [true],
348
-                'capability' => 'ee_edit_registration',
349
-                'obj_id'     => $REG_ID,
350
-            ],
351
-            'decline_registrations'               => [
352
-                'func'       => 'bulk_action_on_registrations',
353
-                'noheader'   => true,
354
-                'capability' => 'ee_edit_registrations',
355
-                'args'       => ['decline'],
356
-            ],
357
-            'decline_and_notify_registrations'    => [
358
-                'func'       => 'bulk_action_on_registrations',
359
-                'noheader'   => true,
360
-                'capability' => 'ee_edit_registrations',
361
-                'args'       => ['decline', true],
362
-            ],
363
-            'pending_registration'                => [
364
-                'func'       => 'pending_registration',
365
-                'noheader'   => true,
366
-                'capability' => 'ee_edit_registration',
367
-                'obj_id'     => $REG_ID,
368
-            ],
369
-            'pending_and_notify_registration'     => [
370
-                'func'       => 'pending_registration',
371
-                'noheader'   => true,
372
-                'args'       => [true],
373
-                'capability' => 'ee_edit_registration',
374
-                'obj_id'     => $REG_ID,
375
-            ],
376
-            'pending_registrations'               => [
377
-                'func'       => 'bulk_action_on_registrations',
378
-                'noheader'   => true,
379
-                'capability' => 'ee_edit_registrations',
380
-                'args'       => ['pending'],
381
-            ],
382
-            'pending_and_notify_registrations'    => [
383
-                'func'       => 'bulk_action_on_registrations',
384
-                'noheader'   => true,
385
-                'capability' => 'ee_edit_registrations',
386
-                'args'       => ['pending', true],
387
-            ],
388
-            'no_approve_registration'             => [
389
-                'func'       => 'not_approve_registration',
390
-                'noheader'   => true,
391
-                'capability' => 'ee_edit_registration',
392
-                'obj_id'     => $REG_ID,
393
-            ],
394
-            'no_approve_and_notify_registration'  => [
395
-                'func'       => 'not_approve_registration',
396
-                'noheader'   => true,
397
-                'args'       => [true],
398
-                'capability' => 'ee_edit_registration',
399
-                'obj_id'     => $REG_ID,
400
-            ],
401
-            'no_approve_registrations'            => [
402
-                'func'       => 'bulk_action_on_registrations',
403
-                'noheader'   => true,
404
-                'capability' => 'ee_edit_registrations',
405
-                'args'       => ['not_approve'],
406
-            ],
407
-            'no_approve_and_notify_registrations' => [
408
-                'func'       => 'bulk_action_on_registrations',
409
-                'noheader'   => true,
410
-                'capability' => 'ee_edit_registrations',
411
-                'args'       => ['not_approve', true],
412
-            ],
413
-            'cancel_registration'                 => [
414
-                'func'       => 'cancel_registration',
415
-                'noheader'   => true,
416
-                'capability' => 'ee_edit_registration',
417
-                'obj_id'     => $REG_ID,
418
-            ],
419
-            'cancel_and_notify_registration'      => [
420
-                'func'       => 'cancel_registration',
421
-                'noheader'   => true,
422
-                'args'       => [true],
423
-                'capability' => 'ee_edit_registration',
424
-                'obj_id'     => $REG_ID,
425
-            ],
426
-            'cancel_registrations'                => [
427
-                'func'       => 'bulk_action_on_registrations',
428
-                'noheader'   => true,
429
-                'capability' => 'ee_edit_registrations',
430
-                'args'       => ['cancel'],
431
-            ],
432
-            'cancel_and_notify_registrations'     => [
433
-                'func'       => 'bulk_action_on_registrations',
434
-                'noheader'   => true,
435
-                'capability' => 'ee_edit_registrations',
436
-                'args'       => ['cancel', true],
437
-            ],
438
-            'wait_list_registration'              => [
439
-                'func'       => 'wait_list_registration',
440
-                'noheader'   => true,
441
-                'capability' => 'ee_edit_registration',
442
-                'obj_id'     => $REG_ID,
443
-            ],
444
-            'wait_list_and_notify_registration'   => [
445
-                'func'       => 'wait_list_registration',
446
-                'noheader'   => true,
447
-                'args'       => [true],
448
-                'capability' => 'ee_edit_registration',
449
-                'obj_id'     => $REG_ID,
450
-            ],
451
-            'contact_list'                        => [
452
-                'func'       => '_attendee_contact_list_table',
453
-                'capability' => 'ee_read_contacts',
454
-            ],
455
-            'add_new_attendee'                    => [
456
-                'func' => '_create_new_cpt_item',
457
-                'args' => [
458
-                    'new_attendee' => true,
459
-                    'capability'   => 'ee_edit_contacts',
460
-                ],
461
-            ],
462
-            'edit_attendee'                       => [
463
-                'func'       => '_edit_cpt_item',
464
-                'capability' => 'ee_edit_contacts',
465
-                'obj_id'     => $ATT_ID,
466
-            ],
467
-            'duplicate_attendee'                  => [
468
-                'func'       => '_duplicate_attendee',
469
-                'noheader'   => true,
470
-                'capability' => 'ee_edit_contacts',
471
-                'obj_id'     => $ATT_ID,
472
-            ],
473
-            'insert_attendee'                     => [
474
-                'func'       => '_insert_or_update_attendee',
475
-                'args'       => [
476
-                    'new_attendee' => true,
477
-                ],
478
-                'noheader'   => true,
479
-                'capability' => 'ee_edit_contacts',
480
-            ],
481
-            'update_attendee'                     => [
482
-                'func'       => '_insert_or_update_attendee',
483
-                'args'       => [
484
-                    'new_attendee' => false,
485
-                ],
486
-                'noheader'   => true,
487
-                'capability' => 'ee_edit_contacts',
488
-                'obj_id'     => $ATT_ID,
489
-            ],
490
-            'trash_attendees'                     => [
491
-                'func'       => '_trash_or_restore_attendees',
492
-                'args'       => [
493
-                    'trash' => 'true',
494
-                ],
495
-                'noheader'   => true,
496
-                'capability' => 'ee_delete_contacts',
497
-            ],
498
-            'trash_attendee'                      => [
499
-                'func'       => '_trash_or_restore_attendees',
500
-                'args'       => [
501
-                    'trash' => true,
502
-                ],
503
-                'noheader'   => true,
504
-                'capability' => 'ee_delete_contacts',
505
-                'obj_id'     => $ATT_ID,
506
-            ],
507
-            'restore_attendees'                   => [
508
-                'func'       => '_trash_or_restore_attendees',
509
-                'args'       => [
510
-                    'trash' => false,
511
-                ],
512
-                'noheader'   => true,
513
-                'capability' => 'ee_delete_contacts',
514
-                'obj_id'     => $ATT_ID,
515
-            ],
516
-            'resend_registration'                 => [
517
-                'func'       => '_resend_registration',
518
-                'noheader'   => true,
519
-                'capability' => 'ee_send_message',
520
-            ],
521
-            'registrations_report'                => [
522
-                'func'       => [$this, '_registrations_report'],
523
-                'noheader'   => true,
524
-                'capability' => 'ee_read_registrations',
525
-            ],
526
-            'contact_list_export'                 => [
527
-                'func'       => '_contact_list_export',
528
-                'noheader'   => true,
529
-                'capability' => 'export',
530
-            ],
531
-            'contact_list_report'                 => [
532
-                'func'       => '_contact_list_report',
533
-                'noheader'   => true,
534
-                'capability' => 'ee_read_contacts',
535
-            ],
536
-        ];
537
-    }
538
-
539
-
540
-    protected function _set_page_config()
541
-    {
542
-        $REG_ID             = $this->request->getRequestParam('_REG_ID', 0, 'int');
543
-        $ATT_ID             = $this->request->getRequestParam('ATT_ID', 0, 'int');
544
-        $this->_page_config = [
545
-            'default'           => [
546
-                'nav'           => [
547
-                    'label' => esc_html__('Overview', 'event_espresso'),
548
-                    'icon'  => 'dashicons-list-view',
549
-                    'order' => 5,
550
-                ],
551
-                'help_tabs'     => [
552
-                    'registrations_overview_help_tab'                       => [
553
-                        'title'    => esc_html__('Registrations Overview', 'event_espresso'),
554
-                        'filename' => 'registrations_overview',
555
-                    ],
556
-                    'registrations_overview_table_column_headings_help_tab' => [
557
-                        'title'    => esc_html__('Registrations Table Column Headings', 'event_espresso'),
558
-                        'filename' => 'registrations_overview_table_column_headings',
559
-                    ],
560
-                    'registrations_overview_filters_help_tab'               => [
561
-                        'title'    => esc_html__('Registration Filters', 'event_espresso'),
562
-                        'filename' => 'registrations_overview_filters',
563
-                    ],
564
-                    'registrations_overview_views_help_tab'                 => [
565
-                        'title'    => esc_html__('Registration Views', 'event_espresso'),
566
-                        'filename' => 'registrations_overview_views',
567
-                    ],
568
-                    'registrations_regoverview_other_help_tab'              => [
569
-                        'title'    => esc_html__('Registrations Other', 'event_espresso'),
570
-                        'filename' => 'registrations_overview_other',
571
-                    ],
572
-                ],
573
-                'list_table'    => 'EE_Registrations_List_Table',
574
-                'require_nonce' => false,
575
-            ],
576
-            'view_registration' => [
577
-                'nav'           => [
578
-                    'label'      => esc_html__('REG Details', 'event_espresso'),
579
-                    'icon'       => 'dashicons-clipboard',
580
-                    'order'      => 15,
581
-                    'url'        => $REG_ID
582
-                        ? add_query_arg(['_REG_ID' => $REG_ID], $this->_current_page_view_url)
583
-                        : $this->_admin_base_url,
584
-                    'persistent' => false,
585
-                ],
586
-                'help_tabs'     => [
587
-                    'registrations_details_help_tab'                    => [
588
-                        'title'    => esc_html__('Registration Details', 'event_espresso'),
589
-                        'filename' => 'registrations_details',
590
-                    ],
591
-                    'registrations_details_table_help_tab'              => [
592
-                        'title'    => esc_html__('Registration Details Table', 'event_espresso'),
593
-                        'filename' => 'registrations_details_table',
594
-                    ],
595
-                    'registrations_details_form_answers_help_tab'       => [
596
-                        'title'    => esc_html__('Registration Form Answers', 'event_espresso'),
597
-                        'filename' => 'registrations_details_form_answers',
598
-                    ],
599
-                    'registrations_details_registrant_details_help_tab' => [
600
-                        'title'    => esc_html__('Contact Details', 'event_espresso'),
601
-                        'filename' => 'registrations_details_registrant_details',
602
-                    ],
603
-                ],
604
-                'metaboxes'     => array_merge(
605
-                    $this->_default_espresso_metaboxes,
606
-                    ['_registration_details_metaboxes']
607
-                ),
608
-                'require_nonce' => false,
609
-            ],
610
-            'new_registration'  => [
611
-                'nav'           => [
612
-                    'label'      => esc_html__('Add New Registration', 'event_espresso'),
613
-                    'icon'       => 'dashicons-plus-alt',
614
-                    'url'        => '#',
615
-                    'order'      => 15,
616
-                    'persistent' => false,
617
-                ],
618
-                'metaboxes'     => $this->_default_espresso_metaboxes,
619
-                'labels'        => [
620
-                    'publishbox' => esc_html__('Save Registration', 'event_espresso'),
621
-                ],
622
-                'require_nonce' => false,
623
-            ],
624
-            'add_new_attendee'  => [
625
-                'nav'           => [
626
-                    'label'      => esc_html__('Add Contact', 'event_espresso'),
627
-                    'icon'       => 'dashicons-plus-alt',
628
-                    'order'      => 15,
629
-                    'persistent' => false,
630
-                ],
631
-                'metaboxes'     => array_merge(
632
-                    $this->_default_espresso_metaboxes,
633
-                    ['_publish_post_box', 'attendee_editor_metaboxes']
634
-                ),
635
-                'require_nonce' => false,
636
-            ],
637
-            'edit_attendee'     => [
638
-                'nav'           => [
639
-                    'label'      => esc_html__('Edit Contact', 'event_espresso'),
640
-                    'icon'       => 'dashicons-edit-large',
641
-                    'order'      => 15,
642
-                    'persistent' => false,
643
-                    'url'        => $ATT_ID
644
-                        ? add_query_arg(['ATT_ID' => $ATT_ID], $this->_current_page_view_url)
645
-                        : $this->_admin_base_url,
646
-                ],
647
-                'metaboxes'     => array_merge(
648
-                    $this->_default_espresso_metaboxes,
649
-                    ['attendee_editor_metaboxes']
650
-                ),
651
-                'require_nonce' => false,
652
-            ],
653
-            'contact_list'      => [
654
-                'nav'           => [
655
-                    'label' => esc_html__('Contact List', 'event_espresso'),
656
-                    'icon'  => 'dashicons-id-alt',
657
-                    'order' => 20,
658
-                ],
659
-                'list_table'    => 'EE_Attendee_Contact_List_Table',
660
-                'help_tabs'     => [
661
-                    'registrations_contact_list_help_tab'                       => [
662
-                        'title'    => esc_html__('Registrations Contact List', 'event_espresso'),
663
-                        'filename' => 'registrations_contact_list',
664
-                    ],
665
-                    'registrations_contact-list_table_column_headings_help_tab' => [
666
-                        'title'    => esc_html__('Contact List Table Column Headings', 'event_espresso'),
667
-                        'filename' => 'registrations_contact_list_table_column_headings',
668
-                    ],
669
-                    'registrations_contact_list_views_help_tab'                 => [
670
-                        'title'    => esc_html__('Contact List Views', 'event_espresso'),
671
-                        'filename' => 'registrations_contact_list_views',
672
-                    ],
673
-                    'registrations_contact_list_other_help_tab'                 => [
674
-                        'title'    => esc_html__('Contact List Other', 'event_espresso'),
675
-                        'filename' => 'registrations_contact_list_other',
676
-                    ],
677
-                ],
678
-                'metaboxes'     => [],
679
-                'require_nonce' => false,
680
-            ],
681
-            // override default cpt routes
682
-            'create_new'        => '',
683
-            'edit'              => '',
684
-        ];
685
-    }
686
-
687
-
688
-    /**
689
-     * The below methods aren't used by this class currently
690
-     */
691
-    protected function _add_screen_options()
692
-    {
693
-    }
694
-
695
-
696
-    protected function _add_feature_pointers()
697
-    {
698
-    }
699
-
700
-
701
-    public function admin_init()
702
-    {
703
-        EE_Registry::$i18n_js_strings['update_att_qstns'] = esc_html__(
704
-            'click "Update Registration Questions" to save your changes',
705
-            'event_espresso'
706
-        );
707
-    }
708
-
709
-
710
-    public function admin_notices()
711
-    {
712
-    }
713
-
714
-
715
-    public function admin_footer_scripts()
716
-    {
717
-    }
718
-
719
-
720
-    /**
721
-     * get list of registration statuses
722
-     *
723
-     * @return void
724
-     * @throws EE_Error
725
-     */
726
-    private function _get_registration_status_array()
727
-    {
728
-        self::$_reg_status = EEM_Registration::reg_status_array([], true);
729
-    }
730
-
731
-
732
-    /**
733
-     * @throws InvalidArgumentException
734
-     * @throws InvalidDataTypeException
735
-     * @throws InvalidInterfaceException
736
-     * @since 4.10.2.p
737
-     */
738
-    protected function _add_screen_options_default()
739
-    {
740
-        $this->_per_page_screen_option();
741
-    }
742
-
743
-
744
-    /**
745
-     * @throws InvalidArgumentException
746
-     * @throws InvalidDataTypeException
747
-     * @throws InvalidInterfaceException
748
-     * @since 4.10.2.p
749
-     */
750
-    protected function _add_screen_options_contact_list()
751
-    {
752
-        $page_title              = $this->_admin_page_title;
753
-        $this->_admin_page_title = esc_html__('Contacts', 'event_espresso');
754
-        $this->_per_page_screen_option();
755
-        $this->_admin_page_title = $page_title;
756
-    }
757
-
758
-
759
-    public function load_scripts_styles()
760
-    {
761
-        // style
762
-        wp_register_style(
763
-            'espresso_reg',
764
-            REG_ASSETS_URL . 'espresso_registrations_admin.css',
765
-            ['ee-admin-css'],
766
-            EVENT_ESPRESSO_VERSION
767
-        );
768
-        wp_enqueue_style('espresso_reg');
769
-        // script
770
-        wp_register_script(
771
-            'espresso_reg',
772
-            REG_ASSETS_URL . 'espresso_registrations_admin.js',
773
-            ['jquery-ui-datepicker', 'jquery-ui-draggable', 'ee_admin_js'],
774
-            EVENT_ESPRESSO_VERSION,
775
-            true
776
-        );
777
-        wp_enqueue_script('espresso_reg');
778
-    }
779
-
780
-
781
-    /**
782
-     * @throws EE_Error
783
-     * @throws InvalidArgumentException
784
-     * @throws InvalidDataTypeException
785
-     * @throws InvalidInterfaceException
786
-     * @throws ReflectionException
787
-     * @since 4.10.2.p
788
-     */
789
-    public function load_scripts_styles_edit_attendee()
790
-    {
791
-        // stuff to only show up on our attendee edit details page.
792
-        $attendee_details_translations = [
793
-            'att_publish_text' => sprintf(
794
-            /* translators: The date and time */
795
-                wp_strip_all_tags(__('Created on: %s', 'event_espresso')),
796
-                '<b>' . $this->_cpt_model_obj->get_datetime('ATT_created') . '</b>'
797
-            ),
798
-        ];
799
-        wp_localize_script('espresso_reg', 'ATTENDEE_DETAILS', $attendee_details_translations);
800
-        wp_enqueue_script('jquery-validate');
801
-    }
802
-
803
-
804
-    /**
805
-     * @throws EE_Error
806
-     * @throws InvalidArgumentException
807
-     * @throws InvalidDataTypeException
808
-     * @throws InvalidInterfaceException
809
-     * @throws ReflectionException
810
-     * @since 4.10.2.p
811
-     */
812
-    public function load_scripts_styles_view_registration()
813
-    {
814
-        $this->_set_registration_object();
815
-        // styles
816
-        wp_enqueue_style('espresso-ui-theme');
817
-        // scripts
818
-        $this->_get_reg_custom_questions_form($this->_registration->ID());
819
-        $this->_reg_custom_questions_form->wp_enqueue_scripts();
820
-    }
821
-
822
-
823
-    public function load_scripts_styles_contact_list()
824
-    {
825
-        wp_dequeue_style('espresso_reg');
826
-        wp_register_style(
827
-            'espresso_att',
828
-            REG_ASSETS_URL . 'espresso_attendees_admin.css',
829
-            ['ee-admin-css'],
830
-            EVENT_ESPRESSO_VERSION
831
-        );
832
-        wp_enqueue_style('espresso_att');
833
-    }
834
-
835
-
836
-    public function load_scripts_styles_new_registration()
837
-    {
838
-        wp_register_script(
839
-            'ee-spco-for-admin',
840
-            REG_ASSETS_URL . 'spco_for_admin.js',
841
-            ['underscore', 'jquery'],
842
-            EVENT_ESPRESSO_VERSION,
843
-            true
844
-        );
845
-        wp_enqueue_script('ee-spco-for-admin');
846
-        add_filter('FHEE__EED_Ticket_Selector__load_tckt_slctr_assets', '__return_true');
847
-        EE_Form_Section_Proper::wp_enqueue_scripts();
848
-        EED_Ticket_Selector::load_tckt_slctr_assets();
849
-        EE_Datepicker_Input::enqueue_styles_and_scripts();
850
-    }
851
-
852
-
853
-    public function AHEE__EE_Admin_Page__route_admin_request_resend_registration()
854
-    {
855
-        add_filter('FHEE_load_EE_messages', '__return_true');
856
-    }
857
-
858
-
859
-    public function AHEE__EE_Admin_Page__route_admin_request_approve_registration()
860
-    {
861
-        add_filter('FHEE_load_EE_messages', '__return_true');
862
-    }
863
-
864
-
865
-    /**
866
-     * @throws EE_Error
867
-     * @throws InvalidArgumentException
868
-     * @throws InvalidDataTypeException
869
-     * @throws InvalidInterfaceException
870
-     * @throws ReflectionException
871
-     * @since 4.10.2.p
872
-     */
873
-    protected function _set_list_table_views_default()
874
-    {
875
-        // for notification related bulk actions we need to make sure only active messengers have an option.
876
-        EED_Messages::set_autoloaders();
877
-        /** @type EE_Message_Resource_Manager $message_resource_manager */
878
-        $message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
879
-        $active_mts               = $message_resource_manager->list_of_active_message_types();
880
-        // key= bulk_action_slug, value= message type.
881
-        $match_array = [
882
-            'approve_registrations'    => 'registration',
883
-            'decline_registrations'    => 'declined_registration',
884
-            'pending_registrations'    => 'pending_approval',
885
-            'no_approve_registrations' => 'not_approved_registration',
886
-            'cancel_registrations'     => 'cancelled_registration',
887
-        ];
888
-        $can_send    = $this->capabilities->current_user_can(
889
-            'ee_send_message',
890
-            'batch_send_messages'
891
-        );
892
-        /** setup reg status bulk actions **/
893
-        $def_reg_status_actions['approve_registrations'] = esc_html__('Approve Registrations', 'event_espresso');
894
-        if ($can_send && in_array($match_array['approve_registrations'], $active_mts, true)) {
895
-            $def_reg_status_actions['approve_and_notify_registrations'] = esc_html__(
896
-                'Approve and Notify Registrations',
897
-                'event_espresso'
898
-            );
899
-        }
900
-        $def_reg_status_actions['decline_registrations'] = esc_html__('Decline Registrations', 'event_espresso');
901
-        if ($can_send && in_array($match_array['decline_registrations'], $active_mts, true)) {
902
-            $def_reg_status_actions['decline_and_notify_registrations'] = esc_html__(
903
-                'Decline and Notify Registrations',
904
-                'event_espresso'
905
-            );
906
-        }
907
-        $def_reg_status_actions['pending_registrations'] = esc_html__(
908
-            'Set Registrations to Pending Payment',
909
-            'event_espresso'
910
-        );
911
-        if ($can_send && in_array($match_array['pending_registrations'], $active_mts, true)) {
912
-            $def_reg_status_actions['pending_and_notify_registrations'] = esc_html__(
913
-                'Set Registrations to Pending Payment and Notify',
914
-                'event_espresso'
915
-            );
916
-        }
917
-        $def_reg_status_actions['no_approve_registrations'] = esc_html__(
918
-            'Set Registrations to Not Approved',
919
-            'event_espresso'
920
-        );
921
-        if ($can_send && in_array($match_array['no_approve_registrations'], $active_mts, true)) {
922
-            $def_reg_status_actions['no_approve_and_notify_registrations'] = esc_html__(
923
-                'Set Registrations to Not Approved and Notify',
924
-                'event_espresso'
925
-            );
926
-        }
927
-        $def_reg_status_actions['cancel_registrations'] = esc_html__('Cancel Registrations', 'event_espresso');
928
-        if ($can_send && in_array($match_array['cancel_registrations'], $active_mts, true)) {
929
-            $def_reg_status_actions['cancel_and_notify_registrations'] = esc_html__(
930
-                'Cancel Registrations and Notify',
931
-                'event_espresso'
932
-            );
933
-        }
934
-        $def_reg_status_actions = apply_filters(
935
-            'FHEE__Registrations_Admin_Page___set_list_table_views_default__def_reg_status_actions_array',
936
-            $def_reg_status_actions,
937
-            $active_mts,
938
-            $can_send
939
-        );
940
-
941
-        $this->_views = [
942
-            'all'   => [
943
-                'slug'        => 'all',
944
-                'label'       => esc_html__('View All Registrations', 'event_espresso'),
945
-                'count'       => 0,
946
-                'bulk_action' => array_merge(
947
-                    $def_reg_status_actions,
948
-                    [
949
-                        'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
950
-                    ]
951
-                ),
952
-            ],
953
-            'month' => [
954
-                'slug'        => 'month',
955
-                'label'       => esc_html__('This Month', 'event_espresso'),
956
-                'count'       => 0,
957
-                'bulk_action' => array_merge(
958
-                    $def_reg_status_actions,
959
-                    [
960
-                        'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
961
-                    ]
962
-                ),
963
-            ],
964
-            'today' => [
965
-                'slug'        => 'today',
966
-                'label'       => sprintf(
967
-                    esc_html__('Today - %s', 'event_espresso'),
968
-                    date('M d, Y', current_time('timestamp'))
969
-                ),
970
-                'count'       => 0,
971
-                'bulk_action' => array_merge(
972
-                    $def_reg_status_actions,
973
-                    [
974
-                        'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
975
-                    ]
976
-                ),
977
-            ],
978
-        ];
979
-        if (
980
-            $this->capabilities->current_user_can(
981
-                'ee_delete_registrations',
982
-                'espresso_registrations_delete_registration'
983
-            )
984
-        ) {
985
-            $this->_views['incomplete'] = [
986
-                'slug'        => 'incomplete',
987
-                'label'       => esc_html__('Incomplete', 'event_espresso'),
988
-                'count'       => 0,
989
-                'bulk_action' => [
990
-                    'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
991
-                ],
992
-            ];
993
-            $this->_views['trash']      = [
994
-                'slug'        => 'trash',
995
-                'label'       => esc_html__('Trash', 'event_espresso'),
996
-                'count'       => 0,
997
-                'bulk_action' => [
998
-                    'restore_registrations' => esc_html__('Restore Registrations', 'event_espresso'),
999
-                    'delete_registrations'  => esc_html__('Delete Registrations Permanently', 'event_espresso'),
1000
-                ],
1001
-            ];
1002
-        }
1003
-    }
1004
-
1005
-
1006
-    protected function _set_list_table_views_contact_list()
1007
-    {
1008
-        $this->_views = [
1009
-            'in_use' => [
1010
-                'slug'        => 'in_use',
1011
-                'label'       => esc_html__('In Use', 'event_espresso'),
1012
-                'count'       => 0,
1013
-                'bulk_action' => [
1014
-                    'trash_attendees' => esc_html__('Move to Trash', 'event_espresso'),
1015
-                ],
1016
-            ],
1017
-        ];
1018
-        if (
1019
-            $this->capabilities->current_user_can(
1020
-                'ee_delete_contacts',
1021
-                'espresso_registrations_trash_attendees'
1022
-            )
1023
-        ) {
1024
-            $this->_views['trash'] = [
1025
-                'slug'        => 'trash',
1026
-                'label'       => esc_html__('Trash', 'event_espresso'),
1027
-                'count'       => 0,
1028
-                'bulk_action' => [
1029
-                    'restore_attendees' => esc_html__('Restore from Trash', 'event_espresso'),
1030
-                ],
1031
-            ];
1032
-        }
1033
-    }
1034
-
1035
-
1036
-    /**
1037
-     * @return array
1038
-     * @throws EE_Error
1039
-     */
1040
-    protected function _registration_legend_items()
1041
-    {
1042
-        $fc_items = [
1043
-            'star-icon'        => [
1044
-                'class' => 'dashicons dashicons-star-filled gold-icon',
1045
-                'desc'  => esc_html__('This is the Primary Registrant', 'event_espresso'),
1046
-            ],
1047
-            'view_details'     => [
1048
-                'class' => 'dashicons dashicons-clipboard',
1049
-                'desc'  => esc_html__('View Registration Details', 'event_espresso'),
1050
-            ],
1051
-            'edit_attendee'    => [
1052
-                'class' => 'dashicons dashicons-admin-users',
1053
-                'desc'  => esc_html__('Edit Contact Details', 'event_espresso'),
1054
-            ],
1055
-            'view_transaction' => [
1056
-                'class' => 'dashicons dashicons-cart',
1057
-                'desc'  => esc_html__('View Transaction Details', 'event_espresso'),
1058
-            ],
1059
-            'view_invoice'     => [
1060
-                'class' => 'dashicons dashicons-media-spreadsheet',
1061
-                'desc'  => esc_html__('View Transaction Invoice', 'event_espresso'),
1062
-            ],
1063
-        ];
1064
-        if (
1065
-            $this->capabilities->current_user_can(
1066
-                'ee_send_message',
1067
-                'espresso_registrations_resend_registration'
1068
-            )
1069
-        ) {
1070
-            $fc_items['resend_registration'] = [
1071
-                'class' => 'dashicons dashicons-email-alt',
1072
-                'desc'  => esc_html__('Resend Registration Details', 'event_espresso'),
1073
-            ];
1074
-        } else {
1075
-            $fc_items['blank'] = ['class' => 'blank', 'desc' => ''];
1076
-        }
1077
-        if (
1078
-            $this->capabilities->current_user_can(
1079
-                'ee_read_global_messages',
1080
-                'view_filtered_messages'
1081
-            )
1082
-        ) {
1083
-            $related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
1084
-            if (is_array($related_for_icon) && isset($related_for_icon['css_class'], $related_for_icon['label'])) {
1085
-                $fc_items['view_related_messages'] = [
1086
-                    'class' => $related_for_icon['css_class'],
1087
-                    'desc'  => $related_for_icon['label'],
1088
-                ];
1089
-            }
1090
-        }
1091
-        $sc_items = [
1092
-            'approved_status'   => [
1093
-                'class' => 'ee-status-legend ee-status-bg--' . EEM_Registration::status_id_approved,
1094
-                'desc'  => EEH_Template::pretty_status(
1095
-                    EEM_Registration::status_id_approved,
1096
-                    false,
1097
-                    'sentence'
1098
-                ),
1099
-            ],
1100
-            'pending_status'    => [
1101
-                'class' => 'ee-status-legend ee-status-bg--' . EEM_Registration::status_id_pending_payment,
1102
-                'desc'  => EEH_Template::pretty_status(
1103
-                    EEM_Registration::status_id_pending_payment,
1104
-                    false,
1105
-                    'sentence'
1106
-                ),
1107
-            ],
1108
-            'wait_list'         => [
1109
-                'class' => 'ee-status-legend ee-status-bg--' . EEM_Registration::status_id_wait_list,
1110
-                'desc'  => EEH_Template::pretty_status(
1111
-                    EEM_Registration::status_id_wait_list,
1112
-                    false,
1113
-                    'sentence'
1114
-                ),
1115
-            ],
1116
-            'incomplete_status' => [
1117
-                'class' => 'ee-status-legend ee-status-bg--' . EEM_Registration::status_id_incomplete,
1118
-                'desc'  => EEH_Template::pretty_status(
1119
-                    EEM_Registration::status_id_incomplete,
1120
-                    false,
1121
-                    'sentence'
1122
-                ),
1123
-            ],
1124
-            'not_approved'      => [
1125
-                'class' => 'ee-status-legend ee-status-bg--' . EEM_Registration::status_id_not_approved,
1126
-                'desc'  => EEH_Template::pretty_status(
1127
-                    EEM_Registration::status_id_not_approved,
1128
-                    false,
1129
-                    'sentence'
1130
-                ),
1131
-            ],
1132
-            'declined_status'   => [
1133
-                'class' => 'ee-status-legend ee-status-bg--' . EEM_Registration::status_id_declined,
1134
-                'desc'  => EEH_Template::pretty_status(
1135
-                    EEM_Registration::status_id_declined,
1136
-                    false,
1137
-                    'sentence'
1138
-                ),
1139
-            ],
1140
-            'cancelled_status'  => [
1141
-                'class' => 'ee-status-legend ee-status-bg--' . EEM_Registration::status_id_cancelled,
1142
-                'desc'  => EEH_Template::pretty_status(
1143
-                    EEM_Registration::status_id_cancelled,
1144
-                    false,
1145
-                    'sentence'
1146
-                ),
1147
-            ],
1148
-        ];
1149
-        return array_merge($fc_items, $sc_items);
1150
-    }
1151
-
1152
-
1153
-
1154
-    /***************************************        REGISTRATION OVERVIEW        **************************************/
1155
-
1156
-
1157
-    /**
1158
-     * @throws DomainException
1159
-     * @throws EE_Error
1160
-     * @throws InvalidArgumentException
1161
-     * @throws InvalidDataTypeException
1162
-     * @throws InvalidInterfaceException
1163
-     */
1164
-    protected function _registrations_overview_list_table()
1165
-    {
1166
-        $this->appendAddNewRegistrationButtonToPageTitle();
1167
-        $header_text                  = '';
1168
-        $admin_page_header_decorators = [
1169
-            'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\AttendeeFilterHeader',
1170
-            'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\EventFilterHeader',
1171
-            'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\DateFilterHeader',
1172
-            'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\TicketFilterHeader',
1173
-        ];
1174
-        foreach ($admin_page_header_decorators as $admin_page_header_decorator) {
1175
-            $filter_header_decorator = $this->loader->getNew($admin_page_header_decorator);
1176
-            $header_text             = $filter_header_decorator->getHeaderText($header_text);
1177
-        }
1178
-        $this->_template_args['before_list_table'] = $header_text;
1179
-        $this->_template_args['after_list_table']  = $this->_display_legend($this->_registration_legend_items());
1180
-        $this->display_admin_list_table_page_with_no_sidebar();
1181
-    }
1182
-
1183
-
1184
-    /**
1185
-     * @throws EE_Error
1186
-     * @throws InvalidArgumentException
1187
-     * @throws InvalidDataTypeException
1188
-     * @throws InvalidInterfaceException
1189
-     */
1190
-    private function appendAddNewRegistrationButtonToPageTitle()
1191
-    {
1192
-        $EVT_ID = $this->request->getRequestParam('event_id', 0, 'int');
1193
-        if (
1194
-            $EVT_ID
1195
-            && $this->capabilities->current_user_can(
1196
-                'ee_edit_registrations',
1197
-                'espresso_registrations_new_registration',
1198
-                $EVT_ID
1199
-            )
1200
-        ) {
1201
-            $this->_admin_page_title .= ' ' . $this->get_action_link_or_button(
1202
-                    'new_registration',
1203
-                    'add-registrant',
1204
-                    ['event_id' => $EVT_ID],
1205
-                    'add-new-h2'
1206
-                );
1207
-        }
1208
-    }
1209
-
1210
-
1211
-    /**
1212
-     * This sets the _registration property for the registration details screen
1213
-     *
1214
-     * @return void
1215
-     * @throws EE_Error
1216
-     * @throws InvalidArgumentException
1217
-     * @throws InvalidDataTypeException
1218
-     * @throws InvalidInterfaceException
1219
-     */
1220
-    private function _set_registration_object()
1221
-    {
1222
-        // get out if we've already set the object
1223
-        if ($this->_registration instanceof EE_Registration) {
1224
-            return;
1225
-        }
1226
-        $REG_ID = $this->request->getRequestParam('_REG_ID', 0, 'int');
1227
-        if ($this->_registration = $this->getRegistrationModel()->get_one_by_ID($REG_ID)) {
1228
-            return;
1229
-        }
1230
-        $error_msg = sprintf(
1231
-            esc_html__(
1232
-                'An error occurred and the details for Registration ID #%s could not be retrieved.',
1233
-                'event_espresso'
1234
-            ),
1235
-            $REG_ID
1236
-        );
1237
-        EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
1238
-        $this->_registration = null;
1239
-    }
1240
-
1241
-
1242
-    /**
1243
-     * Used to retrieve registrations for the list table.
1244
-     *
1245
-     * @param int  $per_page
1246
-     * @param bool $count
1247
-     * @param bool $this_month
1248
-     * @param bool $today
1249
-     * @return EE_Registration[]|int
1250
-     * @throws EE_Error
1251
-     * @throws InvalidArgumentException
1252
-     * @throws InvalidDataTypeException
1253
-     * @throws InvalidInterfaceException
1254
-     */
1255
-    public function get_registrations(
1256
-        $per_page = 10,
1257
-        $count = false,
1258
-        $this_month = false,
1259
-        $today = false
1260
-    ) {
1261
-        if ($this_month) {
1262
-            $this->request->setRequestParam('status', 'month');
1263
-        }
1264
-        if ($today) {
1265
-            $this->request->setRequestParam('status', 'today');
1266
-        }
1267
-        $query_params = $this->_get_registration_query_parameters([], $per_page, $count);
1268
-        /**
1269
-         * Override the default groupby added by EEM_Base so that sorts with multiple order bys work as expected
1270
-         *
1271
-         * @link https://events.codebasehq.com/projects/event-espresso/tickets/10093
1272
-         * @see  https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1273
-         *                      or if you have the development copy of EE you can view this at the path:
1274
-         *                      /docs/G--Model-System/model-query-params.md
1275
-         */
1276
-        $query_params['group_by'] = '';
1277
-
1278
-        return $count
1279
-            ? $this->getRegistrationModel()->count($query_params)
1280
-            /** @type EE_Registration[] */
1281
-            : $this->getRegistrationModel()->get_all($query_params);
1282
-    }
1283
-
1284
-
1285
-    /**
1286
-     * Retrieves the query parameters to be used by the Registration model for getting registrations.
1287
-     * Note: this listens to values on the request for some query parameters.
1288
-     *
1289
-     * @param array $request
1290
-     * @param int   $per_page
1291
-     * @param bool  $count
1292
-     * @return array
1293
-     * @throws EE_Error
1294
-     * @throws InvalidArgumentException
1295
-     * @throws InvalidDataTypeException
1296
-     * @throws InvalidInterfaceException
1297
-     */
1298
-    protected function _get_registration_query_parameters(
1299
-        array $request = [],
1300
-        int $per_page = 10,
1301
-        bool $count = false
1302
-    ): array {
1303
-        /** @var EventEspresso\core\domain\services\admin\registrations\list_table\QueryBuilder $list_table_query_builder */
1304
-        $list_table_query_builder = $this->loader->getNew(
1305
-            'EventEspresso\core\domain\services\admin\registrations\list_table\QueryBuilder',
1306
-            [null, null, $request]
1307
-        );
1308
-        return $list_table_query_builder->getQueryParams($per_page, $count);
1309
-    }
1310
-
1311
-
1312
-    public function get_registration_status_array(): array
1313
-    {
1314
-        return self::$_reg_status;
1315
-    }
1316
-
1317
-
1318
-
1319
-
1320
-    /***************************************        REGISTRATION DETAILS        ***************************************/
1321
-    /**
1322
-     * generates HTML for the View Registration Details Admin page
1323
-     *
1324
-     * @return void
1325
-     * @throws DomainException
1326
-     * @throws EE_Error
1327
-     * @throws InvalidArgumentException
1328
-     * @throws InvalidDataTypeException
1329
-     * @throws InvalidInterfaceException
1330
-     * @throws EntityNotFoundException
1331
-     * @throws ReflectionException
1332
-     */
1333
-    protected function _registration_details()
1334
-    {
1335
-        $this->_template_args = [];
1336
-        $this->_set_registration_object();
1337
-        if (is_object($this->_registration)) {
1338
-            $transaction                                   = $this->_registration->transaction()
1339
-                ? $this->_registration->transaction()
1340
-                : EE_Transaction::new_instance();
1341
-            $this->_session                                = $transaction->session_data();
1342
-            $event_id                                      = $this->_registration->event_ID();
1343
-            $this->_template_args['reg_nmbr']['value']     = $this->_registration->ID();
1344
-            $this->_template_args['reg_nmbr']['label']     = esc_html__('Registration Number', 'event_espresso');
1345
-            $this->_template_args['reg_datetime']['value'] = $this->_registration->get_i18n_datetime('REG_date');
1346
-            $this->_template_args['reg_datetime']['label'] = esc_html__('Date', 'event_espresso');
1347
-            $this->_template_args['grand_total']           = $transaction->total();
1348
-            $this->_template_args['currency_sign']         = EE_Registry::instance()->CFG->currency->sign;
1349
-            // link back to overview
1350
-            $this->_template_args['reg_overview_url']            = REG_ADMIN_URL;
1351
-            $this->_template_args['registration']                = $this->_registration;
1352
-            $this->_template_args['filtered_registrations_link'] = EE_Admin_Page::add_query_args_and_nonce(
1353
-                [
1354
-                    'action'   => 'default',
1355
-                    'event_id' => $event_id,
1356
-                ],
1357
-                REG_ADMIN_URL
1358
-            );
1359
-            $this->_template_args['filtered_transactions_link']  = EE_Admin_Page::add_query_args_and_nonce(
1360
-                [
1361
-                    'action' => 'default',
1362
-                    'EVT_ID' => $event_id,
1363
-                    'page'   => 'espresso_transactions',
1364
-                ],
1365
-                admin_url('admin.php')
1366
-            );
1367
-            $this->_template_args['event_link']                  = EE_Admin_Page::add_query_args_and_nonce(
1368
-                [
1369
-                    'page'   => 'espresso_events',
1370
-                    'action' => 'edit',
1371
-                    'post'   => $event_id,
1372
-                ],
1373
-                admin_url('admin.php')
1374
-            );
1375
-            // next and previous links
1376
-            $next_reg                                      = $this->_registration->next(
1377
-                null,
1378
-                [],
1379
-                'REG_ID'
1380
-            );
1381
-            $this->_template_args['next_registration']     = $next_reg
1382
-                ? $this->_next_link(
1383
-                    EE_Admin_Page::add_query_args_and_nonce(
1384
-                        [
1385
-                            'action'  => 'view_registration',
1386
-                            '_REG_ID' => $next_reg['REG_ID'],
1387
-                        ],
1388
-                        REG_ADMIN_URL
1389
-                    ),
1390
-                    'dashicons dashicons-arrow-right ee-icon-size-22'
1391
-                )
1392
-                : '';
1393
-            $previous_reg                                  = $this->_registration->previous(
1394
-                null,
1395
-                [],
1396
-                'REG_ID'
1397
-            );
1398
-            $this->_template_args['previous_registration'] = $previous_reg
1399
-                ? $this->_previous_link(
1400
-                    EE_Admin_Page::add_query_args_and_nonce(
1401
-                        [
1402
-                            'action'  => 'view_registration',
1403
-                            '_REG_ID' => $previous_reg['REG_ID'],
1404
-                        ],
1405
-                        REG_ADMIN_URL
1406
-                    ),
1407
-                    'dashicons dashicons-arrow-left ee-icon-size-22'
1408
-                )
1409
-                : '';
1410
-            // grab header
1411
-            $template_path                             = REG_TEMPLATE_PATH . 'reg_admin_details_header.template.php';
1412
-            $this->_template_args['REG_ID']            = $this->_registration->ID();
1413
-            $this->_template_args['admin_page_header'] = EEH_Template::display_template(
1414
-                $template_path,
1415
-                $this->_template_args,
1416
-                true
1417
-            );
1418
-        } else {
1419
-            $this->_template_args['admin_page_header'] = '';
1420
-            $this->_display_espresso_notices();
1421
-        }
1422
-        // the details template wrapper
1423
-        $this->display_admin_page_with_sidebar();
1424
-    }
1425
-
1426
-
1427
-    /**
1428
-     * @throws EE_Error
1429
-     * @throws InvalidArgumentException
1430
-     * @throws InvalidDataTypeException
1431
-     * @throws InvalidInterfaceException
1432
-     * @throws ReflectionException
1433
-     * @since 4.10.2.p
1434
-     */
1435
-    protected function _registration_details_metaboxes()
1436
-    {
1437
-        do_action('AHEE__Registrations_Admin_Page___registration_details_metabox__start', $this);
1438
-        $this->_set_registration_object();
1439
-        $attendee = $this->_registration instanceof EE_Registration ? $this->_registration->attendee() : null;
1440
-        $this->addMetaBox(
1441
-            'edit-reg-status-mbox',
1442
-            esc_html__('Registration Status', 'event_espresso'),
1443
-            [$this, 'set_reg_status_buttons_metabox'],
1444
-            $this->_wp_page_slug
1445
-        );
1446
-        $this->addMetaBox(
1447
-            'edit-reg-details-mbox',
1448
-            '<span>' . esc_html__('Registration Details', 'event_espresso')
1449
-            . '&nbsp;<span class="dashicons dashicons-clipboard"></span></span>',
1450
-            [$this, '_reg_details_meta_box'],
1451
-            $this->_wp_page_slug
1452
-        );
1453
-        if (
1454
-            $attendee instanceof EE_Attendee
1455
-            && $this->capabilities->current_user_can(
1456
-                'ee_read_registration',
1457
-                'edit-reg-questions-mbox',
1458
-                $this->_registration->ID()
1459
-            )
1460
-        ) {
1461
-            $this->addMetaBox(
1462
-                'edit-reg-questions-mbox',
1463
-                esc_html__('Registration Form Answers', 'event_espresso'),
1464
-                [$this, '_reg_questions_meta_box'],
1465
-                $this->_wp_page_slug
1466
-            );
1467
-        }
1468
-        $this->addMetaBox(
1469
-            'edit-reg-registrant-mbox',
1470
-            esc_html__('Contact Details', 'event_espresso'),
1471
-            [$this, '_reg_registrant_side_meta_box'],
1472
-            $this->_wp_page_slug,
1473
-            'side'
1474
-        );
1475
-        if ($this->_registration->group_size() > 1) {
1476
-            $this->addMetaBox(
1477
-                'edit-reg-attendees-mbox',
1478
-                esc_html__('Other Registrations in this Transaction', 'event_espresso'),
1479
-                [$this, '_reg_attendees_meta_box'],
1480
-                $this->_wp_page_slug
1481
-            );
1482
-        }
1483
-    }
1484
-
1485
-
1486
-    /**
1487
-     * set_reg_status_buttons_metabox
1488
-     *
1489
-     * @return void
1490
-     * @throws EE_Error
1491
-     * @throws EntityNotFoundException
1492
-     * @throws InvalidArgumentException
1493
-     * @throws InvalidDataTypeException
1494
-     * @throws InvalidInterfaceException
1495
-     * @throws ReflectionException
1496
-     */
1497
-    public function set_reg_status_buttons_metabox()
1498
-    {
1499
-        $this->_set_registration_object();
1500
-        $change_reg_status_form = $this->_generate_reg_status_change_form();
1501
-        $output                 = $change_reg_status_form->form_open(
1502
-            self::add_query_args_and_nonce(
1503
-                [
1504
-                    'action' => 'change_reg_status',
1505
-                ],
1506
-                REG_ADMIN_URL
1507
-            )
1508
-        );
1509
-        $output                 .= $change_reg_status_form->get_html();
1510
-        $output                 .= $change_reg_status_form->form_close();
1511
-        echo wp_kses($output, AllowedTags::getWithFormTags());
1512
-    }
1513
-
1514
-
1515
-    /**
1516
-     * @return EE_Form_Section_Proper
1517
-     * @throws EE_Error
1518
-     * @throws InvalidArgumentException
1519
-     * @throws InvalidDataTypeException
1520
-     * @throws InvalidInterfaceException
1521
-     * @throws EntityNotFoundException
1522
-     * @throws ReflectionException
1523
-     */
1524
-    protected function _generate_reg_status_change_form()
1525
-    {
1526
-        $reg_status_change_form_array = [
1527
-            'name'            => 'reg_status_change_form',
1528
-            'html_id'         => 'reg-status-change-form',
1529
-            'layout_strategy' => new EE_Admin_Two_Column_Layout(),
1530
-            'subsections'     => [
1531
-                'return' => new EE_Hidden_Input(
1532
-                    [
1533
-                        'name'    => 'return',
1534
-                        'default' => 'view_registration',
1535
-                    ]
1536
-                ),
1537
-                'REG_ID' => new EE_Hidden_Input(
1538
-                    [
1539
-                        'name'    => 'REG_ID',
1540
-                        'default' => $this->_registration->ID(),
1541
-                    ]
1542
-                ),
1543
-            ],
1544
-        ];
1545
-        if (
1546
-            $this->capabilities->current_user_can(
1547
-                'ee_edit_registration',
1548
-                'toggle_registration_status',
1549
-                $this->_registration->ID()
1550
-            )
1551
-        ) {
1552
-            $reg_status_change_form_array['subsections']['reg_status']         = new EE_Select_Input(
1553
-                $this->_get_reg_statuses(),
1554
-                [
1555
-                    'html_label_text' => esc_html__('Change Registration Status to', 'event_espresso'),
1556
-                    'default'         => $this->_registration->status_ID(),
1557
-                ]
1558
-            );
1559
-            $reg_status_change_form_array['subsections']['send_notifications'] = new EE_Yes_No_Input(
1560
-                [
1561
-                    'html_label_text' => esc_html__('Send Related Messages', 'event_espresso'),
1562
-                    'default'         => false,
1563
-                    'html_help_text'  => esc_html__(
1564
-                        'If set to "Yes", then the related messages will be sent to the registrant.',
1565
-                        'event_espresso'
1566
-                    ),
1567
-                ]
1568
-            );
1569
-            $reg_status_change_form_array['subsections']['submit']             = new EE_Submit_Input(
1570
-                [
1571
-                    'html_class'      => 'button--primary',
1572
-                    'html_label_text' => '&nbsp;',
1573
-                    'default'         => esc_html__('Update Registration Status', 'event_espresso'),
1574
-                ]
1575
-            );
1576
-        }
1577
-        return new EE_Form_Section_Proper($reg_status_change_form_array);
1578
-    }
1579
-
1580
-
1581
-    /**
1582
-     * Returns an array of all the buttons for the various statuses and switch status actions
1583
-     *
1584
-     * @return array
1585
-     * @throws EE_Error
1586
-     * @throws InvalidArgumentException
1587
-     * @throws InvalidDataTypeException
1588
-     * @throws InvalidInterfaceException
1589
-     * @throws EntityNotFoundException
1590
-     */
1591
-    protected function _get_reg_statuses()
1592
-    {
1593
-        $reg_status_array = $this->getRegistrationModel()->reg_status_array();
1594
-        unset($reg_status_array[ EEM_Registration::status_id_incomplete ]);
1595
-        // get current reg status
1596
-        $current_status = $this->_registration->status_ID();
1597
-        // is registration for free event? This will determine whether to display the pending payment option
1598
-        if (
1599
-            $current_status !== EEM_Registration::status_id_pending_payment
1600
-            && EEH_Money::compare_floats($this->_registration->ticket()->price(), 0.00)
1601
-        ) {
1602
-            unset($reg_status_array[ EEM_Registration::status_id_pending_payment ]);
1603
-        }
1604
-        return $this->getStatusModel()->localized_status($reg_status_array, false, 'sentence');
1605
-    }
1606
-
1607
-
1608
-    /**
1609
-     * This method is used when using _REG_ID from request which may or may not be an array of reg_ids.
1610
-     *
1611
-     * @param bool $status REG status given for changing registrations to.
1612
-     * @param bool $notify Whether to send messages notifications or not.
1613
-     * @return array (array with reg_id(s) updated and whether update was successful.
1614
-     * @throws DomainException
1615
-     * @throws EE_Error
1616
-     * @throws EntityNotFoundException
1617
-     * @throws InvalidArgumentException
1618
-     * @throws InvalidDataTypeException
1619
-     * @throws InvalidInterfaceException
1620
-     * @throws ReflectionException
1621
-     * @throws RuntimeException
1622
-     */
1623
-    protected function _set_registration_status_from_request($status = false, $notify = false)
1624
-    {
1625
-        $REG_IDs = $this->request->requestParamIsSet('reg_status_change_form')
1626
-            ? $this->request->getRequestParam('reg_status_change_form[REG_ID]', [], 'int', true)
1627
-            : $this->request->getRequestParam('_REG_ID', [], 'int', true);
1628
-        // sanitize $REG_IDs
1629
-        $REG_IDs = array_map('absint', $REG_IDs);
1630
-        // and remove empty entries
1631
-        $REG_IDs = array_filter($REG_IDs);
1632
-
1633
-        $result = $this->_set_registration_status($REG_IDs, $status, $notify);
1634
-
1635
-        /**
1636
-         * Set and filter $_req_data['_REG_ID'] for any potential future messages notifications.
1637
-         * Currently this value is used downstream by the _process_resend_registration method.
1638
-         *
1639
-         * @param int|array                $registration_ids The registration ids that have had their status changed successfully.
1640
-         * @param bool                     $status           The status registrations were changed to.
1641
-         * @param bool                     $success          If the status was changed successfully for all registrations.
1642
-         * @param Registrations_Admin_Page $admin_page
1643
-         */
1644
-        $REG_ID = apply_filters(
1645
-            'FHEE__Registrations_Admin_Page___set_registration_status_from_request__REG_IDs',
1646
-            $result['REG_ID'],
1647
-            $status,
1648
-            $result['success'],
1649
-            $this
1650
-        );
1651
-        $this->request->setRequestParam('_REG_ID', $REG_ID);
1652
-
1653
-        // notify?
1654
-        if (
1655
-            $notify
1656
-            && $result['success']
1657
-            && ! empty($REG_ID)
1658
-            && $this->capabilities->current_user_can(
1659
-                'ee_send_message',
1660
-                'espresso_registrations_resend_registration'
1661
-            )
1662
-        ) {
1663
-            $this->_process_resend_registration();
1664
-        }
1665
-        return $result;
1666
-    }
1667
-
1668
-
1669
-    /**
1670
-     * Set the registration status for the given reg_id (which may or may not be an array, it gets typecast to an
1671
-     * array). Note, this method does NOT take care of possible notifications.  That is required by calling code.
1672
-     *
1673
-     * @param array  $REG_IDs
1674
-     * @param string $status
1675
-     * @param bool   $notify Used to indicate whether notification was requested or not.  This determines the context
1676
-     *                       slug sent with setting the registration status.
1677
-     * @return array (an array with 'success' key representing whether status change was successful, and 'REG_ID' as
1678
-     * @throws EE_Error
1679
-     * @throws InvalidArgumentException
1680
-     * @throws InvalidDataTypeException
1681
-     * @throws InvalidInterfaceException
1682
-     * @throws ReflectionException
1683
-     * @throws RuntimeException
1684
-     * @throws EntityNotFoundException
1685
-     * @throws DomainException
1686
-     */
1687
-    protected function _set_registration_status($REG_IDs = [], $status = '', $notify = false)
1688
-    {
1689
-        $success = false;
1690
-        // typecast $REG_IDs
1691
-        $REG_IDs = (array) $REG_IDs;
1692
-        if (! empty($REG_IDs)) {
1693
-            $success = true;
1694
-            // set default status if none is passed
1695
-            $status         = $status ?: EEM_Registration::status_id_pending_payment;
1696
-            $status_context = $notify
1697
-                ? Domain::CONTEXT_REGISTRATION_STATUS_CHANGE_REGISTRATION_ADMIN_NOTIFY
1698
-                : Domain::CONTEXT_REGISTRATION_STATUS_CHANGE_REGISTRATION_ADMIN;
1699
-            // loop through REG_ID's and change status
1700
-            foreach ($REG_IDs as $REG_ID) {
1701
-                $registration = $this->getRegistrationModel()->get_one_by_ID($REG_ID);
1702
-                if ($registration instanceof EE_Registration) {
1703
-                    $registration->set_status(
1704
-                        $status,
1705
-                        false,
1706
-                        new Context(
1707
-                            $status_context,
1708
-                            esc_html__(
1709
-                                'Manually triggered status change on a Registration Admin Page route.',
1710
-                                'event_espresso'
1711
-                            )
1712
-                        )
1713
-                    );
1714
-                    $result = $registration->save();
1715
-                    // verifying explicit fails because update *may* just return 0 for 0 rows affected
1716
-                    $success = $result !== false ? $success : false;
1717
-                }
1718
-            }
1719
-        }
1720
-
1721
-        // return $success and processed registrations
1722
-        return ['REG_ID' => $REG_IDs, 'success' => $success];
1723
-    }
1724
-
1725
-
1726
-    /**
1727
-     * Common logic for setting up success message and redirecting to appropriate route
1728
-     *
1729
-     * @param string $STS_ID status id for the registration changed to
1730
-     * @param bool   $notify indicates whether the _set_registration_status_from_request does notifications or not.
1731
-     * @return void
1732
-     * @throws DomainException
1733
-     * @throws EE_Error
1734
-     * @throws EntityNotFoundException
1735
-     * @throws InvalidArgumentException
1736
-     * @throws InvalidDataTypeException
1737
-     * @throws InvalidInterfaceException
1738
-     * @throws ReflectionException
1739
-     * @throws RuntimeException
1740
-     */
1741
-    protected function _reg_status_change_return($STS_ID, $notify = false)
1742
-    {
1743
-        $result  = ! empty($STS_ID) ? $this->_set_registration_status_from_request($STS_ID, $notify)
1744
-            : ['success' => false];
1745
-        $success = isset($result['success']) && $result['success'];
1746
-        // setup success message
1747
-        if ($success) {
1748
-            if (is_array($result['REG_ID']) && count($result['REG_ID']) === 1) {
1749
-                $msg = sprintf(
1750
-                    esc_html__('Registration status has been set to %s', 'event_espresso'),
1751
-                    EEH_Template::pretty_status($STS_ID, false, 'lower')
1752
-                );
1753
-            } else {
1754
-                $msg = sprintf(
1755
-                    esc_html__('Registrations have been set to %s.', 'event_espresso'),
1756
-                    EEH_Template::pretty_status($STS_ID, false, 'lower')
1757
-                );
1758
-            }
1759
-            EE_Error::add_success($msg);
1760
-        } else {
1761
-            EE_Error::add_error(
1762
-                esc_html__(
1763
-                    'Something went wrong, and the status was not changed',
1764
-                    'event_espresso'
1765
-                ),
1766
-                __FILE__,
1767
-                __LINE__,
1768
-                __FUNCTION__
1769
-            );
1770
-        }
1771
-        $return = $this->request->getRequestParam('return');
1772
-        $route  = $return === 'view_registration'
1773
-            ? ['action' => 'view_registration', '_REG_ID' => reset($result['REG_ID'])]
1774
-            : ['action' => 'default'];
1775
-        $route  = $this->mergeExistingRequestParamsWithRedirectArgs($route);
1776
-        $this->_redirect_after_action($success, '', '', $route, true);
1777
-    }
1778
-
1779
-
1780
-    /**
1781
-     * incoming reg status change from reg details page.
1782
-     *
1783
-     * @return void
1784
-     * @throws EE_Error
1785
-     * @throws EntityNotFoundException
1786
-     * @throws InvalidArgumentException
1787
-     * @throws InvalidDataTypeException
1788
-     * @throws InvalidInterfaceException
1789
-     * @throws ReflectionException
1790
-     * @throws RuntimeException
1791
-     * @throws DomainException
1792
-     */
1793
-    protected function _change_reg_status()
1794
-    {
1795
-        $this->request->setRequestParam('return', 'view_registration');
1796
-        // set notify based on whether the send notifications toggle is set or not
1797
-        $notify     = $this->request->getRequestParam('reg_status_change_form[send_notifications]', false, 'bool');
1798
-        $reg_status = $this->request->getRequestParam('reg_status_change_form[reg_status]', '');
1799
-        $this->request->setRequestParam('reg_status_change_form[reg_status]', $reg_status);
1800
-        switch ($reg_status) {
1801
-            case EEM_Registration::status_id_approved:
1802
-            case EEH_Template::pretty_status(EEM_Registration::status_id_approved, false, 'sentence'):
1803
-                $this->approve_registration($notify);
1804
-                break;
1805
-            case EEM_Registration::status_id_pending_payment:
1806
-            case EEH_Template::pretty_status(EEM_Registration::status_id_pending_payment, false, 'sentence'):
1807
-                $this->pending_registration($notify);
1808
-                break;
1809
-            case EEM_Registration::status_id_not_approved:
1810
-            case EEH_Template::pretty_status(EEM_Registration::status_id_not_approved, false, 'sentence'):
1811
-                $this->not_approve_registration($notify);
1812
-                break;
1813
-            case EEM_Registration::status_id_declined:
1814
-            case EEH_Template::pretty_status(EEM_Registration::status_id_declined, false, 'sentence'):
1815
-                $this->decline_registration($notify);
1816
-                break;
1817
-            case EEM_Registration::status_id_cancelled:
1818
-            case EEH_Template::pretty_status(EEM_Registration::status_id_cancelled, false, 'sentence'):
1819
-                $this->cancel_registration($notify);
1820
-                break;
1821
-            case EEM_Registration::status_id_wait_list:
1822
-            case EEH_Template::pretty_status(EEM_Registration::status_id_wait_list, false, 'sentence'):
1823
-                $this->wait_list_registration($notify);
1824
-                break;
1825
-            case EEM_Registration::status_id_incomplete:
1826
-            default:
1827
-                $this->request->unSetRequestParam('return');
1828
-                $this->_reg_status_change_return('');
1829
-                break;
1830
-        }
1831
-    }
1832
-
1833
-
1834
-    /**
1835
-     * Callback for bulk action routes.
1836
-     * Note: although we could just register the singular route callbacks for each bulk action route as well, this
1837
-     * method was chosen so there is one central place all the registration status bulk actions are going through.
1838
-     * Potentially, this provides an easier place to locate logic that is specific to these bulk actions (as opposed to
1839
-     * when an action is happening on just a single registration).
1840
-     *
1841
-     * @param      $action
1842
-     * @param bool $notify
1843
-     */
1844
-    protected function bulk_action_on_registrations($action, $notify = false)
1845
-    {
1846
-        do_action(
1847
-            'AHEE__Registrations_Admin_Page__bulk_action_on_registrations__before_execution',
1848
-            $this,
1849
-            $action,
1850
-            $notify
1851
-        );
1852
-        $method = $action . '_registration';
1853
-        if (method_exists($this, $method)) {
1854
-            $this->$method($notify);
1855
-        }
1856
-    }
1857
-
1858
-
1859
-    /**
1860
-     * approve_registration
1861
-     *
1862
-     * @param bool $notify whether or not to notify the registrant about their approval.
1863
-     * @return void
1864
-     * @throws EE_Error
1865
-     * @throws EntityNotFoundException
1866
-     * @throws InvalidArgumentException
1867
-     * @throws InvalidDataTypeException
1868
-     * @throws InvalidInterfaceException
1869
-     * @throws ReflectionException
1870
-     * @throws RuntimeException
1871
-     * @throws DomainException
1872
-     */
1873
-    protected function approve_registration($notify = false)
1874
-    {
1875
-        $this->_reg_status_change_return(EEM_Registration::status_id_approved, $notify);
1876
-    }
1877
-
1878
-
1879
-    /**
1880
-     * decline_registration
1881
-     *
1882
-     * @param bool $notify whether or not to notify the registrant about their status change.
1883
-     * @return void
1884
-     * @throws EE_Error
1885
-     * @throws EntityNotFoundException
1886
-     * @throws InvalidArgumentException
1887
-     * @throws InvalidDataTypeException
1888
-     * @throws InvalidInterfaceException
1889
-     * @throws ReflectionException
1890
-     * @throws RuntimeException
1891
-     * @throws DomainException
1892
-     */
1893
-    protected function decline_registration($notify = false)
1894
-    {
1895
-        $this->_reg_status_change_return(EEM_Registration::status_id_declined, $notify);
1896
-    }
1897
-
1898
-
1899
-    /**
1900
-     * cancel_registration
1901
-     *
1902
-     * @param bool $notify whether or not to notify the registrant about their status change.
1903
-     * @return void
1904
-     * @throws EE_Error
1905
-     * @throws EntityNotFoundException
1906
-     * @throws InvalidArgumentException
1907
-     * @throws InvalidDataTypeException
1908
-     * @throws InvalidInterfaceException
1909
-     * @throws ReflectionException
1910
-     * @throws RuntimeException
1911
-     * @throws DomainException
1912
-     */
1913
-    protected function cancel_registration($notify = false)
1914
-    {
1915
-        $this->_reg_status_change_return(EEM_Registration::status_id_cancelled, $notify);
1916
-    }
1917
-
1918
-
1919
-    /**
1920
-     * not_approve_registration
1921
-     *
1922
-     * @param bool $notify whether or not to notify the registrant about their status change.
1923
-     * @return void
1924
-     * @throws EE_Error
1925
-     * @throws EntityNotFoundException
1926
-     * @throws InvalidArgumentException
1927
-     * @throws InvalidDataTypeException
1928
-     * @throws InvalidInterfaceException
1929
-     * @throws ReflectionException
1930
-     * @throws RuntimeException
1931
-     * @throws DomainException
1932
-     */
1933
-    protected function not_approve_registration($notify = false)
1934
-    {
1935
-        $this->_reg_status_change_return(EEM_Registration::status_id_not_approved, $notify);
1936
-    }
1937
-
1938
-
1939
-    /**
1940
-     * decline_registration
1941
-     *
1942
-     * @param bool $notify whether or not to notify the registrant about their status change.
1943
-     * @return void
1944
-     * @throws EE_Error
1945
-     * @throws EntityNotFoundException
1946
-     * @throws InvalidArgumentException
1947
-     * @throws InvalidDataTypeException
1948
-     * @throws InvalidInterfaceException
1949
-     * @throws ReflectionException
1950
-     * @throws RuntimeException
1951
-     * @throws DomainException
1952
-     */
1953
-    protected function pending_registration($notify = false)
1954
-    {
1955
-        $this->_reg_status_change_return(EEM_Registration::status_id_pending_payment, $notify);
1956
-    }
1957
-
1958
-
1959
-    /**
1960
-     * waitlist_registration
1961
-     *
1962
-     * @param bool $notify whether or not to notify the registrant about their status change.
1963
-     * @return void
1964
-     * @throws EE_Error
1965
-     * @throws EntityNotFoundException
1966
-     * @throws InvalidArgumentException
1967
-     * @throws InvalidDataTypeException
1968
-     * @throws InvalidInterfaceException
1969
-     * @throws ReflectionException
1970
-     * @throws RuntimeException
1971
-     * @throws DomainException
1972
-     */
1973
-    protected function wait_list_registration($notify = false)
1974
-    {
1975
-        $this->_reg_status_change_return(EEM_Registration::status_id_wait_list, $notify);
1976
-    }
1977
-
1978
-
1979
-    /**
1980
-     * generates HTML for the Registration main meta box
1981
-     *
1982
-     * @return void
1983
-     * @throws DomainException
1984
-     * @throws EE_Error
1985
-     * @throws InvalidArgumentException
1986
-     * @throws InvalidDataTypeException
1987
-     * @throws InvalidInterfaceException
1988
-     * @throws ReflectionException
1989
-     * @throws EntityNotFoundException
1990
-     */
1991
-    public function _reg_details_meta_box()
1992
-    {
1993
-        EEH_Autoloader::register_line_item_display_autoloaders();
1994
-        EEH_Autoloader::register_line_item_filter_autoloaders();
1995
-        EE_Registry::instance()->load_helper('Line_Item');
1996
-        $transaction    = $this->_registration->transaction() ? $this->_registration->transaction()
1997
-            : EE_Transaction::new_instance();
1998
-        $this->_session = $transaction->session_data();
1999
-        $filters        = new EE_Line_Item_Filter_Collection();
2000
-        $filters->add(new EE_Single_Registration_Line_Item_Filter($this->_registration));
2001
-        $filters->add(new EE_Non_Zero_Line_Item_Filter());
2002
-        $line_item_filter_processor              = new EE_Line_Item_Filter_Processor(
2003
-            $filters,
2004
-            $transaction->total_line_item()
2005
-        );
2006
-        $filtered_line_item_tree                 = $line_item_filter_processor->process();
2007
-        $line_item_display                       = new EE_Line_Item_Display(
2008
-            'reg_admin_table',
2009
-            'EE_Admin_Table_Registration_Line_Item_Display_Strategy'
2010
-        );
2011
-        $this->_template_args['line_item_table'] = $line_item_display->display_line_item(
2012
-            $filtered_line_item_tree,
2013
-            ['EE_Registration' => $this->_registration]
2014
-        );
2015
-        $attendee                                = $this->_registration->attendee();
2016
-        if (
2017
-            $this->capabilities->current_user_can(
2018
-                'ee_read_transaction',
2019
-                'espresso_transactions_view_transaction'
2020
-            )
2021
-        ) {
2022
-            $this->_template_args['view_transaction_button'] = EEH_Template::get_button_or_link(
2023
-                EE_Admin_Page::add_query_args_and_nonce(
2024
-                    [
2025
-                        'action' => 'view_transaction',
2026
-                        'TXN_ID' => $transaction->ID(),
2027
-                    ],
2028
-                    TXN_ADMIN_URL
2029
-                ),
2030
-                esc_html__(' View Transaction', 'event_espresso'),
2031
-                'button button--secondary right',
2032
-                'dashicons dashicons-cart'
2033
-            );
2034
-        } else {
2035
-            $this->_template_args['view_transaction_button'] = '';
2036
-        }
2037
-        if (
2038
-            $attendee instanceof EE_Attendee
2039
-            && $this->capabilities->current_user_can(
2040
-                'ee_send_message',
2041
-                'espresso_registrations_resend_registration'
2042
-            )
2043
-        ) {
2044
-            $this->_template_args['resend_registration_button'] = EEH_Template::get_button_or_link(
2045
-                EE_Admin_Page::add_query_args_and_nonce(
2046
-                    [
2047
-                        'action'      => 'resend_registration',
2048
-                        '_REG_ID'     => $this->_registration->ID(),
2049
-                        'redirect_to' => 'view_registration',
2050
-                    ],
2051
-                    REG_ADMIN_URL
2052
-                ),
2053
-                esc_html__(' Resend Registration', 'event_espresso'),
2054
-                'button button--secondary right',
2055
-                'dashicons dashicons-email-alt'
2056
-            );
2057
-        } else {
2058
-            $this->_template_args['resend_registration_button'] = '';
2059
-        }
2060
-        $this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
2061
-        $payment                               = $transaction->get_first_related('Payment');
2062
-        $payment                               = ! $payment instanceof EE_Payment
2063
-            ? EE_Payment::new_instance()
2064
-            : $payment;
2065
-        $payment_method                        = $payment->get_first_related('Payment_Method');
2066
-        $payment_method                        = ! $payment_method instanceof EE_Payment_Method
2067
-            ? EE_Payment_Method::new_instance()
2068
-            : $payment_method;
2069
-        $reg_details                           = [
2070
-            'payment_method'       => $payment_method->name(),
2071
-            'response_msg'         => $payment->gateway_response(),
2072
-            'registration_id'      => $this->_registration->get('REG_code'),
2073
-            'registration_session' => $this->_registration->session_ID(),
2074
-            'ip_address'           => isset($this->_session['ip_address']) ? $this->_session['ip_address'] : '',
2075
-            'user_agent'           => isset($this->_session['user_agent']) ? $this->_session['user_agent'] : '',
2076
-        ];
2077
-        if (isset($reg_details['registration_id'])) {
2078
-            $this->_template_args['reg_details']['registration_id']['value'] = $reg_details['registration_id'];
2079
-            $this->_template_args['reg_details']['registration_id']['label'] = esc_html__(
2080
-                'Registration ID',
2081
-                'event_espresso'
2082
-            );
2083
-            $this->_template_args['reg_details']['registration_id']['class'] = 'regular-text';
2084
-        }
2085
-        if (isset($reg_details['payment_method'])) {
2086
-            $this->_template_args['reg_details']['payment_method']['value'] = $reg_details['payment_method'];
2087
-            $this->_template_args['reg_details']['payment_method']['label'] = esc_html__(
2088
-                'Most Recent Payment Method',
2089
-                'event_espresso'
2090
-            );
2091
-            $this->_template_args['reg_details']['payment_method']['class'] = 'regular-text';
2092
-            $this->_template_args['reg_details']['response_msg']['value']   = $reg_details['response_msg'];
2093
-            $this->_template_args['reg_details']['response_msg']['label']   = esc_html__(
2094
-                'Payment method response',
2095
-                'event_espresso'
2096
-            );
2097
-            $this->_template_args['reg_details']['response_msg']['class']   = 'regular-text';
2098
-        }
2099
-        $this->_template_args['reg_details']['registration_session']['value'] = $reg_details['registration_session'];
2100
-        $this->_template_args['reg_details']['registration_session']['label'] = esc_html__(
2101
-            'Registration Session',
2102
-            'event_espresso'
2103
-        );
2104
-        $this->_template_args['reg_details']['registration_session']['class'] = 'regular-text';
2105
-        $this->_template_args['reg_details']['ip_address']['value']           = $reg_details['ip_address'];
2106
-        $this->_template_args['reg_details']['ip_address']['label']           = esc_html__(
2107
-            'Registration placed from IP',
2108
-            'event_espresso'
2109
-        );
2110
-        $this->_template_args['reg_details']['ip_address']['class']           = 'regular-text';
2111
-        $this->_template_args['reg_details']['user_agent']['value']           = $reg_details['user_agent'];
2112
-        $this->_template_args['reg_details']['user_agent']['label']           = esc_html__(
2113
-            'Registrant User Agent',
2114
-            'event_espresso'
2115
-        );
2116
-        $this->_template_args['reg_details']['user_agent']['class']           = 'large-text';
2117
-        $this->_template_args['event_link']                                   = EE_Admin_Page::add_query_args_and_nonce(
2118
-            [
2119
-                'action'   => 'default',
2120
-                'event_id' => $this->_registration->event_ID(),
2121
-            ],
2122
-            REG_ADMIN_URL
2123
-        );
2124
-
2125
-        $this->_template_args['REG_ID']   = $this->_registration->ID();
2126
-        $this->_template_args['event_id'] = $this->_registration->event_ID();
2127
-
2128
-        $template_path = REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_reg_details.template.php';
2129
-        EEH_Template::display_template($template_path, $this->_template_args); // already escaped
2130
-    }
2131
-
2132
-
2133
-    /**
2134
-     * generates HTML for the Registration Questions meta box.
2135
-     * If pre-4.8.32.rc.000 hooks are used, uses old methods (with its filters),
2136
-     * otherwise uses new forms system
2137
-     *
2138
-     * @return void
2139
-     * @throws DomainException
2140
-     * @throws EE_Error
2141
-     * @throws InvalidArgumentException
2142
-     * @throws InvalidDataTypeException
2143
-     * @throws InvalidInterfaceException
2144
-     * @throws ReflectionException
2145
-     */
2146
-    public function _reg_questions_meta_box()
2147
-    {
2148
-        // allow someone to override this method entirely
2149
-        if (
2150
-            apply_filters(
2151
-                'FHEE__Registrations_Admin_Page___reg_questions_meta_box__do_default',
2152
-                true,
2153
-                $this,
2154
-                $this->_registration
2155
-            )
2156
-        ) {
2157
-            $form = $this->_get_reg_custom_questions_form(
2158
-                $this->_registration->ID()
2159
-            );
2160
-
2161
-            $this->_template_args['att_questions'] = count($form->subforms()) > 0
2162
-                ? $form->get_html_and_js()
2163
-                : '';
2164
-
2165
-            $this->_template_args['reg_questions_form_action'] = 'edit_registration';
2166
-            $this->_template_args['REG_ID']                    = $this->_registration->ID();
2167
-            $template_path                                     =
2168
-                REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_reg_questions.template.php';
2169
-            EEH_Template::display_template($template_path, $this->_template_args);
2170
-        }
2171
-    }
2172
-
2173
-
2174
-    /**
2175
-     * form_before_question_group
2176
-     *
2177
-     * @param string $output
2178
-     * @return        string
2179
-     * @deprecated    as of 4.8.32.rc.000
2180
-     */
2181
-    public function form_before_question_group($output)
2182
-    {
2183
-        EE_Error::doing_it_wrong(
2184
-            __CLASS__ . '::' . __FUNCTION__,
2185
-            esc_html__(
2186
-                '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.',
2187
-                'event_espresso'
2188
-            ),
2189
-            '4.8.32.rc.000'
2190
-        );
2191
-        return '
24
+	/**
25
+	 * @var EE_Registration
26
+	 */
27
+	private $_registration;
28
+
29
+	/**
30
+	 * @var EE_Event
31
+	 */
32
+	private $_reg_event;
33
+
34
+	/**
35
+	 * @var EE_Session
36
+	 */
37
+	private $_session;
38
+
39
+	/**
40
+	 * @var array
41
+	 */
42
+	private static $_reg_status;
43
+
44
+	/**
45
+	 * Form for displaying the custom questions for this registration.
46
+	 * This gets used a few times throughout the request so its best to cache it
47
+	 *
48
+	 * @var EE_Registration_Custom_Questions_Form
49
+	 */
50
+	protected $_reg_custom_questions_form;
51
+
52
+	/**
53
+	 * @var EEM_Registration $registration_model
54
+	 */
55
+	private $registration_model;
56
+
57
+	/**
58
+	 * @var EEM_Attendee $attendee_model
59
+	 */
60
+	private $attendee_model;
61
+
62
+	/**
63
+	 * @var EEM_Event $event_model
64
+	 */
65
+	private $event_model;
66
+
67
+	/**
68
+	 * @var EEM_Status $status_model
69
+	 */
70
+	private $status_model;
71
+
72
+
73
+	/**
74
+	 * @param bool $routing
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
+		$this->cpt_editpost_route = 'edit_attendee';
84
+		add_action('wp_loaded', [$this, 'wp_loaded']);
85
+	}
86
+
87
+
88
+	/**
89
+	 * @return EEM_Registration
90
+	 * @throws InvalidArgumentException
91
+	 * @throws InvalidDataTypeException
92
+	 * @throws InvalidInterfaceException
93
+	 * @since 4.10.2.p
94
+	 */
95
+	protected function getRegistrationModel()
96
+	{
97
+		if (! $this->registration_model instanceof EEM_Registration) {
98
+			$this->registration_model = $this->loader->getShared('EEM_Registration');
99
+		}
100
+		return $this->registration_model;
101
+	}
102
+
103
+
104
+	/**
105
+	 * @return EEM_Attendee
106
+	 * @throws InvalidArgumentException
107
+	 * @throws InvalidDataTypeException
108
+	 * @throws InvalidInterfaceException
109
+	 * @since 4.10.2.p
110
+	 */
111
+	protected function getAttendeeModel()
112
+	{
113
+		if (! $this->attendee_model instanceof EEM_Attendee) {
114
+			$this->attendee_model = $this->loader->getShared('EEM_Attendee');
115
+		}
116
+		return $this->attendee_model;
117
+	}
118
+
119
+
120
+	/**
121
+	 * @return EEM_Event
122
+	 * @throws InvalidArgumentException
123
+	 * @throws InvalidDataTypeException
124
+	 * @throws InvalidInterfaceException
125
+	 * @since 4.10.2.p
126
+	 */
127
+	protected function getEventModel()
128
+	{
129
+		if (! $this->event_model instanceof EEM_Event) {
130
+			$this->event_model = $this->loader->getShared('EEM_Event');
131
+		}
132
+		return $this->event_model;
133
+	}
134
+
135
+
136
+	/**
137
+	 * @return EEM_Status
138
+	 * @throws InvalidArgumentException
139
+	 * @throws InvalidDataTypeException
140
+	 * @throws InvalidInterfaceException
141
+	 * @since 4.10.2.p
142
+	 */
143
+	protected function getStatusModel()
144
+	{
145
+		if (! $this->status_model instanceof EEM_Status) {
146
+			$this->status_model = $this->loader->getShared('EEM_Status');
147
+		}
148
+		return $this->status_model;
149
+	}
150
+
151
+
152
+	public function wp_loaded()
153
+	{
154
+		// when adding a new registration...
155
+		$action = $this->request->getRequestParam('action');
156
+		if ($action === 'new_registration') {
157
+			EE_System::do_not_cache();
158
+			if ($this->request->getRequestParam('processing_registration', 0, 'int') !== 1) {
159
+				// and it's NOT the attendee information reg step
160
+				// force cookie expiration by setting time to last week
161
+				setcookie('ee_registration_added', 0, time() - WEEK_IN_SECONDS, '/');
162
+				// and update the global
163
+				$_COOKIE['ee_registration_added'] = 0;
164
+			}
165
+		}
166
+	}
167
+
168
+
169
+	protected function _init_page_props()
170
+	{
171
+		$this->page_slug        = REG_PG_SLUG;
172
+		$this->_admin_base_url  = REG_ADMIN_URL;
173
+		$this->_admin_base_path = REG_ADMIN;
174
+		$this->page_label       = esc_html__('Registrations', 'event_espresso');
175
+		$this->_cpt_routes      = [
176
+			'add_new_attendee' => 'espresso_attendees',
177
+			'edit_attendee'    => 'espresso_attendees',
178
+			'insert_attendee'  => 'espresso_attendees',
179
+			'update_attendee'  => 'espresso_attendees',
180
+		];
181
+		$this->_cpt_model_names = [
182
+			'add_new_attendee' => 'EEM_Attendee',
183
+			'edit_attendee'    => 'EEM_Attendee',
184
+		];
185
+		$this->_cpt_edit_routes = [
186
+			'espresso_attendees' => 'edit_attendee',
187
+		];
188
+		$this->_pagenow_map     = [
189
+			'add_new_attendee' => 'post-new.php',
190
+			'edit_attendee'    => 'post.php',
191
+			'trash'            => 'post.php',
192
+		];
193
+		add_action('edit_form_after_title', [$this, 'after_title_form_fields'], 10);
194
+		// add filters so that the comment urls don't take users to a confusing 404 page
195
+		add_filter('get_comment_link', [$this, 'clear_comment_link'], 10, 2);
196
+	}
197
+
198
+
199
+	/**
200
+	 * @param string     $link    The comment permalink with '#comment-$id' appended.
201
+	 * @param WP_Comment $comment The current comment object.
202
+	 * @return string
203
+	 */
204
+	public function clear_comment_link($link, WP_Comment $comment)
205
+	{
206
+		// gotta make sure this only happens on this route
207
+		$post_type = get_post_type($comment->comment_post_ID);
208
+		if ($post_type === 'espresso_attendees') {
209
+			return '#commentsdiv';
210
+		}
211
+		return $link;
212
+	}
213
+
214
+
215
+	protected function _ajax_hooks()
216
+	{
217
+		// todo: all hooks for registrations ajax goes in here
218
+		add_action('wp_ajax_toggle_checkin_status', [$this, 'toggle_checkin_status']);
219
+	}
220
+
221
+
222
+	protected function _define_page_props()
223
+	{
224
+		$this->_admin_page_title = $this->page_label;
225
+		$this->_labels           = [
226
+			'buttons'                      => [
227
+				'add-registrant'      => esc_html__('Add New Registration', 'event_espresso'),
228
+				'add-attendee'        => esc_html__('Add Contact', 'event_espresso'),
229
+				'edit'                => esc_html__('Edit Contact', 'event_espresso'),
230
+				'csv_reg_report'      => esc_html__('Registrations CSV Report', 'event_espresso'),
231
+				'contact_list_report' => esc_html__('Contact List Report', 'event_espresso'),
232
+				'contact_list_export' => esc_html__('Export Data', 'event_espresso'),
233
+			],
234
+			'publishbox'                   => [
235
+				'add_new_attendee' => esc_html__('Add Contact Record', 'event_espresso'),
236
+				'edit_attendee'    => esc_html__('Update Contact Record', 'event_espresso'),
237
+			],
238
+			'hide_add_button_on_cpt_route' => [
239
+				'edit_attendee' => true,
240
+			],
241
+		];
242
+	}
243
+
244
+
245
+	/**
246
+	 * grab url requests and route them
247
+	 *
248
+	 * @return void
249
+	 * @throws EE_Error
250
+	 */
251
+	public function _set_page_routes()
252
+	{
253
+		$this->_get_registration_status_array();
254
+		$REG_ID             = $this->request->getRequestParam('_REG_ID', 0, 'int');
255
+		$REG_ID             = $this->request->getRequestParam('reg_status_change_form[REG_ID]', $REG_ID, 'int');
256
+		$ATT_ID             = $this->request->getRequestParam('ATT_ID', 0, 'int');
257
+		$ATT_ID             = $this->request->getRequestParam('post', $ATT_ID, 'int');
258
+		$this->_page_routes = [
259
+			'default'                             => [
260
+				'func'       => [$this, '_registrations_overview_list_table'],
261
+				'capability' => 'ee_read_registrations',
262
+			],
263
+			'view_registration'                   => [
264
+				'func'       => [$this, '_registration_details'],
265
+				'capability' => 'ee_read_registration',
266
+				'obj_id'     => $REG_ID,
267
+			],
268
+			'edit_registration'                   => [
269
+				'func'               => '_update_attendee_registration_form',
270
+				'noheader'           => true,
271
+				'headers_sent_route' => 'view_registration',
272
+				'capability'         => 'ee_edit_registration',
273
+				'obj_id'             => $REG_ID,
274
+				'_REG_ID'            => $REG_ID,
275
+			],
276
+			'trash_registrations'                 => [
277
+				'func'       => '_trash_or_restore_registrations',
278
+				'args'       => ['trash' => true],
279
+				'noheader'   => true,
280
+				'capability' => 'ee_delete_registrations',
281
+			],
282
+			'restore_registrations'               => [
283
+				'func'       => '_trash_or_restore_registrations',
284
+				'args'       => ['trash' => false],
285
+				'noheader'   => true,
286
+				'capability' => 'ee_delete_registrations',
287
+			],
288
+			'delete_registrations'                => [
289
+				'func'       => '_delete_registrations',
290
+				'noheader'   => true,
291
+				'capability' => 'ee_delete_registrations',
292
+			],
293
+			'new_registration'                    => [
294
+				'func'       => 'new_registration',
295
+				'capability' => 'ee_edit_registrations',
296
+			],
297
+			'process_reg_step'                    => [
298
+				'func'       => 'process_reg_step',
299
+				'noheader'   => true,
300
+				'capability' => 'ee_edit_registrations',
301
+			],
302
+			'redirect_to_txn'                     => [
303
+				'func'       => 'redirect_to_txn',
304
+				'noheader'   => true,
305
+				'capability' => 'ee_edit_registrations',
306
+			],
307
+			'change_reg_status'                   => [
308
+				'func'       => '_change_reg_status',
309
+				'noheader'   => true,
310
+				'capability' => 'ee_edit_registration',
311
+				'obj_id'     => $REG_ID,
312
+			],
313
+			'approve_registration'                => [
314
+				'func'       => 'approve_registration',
315
+				'noheader'   => true,
316
+				'capability' => 'ee_edit_registration',
317
+				'obj_id'     => $REG_ID,
318
+			],
319
+			'approve_and_notify_registration'     => [
320
+				'func'       => 'approve_registration',
321
+				'noheader'   => true,
322
+				'args'       => [true],
323
+				'capability' => 'ee_edit_registration',
324
+				'obj_id'     => $REG_ID,
325
+			],
326
+			'approve_registrations'               => [
327
+				'func'       => 'bulk_action_on_registrations',
328
+				'noheader'   => true,
329
+				'capability' => 'ee_edit_registrations',
330
+				'args'       => ['approve'],
331
+			],
332
+			'approve_and_notify_registrations'    => [
333
+				'func'       => 'bulk_action_on_registrations',
334
+				'noheader'   => true,
335
+				'capability' => 'ee_edit_registrations',
336
+				'args'       => ['approve', true],
337
+			],
338
+			'decline_registration'                => [
339
+				'func'       => 'decline_registration',
340
+				'noheader'   => true,
341
+				'capability' => 'ee_edit_registration',
342
+				'obj_id'     => $REG_ID,
343
+			],
344
+			'decline_and_notify_registration'     => [
345
+				'func'       => 'decline_registration',
346
+				'noheader'   => true,
347
+				'args'       => [true],
348
+				'capability' => 'ee_edit_registration',
349
+				'obj_id'     => $REG_ID,
350
+			],
351
+			'decline_registrations'               => [
352
+				'func'       => 'bulk_action_on_registrations',
353
+				'noheader'   => true,
354
+				'capability' => 'ee_edit_registrations',
355
+				'args'       => ['decline'],
356
+			],
357
+			'decline_and_notify_registrations'    => [
358
+				'func'       => 'bulk_action_on_registrations',
359
+				'noheader'   => true,
360
+				'capability' => 'ee_edit_registrations',
361
+				'args'       => ['decline', true],
362
+			],
363
+			'pending_registration'                => [
364
+				'func'       => 'pending_registration',
365
+				'noheader'   => true,
366
+				'capability' => 'ee_edit_registration',
367
+				'obj_id'     => $REG_ID,
368
+			],
369
+			'pending_and_notify_registration'     => [
370
+				'func'       => 'pending_registration',
371
+				'noheader'   => true,
372
+				'args'       => [true],
373
+				'capability' => 'ee_edit_registration',
374
+				'obj_id'     => $REG_ID,
375
+			],
376
+			'pending_registrations'               => [
377
+				'func'       => 'bulk_action_on_registrations',
378
+				'noheader'   => true,
379
+				'capability' => 'ee_edit_registrations',
380
+				'args'       => ['pending'],
381
+			],
382
+			'pending_and_notify_registrations'    => [
383
+				'func'       => 'bulk_action_on_registrations',
384
+				'noheader'   => true,
385
+				'capability' => 'ee_edit_registrations',
386
+				'args'       => ['pending', true],
387
+			],
388
+			'no_approve_registration'             => [
389
+				'func'       => 'not_approve_registration',
390
+				'noheader'   => true,
391
+				'capability' => 'ee_edit_registration',
392
+				'obj_id'     => $REG_ID,
393
+			],
394
+			'no_approve_and_notify_registration'  => [
395
+				'func'       => 'not_approve_registration',
396
+				'noheader'   => true,
397
+				'args'       => [true],
398
+				'capability' => 'ee_edit_registration',
399
+				'obj_id'     => $REG_ID,
400
+			],
401
+			'no_approve_registrations'            => [
402
+				'func'       => 'bulk_action_on_registrations',
403
+				'noheader'   => true,
404
+				'capability' => 'ee_edit_registrations',
405
+				'args'       => ['not_approve'],
406
+			],
407
+			'no_approve_and_notify_registrations' => [
408
+				'func'       => 'bulk_action_on_registrations',
409
+				'noheader'   => true,
410
+				'capability' => 'ee_edit_registrations',
411
+				'args'       => ['not_approve', true],
412
+			],
413
+			'cancel_registration'                 => [
414
+				'func'       => 'cancel_registration',
415
+				'noheader'   => true,
416
+				'capability' => 'ee_edit_registration',
417
+				'obj_id'     => $REG_ID,
418
+			],
419
+			'cancel_and_notify_registration'      => [
420
+				'func'       => 'cancel_registration',
421
+				'noheader'   => true,
422
+				'args'       => [true],
423
+				'capability' => 'ee_edit_registration',
424
+				'obj_id'     => $REG_ID,
425
+			],
426
+			'cancel_registrations'                => [
427
+				'func'       => 'bulk_action_on_registrations',
428
+				'noheader'   => true,
429
+				'capability' => 'ee_edit_registrations',
430
+				'args'       => ['cancel'],
431
+			],
432
+			'cancel_and_notify_registrations'     => [
433
+				'func'       => 'bulk_action_on_registrations',
434
+				'noheader'   => true,
435
+				'capability' => 'ee_edit_registrations',
436
+				'args'       => ['cancel', true],
437
+			],
438
+			'wait_list_registration'              => [
439
+				'func'       => 'wait_list_registration',
440
+				'noheader'   => true,
441
+				'capability' => 'ee_edit_registration',
442
+				'obj_id'     => $REG_ID,
443
+			],
444
+			'wait_list_and_notify_registration'   => [
445
+				'func'       => 'wait_list_registration',
446
+				'noheader'   => true,
447
+				'args'       => [true],
448
+				'capability' => 'ee_edit_registration',
449
+				'obj_id'     => $REG_ID,
450
+			],
451
+			'contact_list'                        => [
452
+				'func'       => '_attendee_contact_list_table',
453
+				'capability' => 'ee_read_contacts',
454
+			],
455
+			'add_new_attendee'                    => [
456
+				'func' => '_create_new_cpt_item',
457
+				'args' => [
458
+					'new_attendee' => true,
459
+					'capability'   => 'ee_edit_contacts',
460
+				],
461
+			],
462
+			'edit_attendee'                       => [
463
+				'func'       => '_edit_cpt_item',
464
+				'capability' => 'ee_edit_contacts',
465
+				'obj_id'     => $ATT_ID,
466
+			],
467
+			'duplicate_attendee'                  => [
468
+				'func'       => '_duplicate_attendee',
469
+				'noheader'   => true,
470
+				'capability' => 'ee_edit_contacts',
471
+				'obj_id'     => $ATT_ID,
472
+			],
473
+			'insert_attendee'                     => [
474
+				'func'       => '_insert_or_update_attendee',
475
+				'args'       => [
476
+					'new_attendee' => true,
477
+				],
478
+				'noheader'   => true,
479
+				'capability' => 'ee_edit_contacts',
480
+			],
481
+			'update_attendee'                     => [
482
+				'func'       => '_insert_or_update_attendee',
483
+				'args'       => [
484
+					'new_attendee' => false,
485
+				],
486
+				'noheader'   => true,
487
+				'capability' => 'ee_edit_contacts',
488
+				'obj_id'     => $ATT_ID,
489
+			],
490
+			'trash_attendees'                     => [
491
+				'func'       => '_trash_or_restore_attendees',
492
+				'args'       => [
493
+					'trash' => 'true',
494
+				],
495
+				'noheader'   => true,
496
+				'capability' => 'ee_delete_contacts',
497
+			],
498
+			'trash_attendee'                      => [
499
+				'func'       => '_trash_or_restore_attendees',
500
+				'args'       => [
501
+					'trash' => true,
502
+				],
503
+				'noheader'   => true,
504
+				'capability' => 'ee_delete_contacts',
505
+				'obj_id'     => $ATT_ID,
506
+			],
507
+			'restore_attendees'                   => [
508
+				'func'       => '_trash_or_restore_attendees',
509
+				'args'       => [
510
+					'trash' => false,
511
+				],
512
+				'noheader'   => true,
513
+				'capability' => 'ee_delete_contacts',
514
+				'obj_id'     => $ATT_ID,
515
+			],
516
+			'resend_registration'                 => [
517
+				'func'       => '_resend_registration',
518
+				'noheader'   => true,
519
+				'capability' => 'ee_send_message',
520
+			],
521
+			'registrations_report'                => [
522
+				'func'       => [$this, '_registrations_report'],
523
+				'noheader'   => true,
524
+				'capability' => 'ee_read_registrations',
525
+			],
526
+			'contact_list_export'                 => [
527
+				'func'       => '_contact_list_export',
528
+				'noheader'   => true,
529
+				'capability' => 'export',
530
+			],
531
+			'contact_list_report'                 => [
532
+				'func'       => '_contact_list_report',
533
+				'noheader'   => true,
534
+				'capability' => 'ee_read_contacts',
535
+			],
536
+		];
537
+	}
538
+
539
+
540
+	protected function _set_page_config()
541
+	{
542
+		$REG_ID             = $this->request->getRequestParam('_REG_ID', 0, 'int');
543
+		$ATT_ID             = $this->request->getRequestParam('ATT_ID', 0, 'int');
544
+		$this->_page_config = [
545
+			'default'           => [
546
+				'nav'           => [
547
+					'label' => esc_html__('Overview', 'event_espresso'),
548
+					'icon'  => 'dashicons-list-view',
549
+					'order' => 5,
550
+				],
551
+				'help_tabs'     => [
552
+					'registrations_overview_help_tab'                       => [
553
+						'title'    => esc_html__('Registrations Overview', 'event_espresso'),
554
+						'filename' => 'registrations_overview',
555
+					],
556
+					'registrations_overview_table_column_headings_help_tab' => [
557
+						'title'    => esc_html__('Registrations Table Column Headings', 'event_espresso'),
558
+						'filename' => 'registrations_overview_table_column_headings',
559
+					],
560
+					'registrations_overview_filters_help_tab'               => [
561
+						'title'    => esc_html__('Registration Filters', 'event_espresso'),
562
+						'filename' => 'registrations_overview_filters',
563
+					],
564
+					'registrations_overview_views_help_tab'                 => [
565
+						'title'    => esc_html__('Registration Views', 'event_espresso'),
566
+						'filename' => 'registrations_overview_views',
567
+					],
568
+					'registrations_regoverview_other_help_tab'              => [
569
+						'title'    => esc_html__('Registrations Other', 'event_espresso'),
570
+						'filename' => 'registrations_overview_other',
571
+					],
572
+				],
573
+				'list_table'    => 'EE_Registrations_List_Table',
574
+				'require_nonce' => false,
575
+			],
576
+			'view_registration' => [
577
+				'nav'           => [
578
+					'label'      => esc_html__('REG Details', 'event_espresso'),
579
+					'icon'       => 'dashicons-clipboard',
580
+					'order'      => 15,
581
+					'url'        => $REG_ID
582
+						? add_query_arg(['_REG_ID' => $REG_ID], $this->_current_page_view_url)
583
+						: $this->_admin_base_url,
584
+					'persistent' => false,
585
+				],
586
+				'help_tabs'     => [
587
+					'registrations_details_help_tab'                    => [
588
+						'title'    => esc_html__('Registration Details', 'event_espresso'),
589
+						'filename' => 'registrations_details',
590
+					],
591
+					'registrations_details_table_help_tab'              => [
592
+						'title'    => esc_html__('Registration Details Table', 'event_espresso'),
593
+						'filename' => 'registrations_details_table',
594
+					],
595
+					'registrations_details_form_answers_help_tab'       => [
596
+						'title'    => esc_html__('Registration Form Answers', 'event_espresso'),
597
+						'filename' => 'registrations_details_form_answers',
598
+					],
599
+					'registrations_details_registrant_details_help_tab' => [
600
+						'title'    => esc_html__('Contact Details', 'event_espresso'),
601
+						'filename' => 'registrations_details_registrant_details',
602
+					],
603
+				],
604
+				'metaboxes'     => array_merge(
605
+					$this->_default_espresso_metaboxes,
606
+					['_registration_details_metaboxes']
607
+				),
608
+				'require_nonce' => false,
609
+			],
610
+			'new_registration'  => [
611
+				'nav'           => [
612
+					'label'      => esc_html__('Add New Registration', 'event_espresso'),
613
+					'icon'       => 'dashicons-plus-alt',
614
+					'url'        => '#',
615
+					'order'      => 15,
616
+					'persistent' => false,
617
+				],
618
+				'metaboxes'     => $this->_default_espresso_metaboxes,
619
+				'labels'        => [
620
+					'publishbox' => esc_html__('Save Registration', 'event_espresso'),
621
+				],
622
+				'require_nonce' => false,
623
+			],
624
+			'add_new_attendee'  => [
625
+				'nav'           => [
626
+					'label'      => esc_html__('Add Contact', 'event_espresso'),
627
+					'icon'       => 'dashicons-plus-alt',
628
+					'order'      => 15,
629
+					'persistent' => false,
630
+				],
631
+				'metaboxes'     => array_merge(
632
+					$this->_default_espresso_metaboxes,
633
+					['_publish_post_box', 'attendee_editor_metaboxes']
634
+				),
635
+				'require_nonce' => false,
636
+			],
637
+			'edit_attendee'     => [
638
+				'nav'           => [
639
+					'label'      => esc_html__('Edit Contact', 'event_espresso'),
640
+					'icon'       => 'dashicons-edit-large',
641
+					'order'      => 15,
642
+					'persistent' => false,
643
+					'url'        => $ATT_ID
644
+						? add_query_arg(['ATT_ID' => $ATT_ID], $this->_current_page_view_url)
645
+						: $this->_admin_base_url,
646
+				],
647
+				'metaboxes'     => array_merge(
648
+					$this->_default_espresso_metaboxes,
649
+					['attendee_editor_metaboxes']
650
+				),
651
+				'require_nonce' => false,
652
+			],
653
+			'contact_list'      => [
654
+				'nav'           => [
655
+					'label' => esc_html__('Contact List', 'event_espresso'),
656
+					'icon'  => 'dashicons-id-alt',
657
+					'order' => 20,
658
+				],
659
+				'list_table'    => 'EE_Attendee_Contact_List_Table',
660
+				'help_tabs'     => [
661
+					'registrations_contact_list_help_tab'                       => [
662
+						'title'    => esc_html__('Registrations Contact List', 'event_espresso'),
663
+						'filename' => 'registrations_contact_list',
664
+					],
665
+					'registrations_contact-list_table_column_headings_help_tab' => [
666
+						'title'    => esc_html__('Contact List Table Column Headings', 'event_espresso'),
667
+						'filename' => 'registrations_contact_list_table_column_headings',
668
+					],
669
+					'registrations_contact_list_views_help_tab'                 => [
670
+						'title'    => esc_html__('Contact List Views', 'event_espresso'),
671
+						'filename' => 'registrations_contact_list_views',
672
+					],
673
+					'registrations_contact_list_other_help_tab'                 => [
674
+						'title'    => esc_html__('Contact List Other', 'event_espresso'),
675
+						'filename' => 'registrations_contact_list_other',
676
+					],
677
+				],
678
+				'metaboxes'     => [],
679
+				'require_nonce' => false,
680
+			],
681
+			// override default cpt routes
682
+			'create_new'        => '',
683
+			'edit'              => '',
684
+		];
685
+	}
686
+
687
+
688
+	/**
689
+	 * The below methods aren't used by this class currently
690
+	 */
691
+	protected function _add_screen_options()
692
+	{
693
+	}
694
+
695
+
696
+	protected function _add_feature_pointers()
697
+	{
698
+	}
699
+
700
+
701
+	public function admin_init()
702
+	{
703
+		EE_Registry::$i18n_js_strings['update_att_qstns'] = esc_html__(
704
+			'click "Update Registration Questions" to save your changes',
705
+			'event_espresso'
706
+		);
707
+	}
708
+
709
+
710
+	public function admin_notices()
711
+	{
712
+	}
713
+
714
+
715
+	public function admin_footer_scripts()
716
+	{
717
+	}
718
+
719
+
720
+	/**
721
+	 * get list of registration statuses
722
+	 *
723
+	 * @return void
724
+	 * @throws EE_Error
725
+	 */
726
+	private function _get_registration_status_array()
727
+	{
728
+		self::$_reg_status = EEM_Registration::reg_status_array([], true);
729
+	}
730
+
731
+
732
+	/**
733
+	 * @throws InvalidArgumentException
734
+	 * @throws InvalidDataTypeException
735
+	 * @throws InvalidInterfaceException
736
+	 * @since 4.10.2.p
737
+	 */
738
+	protected function _add_screen_options_default()
739
+	{
740
+		$this->_per_page_screen_option();
741
+	}
742
+
743
+
744
+	/**
745
+	 * @throws InvalidArgumentException
746
+	 * @throws InvalidDataTypeException
747
+	 * @throws InvalidInterfaceException
748
+	 * @since 4.10.2.p
749
+	 */
750
+	protected function _add_screen_options_contact_list()
751
+	{
752
+		$page_title              = $this->_admin_page_title;
753
+		$this->_admin_page_title = esc_html__('Contacts', 'event_espresso');
754
+		$this->_per_page_screen_option();
755
+		$this->_admin_page_title = $page_title;
756
+	}
757
+
758
+
759
+	public function load_scripts_styles()
760
+	{
761
+		// style
762
+		wp_register_style(
763
+			'espresso_reg',
764
+			REG_ASSETS_URL . 'espresso_registrations_admin.css',
765
+			['ee-admin-css'],
766
+			EVENT_ESPRESSO_VERSION
767
+		);
768
+		wp_enqueue_style('espresso_reg');
769
+		// script
770
+		wp_register_script(
771
+			'espresso_reg',
772
+			REG_ASSETS_URL . 'espresso_registrations_admin.js',
773
+			['jquery-ui-datepicker', 'jquery-ui-draggable', 'ee_admin_js'],
774
+			EVENT_ESPRESSO_VERSION,
775
+			true
776
+		);
777
+		wp_enqueue_script('espresso_reg');
778
+	}
779
+
780
+
781
+	/**
782
+	 * @throws EE_Error
783
+	 * @throws InvalidArgumentException
784
+	 * @throws InvalidDataTypeException
785
+	 * @throws InvalidInterfaceException
786
+	 * @throws ReflectionException
787
+	 * @since 4.10.2.p
788
+	 */
789
+	public function load_scripts_styles_edit_attendee()
790
+	{
791
+		// stuff to only show up on our attendee edit details page.
792
+		$attendee_details_translations = [
793
+			'att_publish_text' => sprintf(
794
+			/* translators: The date and time */
795
+				wp_strip_all_tags(__('Created on: %s', 'event_espresso')),
796
+				'<b>' . $this->_cpt_model_obj->get_datetime('ATT_created') . '</b>'
797
+			),
798
+		];
799
+		wp_localize_script('espresso_reg', 'ATTENDEE_DETAILS', $attendee_details_translations);
800
+		wp_enqueue_script('jquery-validate');
801
+	}
802
+
803
+
804
+	/**
805
+	 * @throws EE_Error
806
+	 * @throws InvalidArgumentException
807
+	 * @throws InvalidDataTypeException
808
+	 * @throws InvalidInterfaceException
809
+	 * @throws ReflectionException
810
+	 * @since 4.10.2.p
811
+	 */
812
+	public function load_scripts_styles_view_registration()
813
+	{
814
+		$this->_set_registration_object();
815
+		// styles
816
+		wp_enqueue_style('espresso-ui-theme');
817
+		// scripts
818
+		$this->_get_reg_custom_questions_form($this->_registration->ID());
819
+		$this->_reg_custom_questions_form->wp_enqueue_scripts();
820
+	}
821
+
822
+
823
+	public function load_scripts_styles_contact_list()
824
+	{
825
+		wp_dequeue_style('espresso_reg');
826
+		wp_register_style(
827
+			'espresso_att',
828
+			REG_ASSETS_URL . 'espresso_attendees_admin.css',
829
+			['ee-admin-css'],
830
+			EVENT_ESPRESSO_VERSION
831
+		);
832
+		wp_enqueue_style('espresso_att');
833
+	}
834
+
835
+
836
+	public function load_scripts_styles_new_registration()
837
+	{
838
+		wp_register_script(
839
+			'ee-spco-for-admin',
840
+			REG_ASSETS_URL . 'spco_for_admin.js',
841
+			['underscore', 'jquery'],
842
+			EVENT_ESPRESSO_VERSION,
843
+			true
844
+		);
845
+		wp_enqueue_script('ee-spco-for-admin');
846
+		add_filter('FHEE__EED_Ticket_Selector__load_tckt_slctr_assets', '__return_true');
847
+		EE_Form_Section_Proper::wp_enqueue_scripts();
848
+		EED_Ticket_Selector::load_tckt_slctr_assets();
849
+		EE_Datepicker_Input::enqueue_styles_and_scripts();
850
+	}
851
+
852
+
853
+	public function AHEE__EE_Admin_Page__route_admin_request_resend_registration()
854
+	{
855
+		add_filter('FHEE_load_EE_messages', '__return_true');
856
+	}
857
+
858
+
859
+	public function AHEE__EE_Admin_Page__route_admin_request_approve_registration()
860
+	{
861
+		add_filter('FHEE_load_EE_messages', '__return_true');
862
+	}
863
+
864
+
865
+	/**
866
+	 * @throws EE_Error
867
+	 * @throws InvalidArgumentException
868
+	 * @throws InvalidDataTypeException
869
+	 * @throws InvalidInterfaceException
870
+	 * @throws ReflectionException
871
+	 * @since 4.10.2.p
872
+	 */
873
+	protected function _set_list_table_views_default()
874
+	{
875
+		// for notification related bulk actions we need to make sure only active messengers have an option.
876
+		EED_Messages::set_autoloaders();
877
+		/** @type EE_Message_Resource_Manager $message_resource_manager */
878
+		$message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
879
+		$active_mts               = $message_resource_manager->list_of_active_message_types();
880
+		// key= bulk_action_slug, value= message type.
881
+		$match_array = [
882
+			'approve_registrations'    => 'registration',
883
+			'decline_registrations'    => 'declined_registration',
884
+			'pending_registrations'    => 'pending_approval',
885
+			'no_approve_registrations' => 'not_approved_registration',
886
+			'cancel_registrations'     => 'cancelled_registration',
887
+		];
888
+		$can_send    = $this->capabilities->current_user_can(
889
+			'ee_send_message',
890
+			'batch_send_messages'
891
+		);
892
+		/** setup reg status bulk actions **/
893
+		$def_reg_status_actions['approve_registrations'] = esc_html__('Approve Registrations', 'event_espresso');
894
+		if ($can_send && in_array($match_array['approve_registrations'], $active_mts, true)) {
895
+			$def_reg_status_actions['approve_and_notify_registrations'] = esc_html__(
896
+				'Approve and Notify Registrations',
897
+				'event_espresso'
898
+			);
899
+		}
900
+		$def_reg_status_actions['decline_registrations'] = esc_html__('Decline Registrations', 'event_espresso');
901
+		if ($can_send && in_array($match_array['decline_registrations'], $active_mts, true)) {
902
+			$def_reg_status_actions['decline_and_notify_registrations'] = esc_html__(
903
+				'Decline and Notify Registrations',
904
+				'event_espresso'
905
+			);
906
+		}
907
+		$def_reg_status_actions['pending_registrations'] = esc_html__(
908
+			'Set Registrations to Pending Payment',
909
+			'event_espresso'
910
+		);
911
+		if ($can_send && in_array($match_array['pending_registrations'], $active_mts, true)) {
912
+			$def_reg_status_actions['pending_and_notify_registrations'] = esc_html__(
913
+				'Set Registrations to Pending Payment and Notify',
914
+				'event_espresso'
915
+			);
916
+		}
917
+		$def_reg_status_actions['no_approve_registrations'] = esc_html__(
918
+			'Set Registrations to Not Approved',
919
+			'event_espresso'
920
+		);
921
+		if ($can_send && in_array($match_array['no_approve_registrations'], $active_mts, true)) {
922
+			$def_reg_status_actions['no_approve_and_notify_registrations'] = esc_html__(
923
+				'Set Registrations to Not Approved and Notify',
924
+				'event_espresso'
925
+			);
926
+		}
927
+		$def_reg_status_actions['cancel_registrations'] = esc_html__('Cancel Registrations', 'event_espresso');
928
+		if ($can_send && in_array($match_array['cancel_registrations'], $active_mts, true)) {
929
+			$def_reg_status_actions['cancel_and_notify_registrations'] = esc_html__(
930
+				'Cancel Registrations and Notify',
931
+				'event_espresso'
932
+			);
933
+		}
934
+		$def_reg_status_actions = apply_filters(
935
+			'FHEE__Registrations_Admin_Page___set_list_table_views_default__def_reg_status_actions_array',
936
+			$def_reg_status_actions,
937
+			$active_mts,
938
+			$can_send
939
+		);
940
+
941
+		$this->_views = [
942
+			'all'   => [
943
+				'slug'        => 'all',
944
+				'label'       => esc_html__('View All Registrations', 'event_espresso'),
945
+				'count'       => 0,
946
+				'bulk_action' => array_merge(
947
+					$def_reg_status_actions,
948
+					[
949
+						'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
950
+					]
951
+				),
952
+			],
953
+			'month' => [
954
+				'slug'        => 'month',
955
+				'label'       => esc_html__('This Month', 'event_espresso'),
956
+				'count'       => 0,
957
+				'bulk_action' => array_merge(
958
+					$def_reg_status_actions,
959
+					[
960
+						'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
961
+					]
962
+				),
963
+			],
964
+			'today' => [
965
+				'slug'        => 'today',
966
+				'label'       => sprintf(
967
+					esc_html__('Today - %s', 'event_espresso'),
968
+					date('M d, Y', current_time('timestamp'))
969
+				),
970
+				'count'       => 0,
971
+				'bulk_action' => array_merge(
972
+					$def_reg_status_actions,
973
+					[
974
+						'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
975
+					]
976
+				),
977
+			],
978
+		];
979
+		if (
980
+			$this->capabilities->current_user_can(
981
+				'ee_delete_registrations',
982
+				'espresso_registrations_delete_registration'
983
+			)
984
+		) {
985
+			$this->_views['incomplete'] = [
986
+				'slug'        => 'incomplete',
987
+				'label'       => esc_html__('Incomplete', 'event_espresso'),
988
+				'count'       => 0,
989
+				'bulk_action' => [
990
+					'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
991
+				],
992
+			];
993
+			$this->_views['trash']      = [
994
+				'slug'        => 'trash',
995
+				'label'       => esc_html__('Trash', 'event_espresso'),
996
+				'count'       => 0,
997
+				'bulk_action' => [
998
+					'restore_registrations' => esc_html__('Restore Registrations', 'event_espresso'),
999
+					'delete_registrations'  => esc_html__('Delete Registrations Permanently', 'event_espresso'),
1000
+				],
1001
+			];
1002
+		}
1003
+	}
1004
+
1005
+
1006
+	protected function _set_list_table_views_contact_list()
1007
+	{
1008
+		$this->_views = [
1009
+			'in_use' => [
1010
+				'slug'        => 'in_use',
1011
+				'label'       => esc_html__('In Use', 'event_espresso'),
1012
+				'count'       => 0,
1013
+				'bulk_action' => [
1014
+					'trash_attendees' => esc_html__('Move to Trash', 'event_espresso'),
1015
+				],
1016
+			],
1017
+		];
1018
+		if (
1019
+			$this->capabilities->current_user_can(
1020
+				'ee_delete_contacts',
1021
+				'espresso_registrations_trash_attendees'
1022
+			)
1023
+		) {
1024
+			$this->_views['trash'] = [
1025
+				'slug'        => 'trash',
1026
+				'label'       => esc_html__('Trash', 'event_espresso'),
1027
+				'count'       => 0,
1028
+				'bulk_action' => [
1029
+					'restore_attendees' => esc_html__('Restore from Trash', 'event_espresso'),
1030
+				],
1031
+			];
1032
+		}
1033
+	}
1034
+
1035
+
1036
+	/**
1037
+	 * @return array
1038
+	 * @throws EE_Error
1039
+	 */
1040
+	protected function _registration_legend_items()
1041
+	{
1042
+		$fc_items = [
1043
+			'star-icon'        => [
1044
+				'class' => 'dashicons dashicons-star-filled gold-icon',
1045
+				'desc'  => esc_html__('This is the Primary Registrant', 'event_espresso'),
1046
+			],
1047
+			'view_details'     => [
1048
+				'class' => 'dashicons dashicons-clipboard',
1049
+				'desc'  => esc_html__('View Registration Details', 'event_espresso'),
1050
+			],
1051
+			'edit_attendee'    => [
1052
+				'class' => 'dashicons dashicons-admin-users',
1053
+				'desc'  => esc_html__('Edit Contact Details', 'event_espresso'),
1054
+			],
1055
+			'view_transaction' => [
1056
+				'class' => 'dashicons dashicons-cart',
1057
+				'desc'  => esc_html__('View Transaction Details', 'event_espresso'),
1058
+			],
1059
+			'view_invoice'     => [
1060
+				'class' => 'dashicons dashicons-media-spreadsheet',
1061
+				'desc'  => esc_html__('View Transaction Invoice', 'event_espresso'),
1062
+			],
1063
+		];
1064
+		if (
1065
+			$this->capabilities->current_user_can(
1066
+				'ee_send_message',
1067
+				'espresso_registrations_resend_registration'
1068
+			)
1069
+		) {
1070
+			$fc_items['resend_registration'] = [
1071
+				'class' => 'dashicons dashicons-email-alt',
1072
+				'desc'  => esc_html__('Resend Registration Details', 'event_espresso'),
1073
+			];
1074
+		} else {
1075
+			$fc_items['blank'] = ['class' => 'blank', 'desc' => ''];
1076
+		}
1077
+		if (
1078
+			$this->capabilities->current_user_can(
1079
+				'ee_read_global_messages',
1080
+				'view_filtered_messages'
1081
+			)
1082
+		) {
1083
+			$related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
1084
+			if (is_array($related_for_icon) && isset($related_for_icon['css_class'], $related_for_icon['label'])) {
1085
+				$fc_items['view_related_messages'] = [
1086
+					'class' => $related_for_icon['css_class'],
1087
+					'desc'  => $related_for_icon['label'],
1088
+				];
1089
+			}
1090
+		}
1091
+		$sc_items = [
1092
+			'approved_status'   => [
1093
+				'class' => 'ee-status-legend ee-status-bg--' . EEM_Registration::status_id_approved,
1094
+				'desc'  => EEH_Template::pretty_status(
1095
+					EEM_Registration::status_id_approved,
1096
+					false,
1097
+					'sentence'
1098
+				),
1099
+			],
1100
+			'pending_status'    => [
1101
+				'class' => 'ee-status-legend ee-status-bg--' . EEM_Registration::status_id_pending_payment,
1102
+				'desc'  => EEH_Template::pretty_status(
1103
+					EEM_Registration::status_id_pending_payment,
1104
+					false,
1105
+					'sentence'
1106
+				),
1107
+			],
1108
+			'wait_list'         => [
1109
+				'class' => 'ee-status-legend ee-status-bg--' . EEM_Registration::status_id_wait_list,
1110
+				'desc'  => EEH_Template::pretty_status(
1111
+					EEM_Registration::status_id_wait_list,
1112
+					false,
1113
+					'sentence'
1114
+				),
1115
+			],
1116
+			'incomplete_status' => [
1117
+				'class' => 'ee-status-legend ee-status-bg--' . EEM_Registration::status_id_incomplete,
1118
+				'desc'  => EEH_Template::pretty_status(
1119
+					EEM_Registration::status_id_incomplete,
1120
+					false,
1121
+					'sentence'
1122
+				),
1123
+			],
1124
+			'not_approved'      => [
1125
+				'class' => 'ee-status-legend ee-status-bg--' . EEM_Registration::status_id_not_approved,
1126
+				'desc'  => EEH_Template::pretty_status(
1127
+					EEM_Registration::status_id_not_approved,
1128
+					false,
1129
+					'sentence'
1130
+				),
1131
+			],
1132
+			'declined_status'   => [
1133
+				'class' => 'ee-status-legend ee-status-bg--' . EEM_Registration::status_id_declined,
1134
+				'desc'  => EEH_Template::pretty_status(
1135
+					EEM_Registration::status_id_declined,
1136
+					false,
1137
+					'sentence'
1138
+				),
1139
+			],
1140
+			'cancelled_status'  => [
1141
+				'class' => 'ee-status-legend ee-status-bg--' . EEM_Registration::status_id_cancelled,
1142
+				'desc'  => EEH_Template::pretty_status(
1143
+					EEM_Registration::status_id_cancelled,
1144
+					false,
1145
+					'sentence'
1146
+				),
1147
+			],
1148
+		];
1149
+		return array_merge($fc_items, $sc_items);
1150
+	}
1151
+
1152
+
1153
+
1154
+	/***************************************        REGISTRATION OVERVIEW        **************************************/
1155
+
1156
+
1157
+	/**
1158
+	 * @throws DomainException
1159
+	 * @throws EE_Error
1160
+	 * @throws InvalidArgumentException
1161
+	 * @throws InvalidDataTypeException
1162
+	 * @throws InvalidInterfaceException
1163
+	 */
1164
+	protected function _registrations_overview_list_table()
1165
+	{
1166
+		$this->appendAddNewRegistrationButtonToPageTitle();
1167
+		$header_text                  = '';
1168
+		$admin_page_header_decorators = [
1169
+			'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\AttendeeFilterHeader',
1170
+			'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\EventFilterHeader',
1171
+			'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\DateFilterHeader',
1172
+			'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\TicketFilterHeader',
1173
+		];
1174
+		foreach ($admin_page_header_decorators as $admin_page_header_decorator) {
1175
+			$filter_header_decorator = $this->loader->getNew($admin_page_header_decorator);
1176
+			$header_text             = $filter_header_decorator->getHeaderText($header_text);
1177
+		}
1178
+		$this->_template_args['before_list_table'] = $header_text;
1179
+		$this->_template_args['after_list_table']  = $this->_display_legend($this->_registration_legend_items());
1180
+		$this->display_admin_list_table_page_with_no_sidebar();
1181
+	}
1182
+
1183
+
1184
+	/**
1185
+	 * @throws EE_Error
1186
+	 * @throws InvalidArgumentException
1187
+	 * @throws InvalidDataTypeException
1188
+	 * @throws InvalidInterfaceException
1189
+	 */
1190
+	private function appendAddNewRegistrationButtonToPageTitle()
1191
+	{
1192
+		$EVT_ID = $this->request->getRequestParam('event_id', 0, 'int');
1193
+		if (
1194
+			$EVT_ID
1195
+			&& $this->capabilities->current_user_can(
1196
+				'ee_edit_registrations',
1197
+				'espresso_registrations_new_registration',
1198
+				$EVT_ID
1199
+			)
1200
+		) {
1201
+			$this->_admin_page_title .= ' ' . $this->get_action_link_or_button(
1202
+					'new_registration',
1203
+					'add-registrant',
1204
+					['event_id' => $EVT_ID],
1205
+					'add-new-h2'
1206
+				);
1207
+		}
1208
+	}
1209
+
1210
+
1211
+	/**
1212
+	 * This sets the _registration property for the registration details screen
1213
+	 *
1214
+	 * @return void
1215
+	 * @throws EE_Error
1216
+	 * @throws InvalidArgumentException
1217
+	 * @throws InvalidDataTypeException
1218
+	 * @throws InvalidInterfaceException
1219
+	 */
1220
+	private function _set_registration_object()
1221
+	{
1222
+		// get out if we've already set the object
1223
+		if ($this->_registration instanceof EE_Registration) {
1224
+			return;
1225
+		}
1226
+		$REG_ID = $this->request->getRequestParam('_REG_ID', 0, 'int');
1227
+		if ($this->_registration = $this->getRegistrationModel()->get_one_by_ID($REG_ID)) {
1228
+			return;
1229
+		}
1230
+		$error_msg = sprintf(
1231
+			esc_html__(
1232
+				'An error occurred and the details for Registration ID #%s could not be retrieved.',
1233
+				'event_espresso'
1234
+			),
1235
+			$REG_ID
1236
+		);
1237
+		EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
1238
+		$this->_registration = null;
1239
+	}
1240
+
1241
+
1242
+	/**
1243
+	 * Used to retrieve registrations for the list table.
1244
+	 *
1245
+	 * @param int  $per_page
1246
+	 * @param bool $count
1247
+	 * @param bool $this_month
1248
+	 * @param bool $today
1249
+	 * @return EE_Registration[]|int
1250
+	 * @throws EE_Error
1251
+	 * @throws InvalidArgumentException
1252
+	 * @throws InvalidDataTypeException
1253
+	 * @throws InvalidInterfaceException
1254
+	 */
1255
+	public function get_registrations(
1256
+		$per_page = 10,
1257
+		$count = false,
1258
+		$this_month = false,
1259
+		$today = false
1260
+	) {
1261
+		if ($this_month) {
1262
+			$this->request->setRequestParam('status', 'month');
1263
+		}
1264
+		if ($today) {
1265
+			$this->request->setRequestParam('status', 'today');
1266
+		}
1267
+		$query_params = $this->_get_registration_query_parameters([], $per_page, $count);
1268
+		/**
1269
+		 * Override the default groupby added by EEM_Base so that sorts with multiple order bys work as expected
1270
+		 *
1271
+		 * @link https://events.codebasehq.com/projects/event-espresso/tickets/10093
1272
+		 * @see  https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1273
+		 *                      or if you have the development copy of EE you can view this at the path:
1274
+		 *                      /docs/G--Model-System/model-query-params.md
1275
+		 */
1276
+		$query_params['group_by'] = '';
1277
+
1278
+		return $count
1279
+			? $this->getRegistrationModel()->count($query_params)
1280
+			/** @type EE_Registration[] */
1281
+			: $this->getRegistrationModel()->get_all($query_params);
1282
+	}
1283
+
1284
+
1285
+	/**
1286
+	 * Retrieves the query parameters to be used by the Registration model for getting registrations.
1287
+	 * Note: this listens to values on the request for some query parameters.
1288
+	 *
1289
+	 * @param array $request
1290
+	 * @param int   $per_page
1291
+	 * @param bool  $count
1292
+	 * @return array
1293
+	 * @throws EE_Error
1294
+	 * @throws InvalidArgumentException
1295
+	 * @throws InvalidDataTypeException
1296
+	 * @throws InvalidInterfaceException
1297
+	 */
1298
+	protected function _get_registration_query_parameters(
1299
+		array $request = [],
1300
+		int $per_page = 10,
1301
+		bool $count = false
1302
+	): array {
1303
+		/** @var EventEspresso\core\domain\services\admin\registrations\list_table\QueryBuilder $list_table_query_builder */
1304
+		$list_table_query_builder = $this->loader->getNew(
1305
+			'EventEspresso\core\domain\services\admin\registrations\list_table\QueryBuilder',
1306
+			[null, null, $request]
1307
+		);
1308
+		return $list_table_query_builder->getQueryParams($per_page, $count);
1309
+	}
1310
+
1311
+
1312
+	public function get_registration_status_array(): array
1313
+	{
1314
+		return self::$_reg_status;
1315
+	}
1316
+
1317
+
1318
+
1319
+
1320
+	/***************************************        REGISTRATION DETAILS        ***************************************/
1321
+	/**
1322
+	 * generates HTML for the View Registration Details Admin page
1323
+	 *
1324
+	 * @return void
1325
+	 * @throws DomainException
1326
+	 * @throws EE_Error
1327
+	 * @throws InvalidArgumentException
1328
+	 * @throws InvalidDataTypeException
1329
+	 * @throws InvalidInterfaceException
1330
+	 * @throws EntityNotFoundException
1331
+	 * @throws ReflectionException
1332
+	 */
1333
+	protected function _registration_details()
1334
+	{
1335
+		$this->_template_args = [];
1336
+		$this->_set_registration_object();
1337
+		if (is_object($this->_registration)) {
1338
+			$transaction                                   = $this->_registration->transaction()
1339
+				? $this->_registration->transaction()
1340
+				: EE_Transaction::new_instance();
1341
+			$this->_session                                = $transaction->session_data();
1342
+			$event_id                                      = $this->_registration->event_ID();
1343
+			$this->_template_args['reg_nmbr']['value']     = $this->_registration->ID();
1344
+			$this->_template_args['reg_nmbr']['label']     = esc_html__('Registration Number', 'event_espresso');
1345
+			$this->_template_args['reg_datetime']['value'] = $this->_registration->get_i18n_datetime('REG_date');
1346
+			$this->_template_args['reg_datetime']['label'] = esc_html__('Date', 'event_espresso');
1347
+			$this->_template_args['grand_total']           = $transaction->total();
1348
+			$this->_template_args['currency_sign']         = EE_Registry::instance()->CFG->currency->sign;
1349
+			// link back to overview
1350
+			$this->_template_args['reg_overview_url']            = REG_ADMIN_URL;
1351
+			$this->_template_args['registration']                = $this->_registration;
1352
+			$this->_template_args['filtered_registrations_link'] = EE_Admin_Page::add_query_args_and_nonce(
1353
+				[
1354
+					'action'   => 'default',
1355
+					'event_id' => $event_id,
1356
+				],
1357
+				REG_ADMIN_URL
1358
+			);
1359
+			$this->_template_args['filtered_transactions_link']  = EE_Admin_Page::add_query_args_and_nonce(
1360
+				[
1361
+					'action' => 'default',
1362
+					'EVT_ID' => $event_id,
1363
+					'page'   => 'espresso_transactions',
1364
+				],
1365
+				admin_url('admin.php')
1366
+			);
1367
+			$this->_template_args['event_link']                  = EE_Admin_Page::add_query_args_and_nonce(
1368
+				[
1369
+					'page'   => 'espresso_events',
1370
+					'action' => 'edit',
1371
+					'post'   => $event_id,
1372
+				],
1373
+				admin_url('admin.php')
1374
+			);
1375
+			// next and previous links
1376
+			$next_reg                                      = $this->_registration->next(
1377
+				null,
1378
+				[],
1379
+				'REG_ID'
1380
+			);
1381
+			$this->_template_args['next_registration']     = $next_reg
1382
+				? $this->_next_link(
1383
+					EE_Admin_Page::add_query_args_and_nonce(
1384
+						[
1385
+							'action'  => 'view_registration',
1386
+							'_REG_ID' => $next_reg['REG_ID'],
1387
+						],
1388
+						REG_ADMIN_URL
1389
+					),
1390
+					'dashicons dashicons-arrow-right ee-icon-size-22'
1391
+				)
1392
+				: '';
1393
+			$previous_reg                                  = $this->_registration->previous(
1394
+				null,
1395
+				[],
1396
+				'REG_ID'
1397
+			);
1398
+			$this->_template_args['previous_registration'] = $previous_reg
1399
+				? $this->_previous_link(
1400
+					EE_Admin_Page::add_query_args_and_nonce(
1401
+						[
1402
+							'action'  => 'view_registration',
1403
+							'_REG_ID' => $previous_reg['REG_ID'],
1404
+						],
1405
+						REG_ADMIN_URL
1406
+					),
1407
+					'dashicons dashicons-arrow-left ee-icon-size-22'
1408
+				)
1409
+				: '';
1410
+			// grab header
1411
+			$template_path                             = REG_TEMPLATE_PATH . 'reg_admin_details_header.template.php';
1412
+			$this->_template_args['REG_ID']            = $this->_registration->ID();
1413
+			$this->_template_args['admin_page_header'] = EEH_Template::display_template(
1414
+				$template_path,
1415
+				$this->_template_args,
1416
+				true
1417
+			);
1418
+		} else {
1419
+			$this->_template_args['admin_page_header'] = '';
1420
+			$this->_display_espresso_notices();
1421
+		}
1422
+		// the details template wrapper
1423
+		$this->display_admin_page_with_sidebar();
1424
+	}
1425
+
1426
+
1427
+	/**
1428
+	 * @throws EE_Error
1429
+	 * @throws InvalidArgumentException
1430
+	 * @throws InvalidDataTypeException
1431
+	 * @throws InvalidInterfaceException
1432
+	 * @throws ReflectionException
1433
+	 * @since 4.10.2.p
1434
+	 */
1435
+	protected function _registration_details_metaboxes()
1436
+	{
1437
+		do_action('AHEE__Registrations_Admin_Page___registration_details_metabox__start', $this);
1438
+		$this->_set_registration_object();
1439
+		$attendee = $this->_registration instanceof EE_Registration ? $this->_registration->attendee() : null;
1440
+		$this->addMetaBox(
1441
+			'edit-reg-status-mbox',
1442
+			esc_html__('Registration Status', 'event_espresso'),
1443
+			[$this, 'set_reg_status_buttons_metabox'],
1444
+			$this->_wp_page_slug
1445
+		);
1446
+		$this->addMetaBox(
1447
+			'edit-reg-details-mbox',
1448
+			'<span>' . esc_html__('Registration Details', 'event_espresso')
1449
+			. '&nbsp;<span class="dashicons dashicons-clipboard"></span></span>',
1450
+			[$this, '_reg_details_meta_box'],
1451
+			$this->_wp_page_slug
1452
+		);
1453
+		if (
1454
+			$attendee instanceof EE_Attendee
1455
+			&& $this->capabilities->current_user_can(
1456
+				'ee_read_registration',
1457
+				'edit-reg-questions-mbox',
1458
+				$this->_registration->ID()
1459
+			)
1460
+		) {
1461
+			$this->addMetaBox(
1462
+				'edit-reg-questions-mbox',
1463
+				esc_html__('Registration Form Answers', 'event_espresso'),
1464
+				[$this, '_reg_questions_meta_box'],
1465
+				$this->_wp_page_slug
1466
+			);
1467
+		}
1468
+		$this->addMetaBox(
1469
+			'edit-reg-registrant-mbox',
1470
+			esc_html__('Contact Details', 'event_espresso'),
1471
+			[$this, '_reg_registrant_side_meta_box'],
1472
+			$this->_wp_page_slug,
1473
+			'side'
1474
+		);
1475
+		if ($this->_registration->group_size() > 1) {
1476
+			$this->addMetaBox(
1477
+				'edit-reg-attendees-mbox',
1478
+				esc_html__('Other Registrations in this Transaction', 'event_espresso'),
1479
+				[$this, '_reg_attendees_meta_box'],
1480
+				$this->_wp_page_slug
1481
+			);
1482
+		}
1483
+	}
1484
+
1485
+
1486
+	/**
1487
+	 * set_reg_status_buttons_metabox
1488
+	 *
1489
+	 * @return void
1490
+	 * @throws EE_Error
1491
+	 * @throws EntityNotFoundException
1492
+	 * @throws InvalidArgumentException
1493
+	 * @throws InvalidDataTypeException
1494
+	 * @throws InvalidInterfaceException
1495
+	 * @throws ReflectionException
1496
+	 */
1497
+	public function set_reg_status_buttons_metabox()
1498
+	{
1499
+		$this->_set_registration_object();
1500
+		$change_reg_status_form = $this->_generate_reg_status_change_form();
1501
+		$output                 = $change_reg_status_form->form_open(
1502
+			self::add_query_args_and_nonce(
1503
+				[
1504
+					'action' => 'change_reg_status',
1505
+				],
1506
+				REG_ADMIN_URL
1507
+			)
1508
+		);
1509
+		$output                 .= $change_reg_status_form->get_html();
1510
+		$output                 .= $change_reg_status_form->form_close();
1511
+		echo wp_kses($output, AllowedTags::getWithFormTags());
1512
+	}
1513
+
1514
+
1515
+	/**
1516
+	 * @return EE_Form_Section_Proper
1517
+	 * @throws EE_Error
1518
+	 * @throws InvalidArgumentException
1519
+	 * @throws InvalidDataTypeException
1520
+	 * @throws InvalidInterfaceException
1521
+	 * @throws EntityNotFoundException
1522
+	 * @throws ReflectionException
1523
+	 */
1524
+	protected function _generate_reg_status_change_form()
1525
+	{
1526
+		$reg_status_change_form_array = [
1527
+			'name'            => 'reg_status_change_form',
1528
+			'html_id'         => 'reg-status-change-form',
1529
+			'layout_strategy' => new EE_Admin_Two_Column_Layout(),
1530
+			'subsections'     => [
1531
+				'return' => new EE_Hidden_Input(
1532
+					[
1533
+						'name'    => 'return',
1534
+						'default' => 'view_registration',
1535
+					]
1536
+				),
1537
+				'REG_ID' => new EE_Hidden_Input(
1538
+					[
1539
+						'name'    => 'REG_ID',
1540
+						'default' => $this->_registration->ID(),
1541
+					]
1542
+				),
1543
+			],
1544
+		];
1545
+		if (
1546
+			$this->capabilities->current_user_can(
1547
+				'ee_edit_registration',
1548
+				'toggle_registration_status',
1549
+				$this->_registration->ID()
1550
+			)
1551
+		) {
1552
+			$reg_status_change_form_array['subsections']['reg_status']         = new EE_Select_Input(
1553
+				$this->_get_reg_statuses(),
1554
+				[
1555
+					'html_label_text' => esc_html__('Change Registration Status to', 'event_espresso'),
1556
+					'default'         => $this->_registration->status_ID(),
1557
+				]
1558
+			);
1559
+			$reg_status_change_form_array['subsections']['send_notifications'] = new EE_Yes_No_Input(
1560
+				[
1561
+					'html_label_text' => esc_html__('Send Related Messages', 'event_espresso'),
1562
+					'default'         => false,
1563
+					'html_help_text'  => esc_html__(
1564
+						'If set to "Yes", then the related messages will be sent to the registrant.',
1565
+						'event_espresso'
1566
+					),
1567
+				]
1568
+			);
1569
+			$reg_status_change_form_array['subsections']['submit']             = new EE_Submit_Input(
1570
+				[
1571
+					'html_class'      => 'button--primary',
1572
+					'html_label_text' => '&nbsp;',
1573
+					'default'         => esc_html__('Update Registration Status', 'event_espresso'),
1574
+				]
1575
+			);
1576
+		}
1577
+		return new EE_Form_Section_Proper($reg_status_change_form_array);
1578
+	}
1579
+
1580
+
1581
+	/**
1582
+	 * Returns an array of all the buttons for the various statuses and switch status actions
1583
+	 *
1584
+	 * @return array
1585
+	 * @throws EE_Error
1586
+	 * @throws InvalidArgumentException
1587
+	 * @throws InvalidDataTypeException
1588
+	 * @throws InvalidInterfaceException
1589
+	 * @throws EntityNotFoundException
1590
+	 */
1591
+	protected function _get_reg_statuses()
1592
+	{
1593
+		$reg_status_array = $this->getRegistrationModel()->reg_status_array();
1594
+		unset($reg_status_array[ EEM_Registration::status_id_incomplete ]);
1595
+		// get current reg status
1596
+		$current_status = $this->_registration->status_ID();
1597
+		// is registration for free event? This will determine whether to display the pending payment option
1598
+		if (
1599
+			$current_status !== EEM_Registration::status_id_pending_payment
1600
+			&& EEH_Money::compare_floats($this->_registration->ticket()->price(), 0.00)
1601
+		) {
1602
+			unset($reg_status_array[ EEM_Registration::status_id_pending_payment ]);
1603
+		}
1604
+		return $this->getStatusModel()->localized_status($reg_status_array, false, 'sentence');
1605
+	}
1606
+
1607
+
1608
+	/**
1609
+	 * This method is used when using _REG_ID from request which may or may not be an array of reg_ids.
1610
+	 *
1611
+	 * @param bool $status REG status given for changing registrations to.
1612
+	 * @param bool $notify Whether to send messages notifications or not.
1613
+	 * @return array (array with reg_id(s) updated and whether update was successful.
1614
+	 * @throws DomainException
1615
+	 * @throws EE_Error
1616
+	 * @throws EntityNotFoundException
1617
+	 * @throws InvalidArgumentException
1618
+	 * @throws InvalidDataTypeException
1619
+	 * @throws InvalidInterfaceException
1620
+	 * @throws ReflectionException
1621
+	 * @throws RuntimeException
1622
+	 */
1623
+	protected function _set_registration_status_from_request($status = false, $notify = false)
1624
+	{
1625
+		$REG_IDs = $this->request->requestParamIsSet('reg_status_change_form')
1626
+			? $this->request->getRequestParam('reg_status_change_form[REG_ID]', [], 'int', true)
1627
+			: $this->request->getRequestParam('_REG_ID', [], 'int', true);
1628
+		// sanitize $REG_IDs
1629
+		$REG_IDs = array_map('absint', $REG_IDs);
1630
+		// and remove empty entries
1631
+		$REG_IDs = array_filter($REG_IDs);
1632
+
1633
+		$result = $this->_set_registration_status($REG_IDs, $status, $notify);
1634
+
1635
+		/**
1636
+		 * Set and filter $_req_data['_REG_ID'] for any potential future messages notifications.
1637
+		 * Currently this value is used downstream by the _process_resend_registration method.
1638
+		 *
1639
+		 * @param int|array                $registration_ids The registration ids that have had their status changed successfully.
1640
+		 * @param bool                     $status           The status registrations were changed to.
1641
+		 * @param bool                     $success          If the status was changed successfully for all registrations.
1642
+		 * @param Registrations_Admin_Page $admin_page
1643
+		 */
1644
+		$REG_ID = apply_filters(
1645
+			'FHEE__Registrations_Admin_Page___set_registration_status_from_request__REG_IDs',
1646
+			$result['REG_ID'],
1647
+			$status,
1648
+			$result['success'],
1649
+			$this
1650
+		);
1651
+		$this->request->setRequestParam('_REG_ID', $REG_ID);
1652
+
1653
+		// notify?
1654
+		if (
1655
+			$notify
1656
+			&& $result['success']
1657
+			&& ! empty($REG_ID)
1658
+			&& $this->capabilities->current_user_can(
1659
+				'ee_send_message',
1660
+				'espresso_registrations_resend_registration'
1661
+			)
1662
+		) {
1663
+			$this->_process_resend_registration();
1664
+		}
1665
+		return $result;
1666
+	}
1667
+
1668
+
1669
+	/**
1670
+	 * Set the registration status for the given reg_id (which may or may not be an array, it gets typecast to an
1671
+	 * array). Note, this method does NOT take care of possible notifications.  That is required by calling code.
1672
+	 *
1673
+	 * @param array  $REG_IDs
1674
+	 * @param string $status
1675
+	 * @param bool   $notify Used to indicate whether notification was requested or not.  This determines the context
1676
+	 *                       slug sent with setting the registration status.
1677
+	 * @return array (an array with 'success' key representing whether status change was successful, and 'REG_ID' as
1678
+	 * @throws EE_Error
1679
+	 * @throws InvalidArgumentException
1680
+	 * @throws InvalidDataTypeException
1681
+	 * @throws InvalidInterfaceException
1682
+	 * @throws ReflectionException
1683
+	 * @throws RuntimeException
1684
+	 * @throws EntityNotFoundException
1685
+	 * @throws DomainException
1686
+	 */
1687
+	protected function _set_registration_status($REG_IDs = [], $status = '', $notify = false)
1688
+	{
1689
+		$success = false;
1690
+		// typecast $REG_IDs
1691
+		$REG_IDs = (array) $REG_IDs;
1692
+		if (! empty($REG_IDs)) {
1693
+			$success = true;
1694
+			// set default status if none is passed
1695
+			$status         = $status ?: EEM_Registration::status_id_pending_payment;
1696
+			$status_context = $notify
1697
+				? Domain::CONTEXT_REGISTRATION_STATUS_CHANGE_REGISTRATION_ADMIN_NOTIFY
1698
+				: Domain::CONTEXT_REGISTRATION_STATUS_CHANGE_REGISTRATION_ADMIN;
1699
+			// loop through REG_ID's and change status
1700
+			foreach ($REG_IDs as $REG_ID) {
1701
+				$registration = $this->getRegistrationModel()->get_one_by_ID($REG_ID);
1702
+				if ($registration instanceof EE_Registration) {
1703
+					$registration->set_status(
1704
+						$status,
1705
+						false,
1706
+						new Context(
1707
+							$status_context,
1708
+							esc_html__(
1709
+								'Manually triggered status change on a Registration Admin Page route.',
1710
+								'event_espresso'
1711
+							)
1712
+						)
1713
+					);
1714
+					$result = $registration->save();
1715
+					// verifying explicit fails because update *may* just return 0 for 0 rows affected
1716
+					$success = $result !== false ? $success : false;
1717
+				}
1718
+			}
1719
+		}
1720
+
1721
+		// return $success and processed registrations
1722
+		return ['REG_ID' => $REG_IDs, 'success' => $success];
1723
+	}
1724
+
1725
+
1726
+	/**
1727
+	 * Common logic for setting up success message and redirecting to appropriate route
1728
+	 *
1729
+	 * @param string $STS_ID status id for the registration changed to
1730
+	 * @param bool   $notify indicates whether the _set_registration_status_from_request does notifications or not.
1731
+	 * @return void
1732
+	 * @throws DomainException
1733
+	 * @throws EE_Error
1734
+	 * @throws EntityNotFoundException
1735
+	 * @throws InvalidArgumentException
1736
+	 * @throws InvalidDataTypeException
1737
+	 * @throws InvalidInterfaceException
1738
+	 * @throws ReflectionException
1739
+	 * @throws RuntimeException
1740
+	 */
1741
+	protected function _reg_status_change_return($STS_ID, $notify = false)
1742
+	{
1743
+		$result  = ! empty($STS_ID) ? $this->_set_registration_status_from_request($STS_ID, $notify)
1744
+			: ['success' => false];
1745
+		$success = isset($result['success']) && $result['success'];
1746
+		// setup success message
1747
+		if ($success) {
1748
+			if (is_array($result['REG_ID']) && count($result['REG_ID']) === 1) {
1749
+				$msg = sprintf(
1750
+					esc_html__('Registration status has been set to %s', 'event_espresso'),
1751
+					EEH_Template::pretty_status($STS_ID, false, 'lower')
1752
+				);
1753
+			} else {
1754
+				$msg = sprintf(
1755
+					esc_html__('Registrations have been set to %s.', 'event_espresso'),
1756
+					EEH_Template::pretty_status($STS_ID, false, 'lower')
1757
+				);
1758
+			}
1759
+			EE_Error::add_success($msg);
1760
+		} else {
1761
+			EE_Error::add_error(
1762
+				esc_html__(
1763
+					'Something went wrong, and the status was not changed',
1764
+					'event_espresso'
1765
+				),
1766
+				__FILE__,
1767
+				__LINE__,
1768
+				__FUNCTION__
1769
+			);
1770
+		}
1771
+		$return = $this->request->getRequestParam('return');
1772
+		$route  = $return === 'view_registration'
1773
+			? ['action' => 'view_registration', '_REG_ID' => reset($result['REG_ID'])]
1774
+			: ['action' => 'default'];
1775
+		$route  = $this->mergeExistingRequestParamsWithRedirectArgs($route);
1776
+		$this->_redirect_after_action($success, '', '', $route, true);
1777
+	}
1778
+
1779
+
1780
+	/**
1781
+	 * incoming reg status change from reg details page.
1782
+	 *
1783
+	 * @return void
1784
+	 * @throws EE_Error
1785
+	 * @throws EntityNotFoundException
1786
+	 * @throws InvalidArgumentException
1787
+	 * @throws InvalidDataTypeException
1788
+	 * @throws InvalidInterfaceException
1789
+	 * @throws ReflectionException
1790
+	 * @throws RuntimeException
1791
+	 * @throws DomainException
1792
+	 */
1793
+	protected function _change_reg_status()
1794
+	{
1795
+		$this->request->setRequestParam('return', 'view_registration');
1796
+		// set notify based on whether the send notifications toggle is set or not
1797
+		$notify     = $this->request->getRequestParam('reg_status_change_form[send_notifications]', false, 'bool');
1798
+		$reg_status = $this->request->getRequestParam('reg_status_change_form[reg_status]', '');
1799
+		$this->request->setRequestParam('reg_status_change_form[reg_status]', $reg_status);
1800
+		switch ($reg_status) {
1801
+			case EEM_Registration::status_id_approved:
1802
+			case EEH_Template::pretty_status(EEM_Registration::status_id_approved, false, 'sentence'):
1803
+				$this->approve_registration($notify);
1804
+				break;
1805
+			case EEM_Registration::status_id_pending_payment:
1806
+			case EEH_Template::pretty_status(EEM_Registration::status_id_pending_payment, false, 'sentence'):
1807
+				$this->pending_registration($notify);
1808
+				break;
1809
+			case EEM_Registration::status_id_not_approved:
1810
+			case EEH_Template::pretty_status(EEM_Registration::status_id_not_approved, false, 'sentence'):
1811
+				$this->not_approve_registration($notify);
1812
+				break;
1813
+			case EEM_Registration::status_id_declined:
1814
+			case EEH_Template::pretty_status(EEM_Registration::status_id_declined, false, 'sentence'):
1815
+				$this->decline_registration($notify);
1816
+				break;
1817
+			case EEM_Registration::status_id_cancelled:
1818
+			case EEH_Template::pretty_status(EEM_Registration::status_id_cancelled, false, 'sentence'):
1819
+				$this->cancel_registration($notify);
1820
+				break;
1821
+			case EEM_Registration::status_id_wait_list:
1822
+			case EEH_Template::pretty_status(EEM_Registration::status_id_wait_list, false, 'sentence'):
1823
+				$this->wait_list_registration($notify);
1824
+				break;
1825
+			case EEM_Registration::status_id_incomplete:
1826
+			default:
1827
+				$this->request->unSetRequestParam('return');
1828
+				$this->_reg_status_change_return('');
1829
+				break;
1830
+		}
1831
+	}
1832
+
1833
+
1834
+	/**
1835
+	 * Callback for bulk action routes.
1836
+	 * Note: although we could just register the singular route callbacks for each bulk action route as well, this
1837
+	 * method was chosen so there is one central place all the registration status bulk actions are going through.
1838
+	 * Potentially, this provides an easier place to locate logic that is specific to these bulk actions (as opposed to
1839
+	 * when an action is happening on just a single registration).
1840
+	 *
1841
+	 * @param      $action
1842
+	 * @param bool $notify
1843
+	 */
1844
+	protected function bulk_action_on_registrations($action, $notify = false)
1845
+	{
1846
+		do_action(
1847
+			'AHEE__Registrations_Admin_Page__bulk_action_on_registrations__before_execution',
1848
+			$this,
1849
+			$action,
1850
+			$notify
1851
+		);
1852
+		$method = $action . '_registration';
1853
+		if (method_exists($this, $method)) {
1854
+			$this->$method($notify);
1855
+		}
1856
+	}
1857
+
1858
+
1859
+	/**
1860
+	 * approve_registration
1861
+	 *
1862
+	 * @param bool $notify whether or not to notify the registrant about their approval.
1863
+	 * @return void
1864
+	 * @throws EE_Error
1865
+	 * @throws EntityNotFoundException
1866
+	 * @throws InvalidArgumentException
1867
+	 * @throws InvalidDataTypeException
1868
+	 * @throws InvalidInterfaceException
1869
+	 * @throws ReflectionException
1870
+	 * @throws RuntimeException
1871
+	 * @throws DomainException
1872
+	 */
1873
+	protected function approve_registration($notify = false)
1874
+	{
1875
+		$this->_reg_status_change_return(EEM_Registration::status_id_approved, $notify);
1876
+	}
1877
+
1878
+
1879
+	/**
1880
+	 * decline_registration
1881
+	 *
1882
+	 * @param bool $notify whether or not to notify the registrant about their status change.
1883
+	 * @return void
1884
+	 * @throws EE_Error
1885
+	 * @throws EntityNotFoundException
1886
+	 * @throws InvalidArgumentException
1887
+	 * @throws InvalidDataTypeException
1888
+	 * @throws InvalidInterfaceException
1889
+	 * @throws ReflectionException
1890
+	 * @throws RuntimeException
1891
+	 * @throws DomainException
1892
+	 */
1893
+	protected function decline_registration($notify = false)
1894
+	{
1895
+		$this->_reg_status_change_return(EEM_Registration::status_id_declined, $notify);
1896
+	}
1897
+
1898
+
1899
+	/**
1900
+	 * cancel_registration
1901
+	 *
1902
+	 * @param bool $notify whether or not to notify the registrant about their status change.
1903
+	 * @return void
1904
+	 * @throws EE_Error
1905
+	 * @throws EntityNotFoundException
1906
+	 * @throws InvalidArgumentException
1907
+	 * @throws InvalidDataTypeException
1908
+	 * @throws InvalidInterfaceException
1909
+	 * @throws ReflectionException
1910
+	 * @throws RuntimeException
1911
+	 * @throws DomainException
1912
+	 */
1913
+	protected function cancel_registration($notify = false)
1914
+	{
1915
+		$this->_reg_status_change_return(EEM_Registration::status_id_cancelled, $notify);
1916
+	}
1917
+
1918
+
1919
+	/**
1920
+	 * not_approve_registration
1921
+	 *
1922
+	 * @param bool $notify whether or not to notify the registrant about their status change.
1923
+	 * @return void
1924
+	 * @throws EE_Error
1925
+	 * @throws EntityNotFoundException
1926
+	 * @throws InvalidArgumentException
1927
+	 * @throws InvalidDataTypeException
1928
+	 * @throws InvalidInterfaceException
1929
+	 * @throws ReflectionException
1930
+	 * @throws RuntimeException
1931
+	 * @throws DomainException
1932
+	 */
1933
+	protected function not_approve_registration($notify = false)
1934
+	{
1935
+		$this->_reg_status_change_return(EEM_Registration::status_id_not_approved, $notify);
1936
+	}
1937
+
1938
+
1939
+	/**
1940
+	 * decline_registration
1941
+	 *
1942
+	 * @param bool $notify whether or not to notify the registrant about their status change.
1943
+	 * @return void
1944
+	 * @throws EE_Error
1945
+	 * @throws EntityNotFoundException
1946
+	 * @throws InvalidArgumentException
1947
+	 * @throws InvalidDataTypeException
1948
+	 * @throws InvalidInterfaceException
1949
+	 * @throws ReflectionException
1950
+	 * @throws RuntimeException
1951
+	 * @throws DomainException
1952
+	 */
1953
+	protected function pending_registration($notify = false)
1954
+	{
1955
+		$this->_reg_status_change_return(EEM_Registration::status_id_pending_payment, $notify);
1956
+	}
1957
+
1958
+
1959
+	/**
1960
+	 * waitlist_registration
1961
+	 *
1962
+	 * @param bool $notify whether or not to notify the registrant about their status change.
1963
+	 * @return void
1964
+	 * @throws EE_Error
1965
+	 * @throws EntityNotFoundException
1966
+	 * @throws InvalidArgumentException
1967
+	 * @throws InvalidDataTypeException
1968
+	 * @throws InvalidInterfaceException
1969
+	 * @throws ReflectionException
1970
+	 * @throws RuntimeException
1971
+	 * @throws DomainException
1972
+	 */
1973
+	protected function wait_list_registration($notify = false)
1974
+	{
1975
+		$this->_reg_status_change_return(EEM_Registration::status_id_wait_list, $notify);
1976
+	}
1977
+
1978
+
1979
+	/**
1980
+	 * generates HTML for the Registration main meta box
1981
+	 *
1982
+	 * @return void
1983
+	 * @throws DomainException
1984
+	 * @throws EE_Error
1985
+	 * @throws InvalidArgumentException
1986
+	 * @throws InvalidDataTypeException
1987
+	 * @throws InvalidInterfaceException
1988
+	 * @throws ReflectionException
1989
+	 * @throws EntityNotFoundException
1990
+	 */
1991
+	public function _reg_details_meta_box()
1992
+	{
1993
+		EEH_Autoloader::register_line_item_display_autoloaders();
1994
+		EEH_Autoloader::register_line_item_filter_autoloaders();
1995
+		EE_Registry::instance()->load_helper('Line_Item');
1996
+		$transaction    = $this->_registration->transaction() ? $this->_registration->transaction()
1997
+			: EE_Transaction::new_instance();
1998
+		$this->_session = $transaction->session_data();
1999
+		$filters        = new EE_Line_Item_Filter_Collection();
2000
+		$filters->add(new EE_Single_Registration_Line_Item_Filter($this->_registration));
2001
+		$filters->add(new EE_Non_Zero_Line_Item_Filter());
2002
+		$line_item_filter_processor              = new EE_Line_Item_Filter_Processor(
2003
+			$filters,
2004
+			$transaction->total_line_item()
2005
+		);
2006
+		$filtered_line_item_tree                 = $line_item_filter_processor->process();
2007
+		$line_item_display                       = new EE_Line_Item_Display(
2008
+			'reg_admin_table',
2009
+			'EE_Admin_Table_Registration_Line_Item_Display_Strategy'
2010
+		);
2011
+		$this->_template_args['line_item_table'] = $line_item_display->display_line_item(
2012
+			$filtered_line_item_tree,
2013
+			['EE_Registration' => $this->_registration]
2014
+		);
2015
+		$attendee                                = $this->_registration->attendee();
2016
+		if (
2017
+			$this->capabilities->current_user_can(
2018
+				'ee_read_transaction',
2019
+				'espresso_transactions_view_transaction'
2020
+			)
2021
+		) {
2022
+			$this->_template_args['view_transaction_button'] = EEH_Template::get_button_or_link(
2023
+				EE_Admin_Page::add_query_args_and_nonce(
2024
+					[
2025
+						'action' => 'view_transaction',
2026
+						'TXN_ID' => $transaction->ID(),
2027
+					],
2028
+					TXN_ADMIN_URL
2029
+				),
2030
+				esc_html__(' View Transaction', 'event_espresso'),
2031
+				'button button--secondary right',
2032
+				'dashicons dashicons-cart'
2033
+			);
2034
+		} else {
2035
+			$this->_template_args['view_transaction_button'] = '';
2036
+		}
2037
+		if (
2038
+			$attendee instanceof EE_Attendee
2039
+			&& $this->capabilities->current_user_can(
2040
+				'ee_send_message',
2041
+				'espresso_registrations_resend_registration'
2042
+			)
2043
+		) {
2044
+			$this->_template_args['resend_registration_button'] = EEH_Template::get_button_or_link(
2045
+				EE_Admin_Page::add_query_args_and_nonce(
2046
+					[
2047
+						'action'      => 'resend_registration',
2048
+						'_REG_ID'     => $this->_registration->ID(),
2049
+						'redirect_to' => 'view_registration',
2050
+					],
2051
+					REG_ADMIN_URL
2052
+				),
2053
+				esc_html__(' Resend Registration', 'event_espresso'),
2054
+				'button button--secondary right',
2055
+				'dashicons dashicons-email-alt'
2056
+			);
2057
+		} else {
2058
+			$this->_template_args['resend_registration_button'] = '';
2059
+		}
2060
+		$this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
2061
+		$payment                               = $transaction->get_first_related('Payment');
2062
+		$payment                               = ! $payment instanceof EE_Payment
2063
+			? EE_Payment::new_instance()
2064
+			: $payment;
2065
+		$payment_method                        = $payment->get_first_related('Payment_Method');
2066
+		$payment_method                        = ! $payment_method instanceof EE_Payment_Method
2067
+			? EE_Payment_Method::new_instance()
2068
+			: $payment_method;
2069
+		$reg_details                           = [
2070
+			'payment_method'       => $payment_method->name(),
2071
+			'response_msg'         => $payment->gateway_response(),
2072
+			'registration_id'      => $this->_registration->get('REG_code'),
2073
+			'registration_session' => $this->_registration->session_ID(),
2074
+			'ip_address'           => isset($this->_session['ip_address']) ? $this->_session['ip_address'] : '',
2075
+			'user_agent'           => isset($this->_session['user_agent']) ? $this->_session['user_agent'] : '',
2076
+		];
2077
+		if (isset($reg_details['registration_id'])) {
2078
+			$this->_template_args['reg_details']['registration_id']['value'] = $reg_details['registration_id'];
2079
+			$this->_template_args['reg_details']['registration_id']['label'] = esc_html__(
2080
+				'Registration ID',
2081
+				'event_espresso'
2082
+			);
2083
+			$this->_template_args['reg_details']['registration_id']['class'] = 'regular-text';
2084
+		}
2085
+		if (isset($reg_details['payment_method'])) {
2086
+			$this->_template_args['reg_details']['payment_method']['value'] = $reg_details['payment_method'];
2087
+			$this->_template_args['reg_details']['payment_method']['label'] = esc_html__(
2088
+				'Most Recent Payment Method',
2089
+				'event_espresso'
2090
+			);
2091
+			$this->_template_args['reg_details']['payment_method']['class'] = 'regular-text';
2092
+			$this->_template_args['reg_details']['response_msg']['value']   = $reg_details['response_msg'];
2093
+			$this->_template_args['reg_details']['response_msg']['label']   = esc_html__(
2094
+				'Payment method response',
2095
+				'event_espresso'
2096
+			);
2097
+			$this->_template_args['reg_details']['response_msg']['class']   = 'regular-text';
2098
+		}
2099
+		$this->_template_args['reg_details']['registration_session']['value'] = $reg_details['registration_session'];
2100
+		$this->_template_args['reg_details']['registration_session']['label'] = esc_html__(
2101
+			'Registration Session',
2102
+			'event_espresso'
2103
+		);
2104
+		$this->_template_args['reg_details']['registration_session']['class'] = 'regular-text';
2105
+		$this->_template_args['reg_details']['ip_address']['value']           = $reg_details['ip_address'];
2106
+		$this->_template_args['reg_details']['ip_address']['label']           = esc_html__(
2107
+			'Registration placed from IP',
2108
+			'event_espresso'
2109
+		);
2110
+		$this->_template_args['reg_details']['ip_address']['class']           = 'regular-text';
2111
+		$this->_template_args['reg_details']['user_agent']['value']           = $reg_details['user_agent'];
2112
+		$this->_template_args['reg_details']['user_agent']['label']           = esc_html__(
2113
+			'Registrant User Agent',
2114
+			'event_espresso'
2115
+		);
2116
+		$this->_template_args['reg_details']['user_agent']['class']           = 'large-text';
2117
+		$this->_template_args['event_link']                                   = EE_Admin_Page::add_query_args_and_nonce(
2118
+			[
2119
+				'action'   => 'default',
2120
+				'event_id' => $this->_registration->event_ID(),
2121
+			],
2122
+			REG_ADMIN_URL
2123
+		);
2124
+
2125
+		$this->_template_args['REG_ID']   = $this->_registration->ID();
2126
+		$this->_template_args['event_id'] = $this->_registration->event_ID();
2127
+
2128
+		$template_path = REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_reg_details.template.php';
2129
+		EEH_Template::display_template($template_path, $this->_template_args); // already escaped
2130
+	}
2131
+
2132
+
2133
+	/**
2134
+	 * generates HTML for the Registration Questions meta box.
2135
+	 * If pre-4.8.32.rc.000 hooks are used, uses old methods (with its filters),
2136
+	 * otherwise uses new forms system
2137
+	 *
2138
+	 * @return void
2139
+	 * @throws DomainException
2140
+	 * @throws EE_Error
2141
+	 * @throws InvalidArgumentException
2142
+	 * @throws InvalidDataTypeException
2143
+	 * @throws InvalidInterfaceException
2144
+	 * @throws ReflectionException
2145
+	 */
2146
+	public function _reg_questions_meta_box()
2147
+	{
2148
+		// allow someone to override this method entirely
2149
+		if (
2150
+			apply_filters(
2151
+				'FHEE__Registrations_Admin_Page___reg_questions_meta_box__do_default',
2152
+				true,
2153
+				$this,
2154
+				$this->_registration
2155
+			)
2156
+		) {
2157
+			$form = $this->_get_reg_custom_questions_form(
2158
+				$this->_registration->ID()
2159
+			);
2160
+
2161
+			$this->_template_args['att_questions'] = count($form->subforms()) > 0
2162
+				? $form->get_html_and_js()
2163
+				: '';
2164
+
2165
+			$this->_template_args['reg_questions_form_action'] = 'edit_registration';
2166
+			$this->_template_args['REG_ID']                    = $this->_registration->ID();
2167
+			$template_path                                     =
2168
+				REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_reg_questions.template.php';
2169
+			EEH_Template::display_template($template_path, $this->_template_args);
2170
+		}
2171
+	}
2172
+
2173
+
2174
+	/**
2175
+	 * form_before_question_group
2176
+	 *
2177
+	 * @param string $output
2178
+	 * @return        string
2179
+	 * @deprecated    as of 4.8.32.rc.000
2180
+	 */
2181
+	public function form_before_question_group($output)
2182
+	{
2183
+		EE_Error::doing_it_wrong(
2184
+			__CLASS__ . '::' . __FUNCTION__,
2185
+			esc_html__(
2186
+				'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.',
2187
+				'event_espresso'
2188
+			),
2189
+			'4.8.32.rc.000'
2190
+		);
2191
+		return '
2192 2192
 	<table class="form-table ee-width-100">
2193 2193
 		<tbody>
2194 2194
 			';
2195
-    }
2196
-
2197
-
2198
-    /**
2199
-     * form_after_question_group
2200
-     *
2201
-     * @param string $output
2202
-     * @return        string
2203
-     * @deprecated    as of 4.8.32.rc.000
2204
-     */
2205
-    public function form_after_question_group($output)
2206
-    {
2207
-        EE_Error::doing_it_wrong(
2208
-            __CLASS__ . '::' . __FUNCTION__,
2209
-            esc_html__(
2210
-                '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.',
2211
-                'event_espresso'
2212
-            ),
2213
-            '4.8.32.rc.000'
2214
-        );
2215
-        return '
2195
+	}
2196
+
2197
+
2198
+	/**
2199
+	 * form_after_question_group
2200
+	 *
2201
+	 * @param string $output
2202
+	 * @return        string
2203
+	 * @deprecated    as of 4.8.32.rc.000
2204
+	 */
2205
+	public function form_after_question_group($output)
2206
+	{
2207
+		EE_Error::doing_it_wrong(
2208
+			__CLASS__ . '::' . __FUNCTION__,
2209
+			esc_html__(
2210
+				'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.',
2211
+				'event_espresso'
2212
+			),
2213
+			'4.8.32.rc.000'
2214
+		);
2215
+		return '
2216 2216
 			<tr class="hide-if-no-js">
2217 2217
 				<th> </th>
2218 2218
 				<td class="reg-admin-edit-attendee-question-td">
2219 2219
 					<a class="reg-admin-edit-attendee-question-lnk" href="#" aria-label="'
2220
-               . esc_attr__('click to edit question', 'event_espresso')
2221
-               . '">
2220
+			   . esc_attr__('click to edit question', 'event_espresso')
2221
+			   . '">
2222 2222
 						<span class="reg-admin-edit-question-group-spn lt-grey-txt">'
2223
-               . esc_html__('edit the above question group', 'event_espresso')
2224
-               . '</span>
2223
+			   . esc_html__('edit the above question group', 'event_espresso')
2224
+			   . '</span>
2225 2225
 						<div class="dashicons dashicons-edit"></div>
2226 2226
 					</a>
2227 2227
 				</td>
@@ -2229,642 +2229,642 @@  discard block
 block discarded – undo
2229 2229
 		</tbody>
2230 2230
 	</table>
2231 2231
 ';
2232
-    }
2233
-
2234
-
2235
-    /**
2236
-     * form_form_field_label_wrap
2237
-     *
2238
-     * @param string $label
2239
-     * @return        string
2240
-     * @deprecated    as of 4.8.32.rc.000
2241
-     */
2242
-    public function form_form_field_label_wrap($label)
2243
-    {
2244
-        EE_Error::doing_it_wrong(
2245
-            __CLASS__ . '::' . __FUNCTION__,
2246
-            esc_html__(
2247
-                '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.',
2248
-                'event_espresso'
2249
-            ),
2250
-            '4.8.32.rc.000'
2251
-        );
2252
-        return '
2232
+	}
2233
+
2234
+
2235
+	/**
2236
+	 * form_form_field_label_wrap
2237
+	 *
2238
+	 * @param string $label
2239
+	 * @return        string
2240
+	 * @deprecated    as of 4.8.32.rc.000
2241
+	 */
2242
+	public function form_form_field_label_wrap($label)
2243
+	{
2244
+		EE_Error::doing_it_wrong(
2245
+			__CLASS__ . '::' . __FUNCTION__,
2246
+			esc_html__(
2247
+				'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.',
2248
+				'event_espresso'
2249
+			),
2250
+			'4.8.32.rc.000'
2251
+		);
2252
+		return '
2253 2253
 			<tr>
2254 2254
 				<th>
2255 2255
 					' . $label . '
2256 2256
 				</th>';
2257
-    }
2258
-
2259
-
2260
-    /**
2261
-     * form_form_field_input__wrap
2262
-     *
2263
-     * @param string $input
2264
-     * @return        string
2265
-     * @deprecated    as of 4.8.32.rc.000
2266
-     */
2267
-    public function form_form_field_input__wrap($input)
2268
-    {
2269
-        EE_Error::doing_it_wrong(
2270
-            __CLASS__ . '::' . __FUNCTION__,
2271
-            esc_html__(
2272
-                '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.',
2273
-                'event_espresso'
2274
-            ),
2275
-            '4.8.32.rc.000'
2276
-        );
2277
-        return '
2257
+	}
2258
+
2259
+
2260
+	/**
2261
+	 * form_form_field_input__wrap
2262
+	 *
2263
+	 * @param string $input
2264
+	 * @return        string
2265
+	 * @deprecated    as of 4.8.32.rc.000
2266
+	 */
2267
+	public function form_form_field_input__wrap($input)
2268
+	{
2269
+		EE_Error::doing_it_wrong(
2270
+			__CLASS__ . '::' . __FUNCTION__,
2271
+			esc_html__(
2272
+				'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.',
2273
+				'event_espresso'
2274
+			),
2275
+			'4.8.32.rc.000'
2276
+		);
2277
+		return '
2278 2278
 				<td class="reg-admin-attendee-questions-input-td disabled-input">
2279 2279
 					' . $input . '
2280 2280
 				</td>
2281 2281
 			</tr>';
2282
-    }
2283
-
2284
-
2285
-    /**
2286
-     * Updates the registration's custom questions according to the form info, if the form is submitted.
2287
-     * If it's not a post, the "view_registrations" route will be called next on the SAME request
2288
-     * to display the page
2289
-     *
2290
-     * @return void
2291
-     * @throws EE_Error
2292
-     * @throws InvalidArgumentException
2293
-     * @throws InvalidDataTypeException
2294
-     * @throws InvalidInterfaceException
2295
-     * @throws ReflectionException
2296
-     */
2297
-    protected function _update_attendee_registration_form()
2298
-    {
2299
-        do_action('AHEE__Registrations_Admin_Page___update_attendee_registration_form__start', $this);
2300
-        if ($_SERVER['REQUEST_METHOD'] === 'POST') {
2301
-            $REG_ID  = $this->request->getRequestParam('_REG_ID', 0, 'int');
2302
-            $success = $this->_save_reg_custom_questions_form($REG_ID);
2303
-            if ($success) {
2304
-                $what  = esc_html__('Registration Form', 'event_espresso');
2305
-                $route = $REG_ID
2306
-                    ? ['action' => 'view_registration', '_REG_ID' => $REG_ID]
2307
-                    : ['action' => 'default'];
2308
-                $this->_redirect_after_action(true, $what, esc_html__('updated', 'event_espresso'), $route);
2309
-            }
2310
-        }
2311
-    }
2312
-
2313
-
2314
-    /**
2315
-     * Gets the form for saving registrations custom questions (if done
2316
-     * previously retrieves the cached form object, which may have validation errors in it)
2317
-     *
2318
-     * @param int $REG_ID
2319
-     * @return EE_Registration_Custom_Questions_Form
2320
-     * @throws EE_Error
2321
-     * @throws InvalidArgumentException
2322
-     * @throws InvalidDataTypeException
2323
-     * @throws InvalidInterfaceException
2324
-     * @throws ReflectionException
2325
-     */
2326
-    protected function _get_reg_custom_questions_form($REG_ID)
2327
-    {
2328
-        if (! $this->_reg_custom_questions_form) {
2329
-            require_once(REG_ADMIN . 'form_sections/EE_Registration_Custom_Questions_Form.form.php');
2330
-            $this->_reg_custom_questions_form = new EE_Registration_Custom_Questions_Form(
2331
-                $this->getRegistrationModel()->get_one_by_ID($REG_ID)
2332
-            );
2333
-            $this->_reg_custom_questions_form->_construct_finalize(null, null);
2334
-        }
2335
-        return $this->_reg_custom_questions_form;
2336
-    }
2337
-
2338
-
2339
-    /**
2340
-     * Saves
2341
-     *
2342
-     * @param bool $REG_ID
2343
-     * @return bool
2344
-     * @throws EE_Error
2345
-     * @throws InvalidArgumentException
2346
-     * @throws InvalidDataTypeException
2347
-     * @throws InvalidInterfaceException
2348
-     * @throws ReflectionException
2349
-     */
2350
-    private function _save_reg_custom_questions_form($REG_ID = 0)
2351
-    {
2352
-        if (! $REG_ID) {
2353
-            EE_Error::add_error(
2354
-                esc_html__(
2355
-                    'An error occurred. No registration ID was received.',
2356
-                    'event_espresso'
2357
-                ),
2358
-                __FILE__,
2359
-                __FUNCTION__,
2360
-                __LINE__
2361
-            );
2362
-        }
2363
-        $form = $this->_get_reg_custom_questions_form($REG_ID);
2364
-        $form->receive_form_submission($this->request->requestParams());
2365
-        $success = false;
2366
-        if ($form->is_valid()) {
2367
-            foreach ($form->subforms() as $question_group_form) {
2368
-                foreach ($question_group_form->inputs() as $question_id => $input) {
2369
-                    $where_conditions    = [
2370
-                        'QST_ID' => $question_id,
2371
-                        'REG_ID' => $REG_ID,
2372
-                    ];
2373
-                    $possibly_new_values = [
2374
-                        'ANS_value' => $input->normalized_value(),
2375
-                    ];
2376
-                    $answer              = EEM_Answer::instance()->get_one([$where_conditions]);
2377
-                    if ($answer instanceof EE_Answer) {
2378
-                        $success = $answer->save($possibly_new_values);
2379
-                    } else {
2380
-                        // insert it then
2381
-                        $cols_n_vals = array_merge($where_conditions, $possibly_new_values);
2382
-                        $answer      = EE_Answer::new_instance($cols_n_vals);
2383
-                        $success     = $answer->save();
2384
-                    }
2385
-                }
2386
-            }
2387
-        } else {
2388
-            EE_Error::add_error($form->get_validation_error_string(), __FILE__, __FUNCTION__, __LINE__);
2389
-        }
2390
-        return $success;
2391
-    }
2392
-
2393
-
2394
-    /**
2395
-     * generates HTML for the Registration main meta box
2396
-     *
2397
-     * @return void
2398
-     * @throws DomainException
2399
-     * @throws EE_Error
2400
-     * @throws InvalidArgumentException
2401
-     * @throws InvalidDataTypeException
2402
-     * @throws InvalidInterfaceException
2403
-     * @throws ReflectionException
2404
-     */
2405
-    public function _reg_attendees_meta_box()
2406
-    {
2407
-        $REG = $this->getRegistrationModel();
2408
-        // get all other registrations on this transaction, and cache
2409
-        // the attendees for them so we don't have to run another query using force_join
2410
-        $registrations                           = $REG->get_all(
2411
-            [
2412
-                [
2413
-                    'TXN_ID' => $this->_registration->transaction_ID(),
2414
-                    'REG_ID' => ['!=', $this->_registration->ID()],
2415
-                ],
2416
-                'force_join'               => ['Attendee'],
2417
-                'default_where_conditions' => 'other_models_only',
2418
-            ]
2419
-        );
2420
-        $this->_template_args['attendees']       = [];
2421
-        $this->_template_args['attendee_notice'] = '';
2422
-        if (
2423
-            empty($registrations)
2424
-            || (is_array($registrations)
2425
-                && ! EEH_Array::get_one_item_from_array($registrations))
2426
-        ) {
2427
-            EE_Error::add_error(
2428
-                esc_html__(
2429
-                    'There are no records attached to this registration. Something may have gone wrong with the registration',
2430
-                    'event_espresso'
2431
-                ),
2432
-                __FILE__,
2433
-                __FUNCTION__,
2434
-                __LINE__
2435
-            );
2436
-            $this->_template_args['attendee_notice'] = EE_Error::get_notices();
2437
-        } else {
2438
-            $att_nmbr = 1;
2439
-            foreach ($registrations as $registration) {
2440
-                /* @var $registration EE_Registration */
2441
-                $attendee                                                      = $registration->attendee()
2442
-                    ? $registration->attendee()
2443
-                    : $this->getAttendeeModel()->create_default_object();
2444
-                $this->_template_args['attendees'][ $att_nmbr ]['STS_ID']      = $registration->status_ID();
2445
-                $this->_template_args['attendees'][ $att_nmbr ]['fname']       = $attendee->fname();
2446
-                $this->_template_args['attendees'][ $att_nmbr ]['lname']       = $attendee->lname();
2447
-                $this->_template_args['attendees'][ $att_nmbr ]['email']       = $attendee->email();
2448
-                $this->_template_args['attendees'][ $att_nmbr ]['final_price'] = $registration->final_price();
2449
-                $this->_template_args['attendees'][ $att_nmbr ]['address']     = implode(
2450
-                    ', ',
2451
-                    $attendee->full_address_as_array()
2452
-                );
2453
-                $this->_template_args['attendees'][ $att_nmbr ]['att_link']    = self::add_query_args_and_nonce(
2454
-                    [
2455
-                        'action' => 'edit_attendee',
2456
-                        'post'   => $attendee->ID(),
2457
-                    ],
2458
-                    REG_ADMIN_URL
2459
-                );
2460
-                $this->_template_args['attendees'][ $att_nmbr ]['event_name']  =
2461
-                    $registration->event_obj() instanceof EE_Event
2462
-                        ? $registration->event_obj()->name()
2463
-                        : '';
2464
-                $att_nmbr++;
2465
-            }
2466
-            $this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
2467
-        }
2468
-        $template_path = REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_attendees.template.php';
2469
-        EEH_Template::display_template($template_path, $this->_template_args);
2470
-    }
2471
-
2472
-
2473
-    /**
2474
-     * generates HTML for the Edit Registration side meta box
2475
-     *
2476
-     * @return void
2477
-     * @throws DomainException
2478
-     * @throws EE_Error
2479
-     * @throws InvalidArgumentException
2480
-     * @throws InvalidDataTypeException
2481
-     * @throws InvalidInterfaceException
2482
-     * @throws ReflectionException
2483
-     */
2484
-    public function _reg_registrant_side_meta_box()
2485
-    {
2486
-        /*@var $attendee EE_Attendee */
2487
-        $att_check = $this->_registration->attendee();
2488
-        $attendee  = $att_check instanceof EE_Attendee
2489
-            ? $att_check
2490
-            : $this->getAttendeeModel()->create_default_object();
2491
-        // now let's determine if this is not the primary registration.  If it isn't then we set the
2492
-        // primary_registration object for reference BUT ONLY if the Attendee object loaded is not the same as the
2493
-        // primary registration object (that way we know if we need to show create button or not)
2494
-        if (! $this->_registration->is_primary_registrant()) {
2495
-            $primary_registration = $this->_registration->get_primary_registration();
2496
-            $primary_attendee     = $primary_registration instanceof EE_Registration ? $primary_registration->attendee()
2497
-                : null;
2498
-            if (! $primary_attendee instanceof EE_Attendee || $attendee->ID() !== $primary_attendee->ID()) {
2499
-                // in here?  This means the displayed registration is not the primary registrant but ALREADY HAS its own
2500
-                // custom attendee object so let's not worry about the primary reg.
2501
-                $primary_registration = null;
2502
-            }
2503
-        } else {
2504
-            $primary_registration = null;
2505
-        }
2506
-        $this->_template_args['ATT_ID']            = $attendee->ID();
2507
-        $this->_template_args['fname']             = $attendee->fname();
2508
-        $this->_template_args['lname']             = $attendee->lname();
2509
-        $this->_template_args['email']             = $attendee->email();
2510
-        $this->_template_args['phone']             = $attendee->phone();
2511
-        $this->_template_args['formatted_address'] = EEH_Address::format($attendee);
2512
-        // edit link
2513
-        $this->_template_args['att_edit_link']  = EE_Admin_Page::add_query_args_and_nonce(
2514
-            [
2515
-                'action' => 'edit_attendee',
2516
-                'post'   => $attendee->ID(),
2517
-            ],
2518
-            REG_ADMIN_URL
2519
-        );
2520
-        $this->_template_args['att_edit_title'] = esc_html__('View details for this contact.', 'event_espresso');
2521
-        $this->_template_args['att_edit_label'] = esc_html__('View/Edit Contact', 'event_espresso');
2522
-        // create link
2523
-        $this->_template_args['create_link']  = $primary_registration instanceof EE_Registration
2524
-            ? EE_Admin_Page::add_query_args_and_nonce(
2525
-                [
2526
-                    'action'  => 'duplicate_attendee',
2527
-                    '_REG_ID' => $this->_registration->ID(),
2528
-                ],
2529
-                REG_ADMIN_URL
2530
-            ) : '';
2531
-        $this->_template_args['create_label'] = esc_html__('Create Contact', 'event_espresso');
2532
-        $this->_template_args['att_check']    = $att_check;
2533
-        $template_path                        =
2534
-            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 DomainException
2545
-     * @throws EE_Error
2546
-     * @throws EntityNotFoundException
2547
-     * @throws InvalidArgumentException
2548
-     * @throws InvalidDataTypeException
2549
-     * @throws InvalidInterfaceException
2550
-     * @throws ReflectionException
2551
-     * @throws RuntimeException
2552
-     * @throws UnexpectedEntityException
2553
-     */
2554
-    protected function _trash_or_restore_registrations($trash = true)
2555
-    {
2556
-        // if empty _REG_ID then get out because there's nothing to do
2557
-        $REG_IDs = $this->request->getRequestParam('_REG_ID', [], 'int', true);
2558
-        if (empty($REG_IDs)) {
2559
-            EE_Error::add_error(
2560
-                sprintf(
2561
-                    esc_html__(
2562
-                        'In order to %1$s registrations you must select which ones you wish to %1$s by clicking the checkboxes.',
2563
-                        'event_espresso'
2564
-                    ),
2565
-                    $trash ? 'trash' : 'restore'
2566
-                ),
2567
-                __FILE__,
2568
-                __LINE__,
2569
-                __FUNCTION__
2570
-            );
2571
-            $this->_redirect_after_action(false, '', '', [], true);
2572
-        }
2573
-        $success        = 0;
2574
-        $overwrite_msgs = false;
2575
-        // Checkboxes
2576
-        $reg_count = count($REG_IDs);
2577
-        // cycle thru checkboxes
2578
-        foreach ($REG_IDs as $REG_ID) {
2579
-            /** @var EE_Registration $REG */
2580
-            $REG      = $this->getRegistrationModel()->get_one_by_ID($REG_ID);
2581
-            $payments = $REG->registration_payments();
2582
-            if (! empty($payments)) {
2583
-                $name           = $REG->attendee() instanceof EE_Attendee
2584
-                    ? $REG->attendee()->full_name()
2585
-                    : esc_html__('Unknown Attendee', 'event_espresso');
2586
-                $overwrite_msgs = true;
2587
-                EE_Error::add_error(
2588
-                    sprintf(
2589
-                        esc_html__(
2590
-                            '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.',
2591
-                            'event_espresso'
2592
-                        ),
2593
-                        $name
2594
-                    ),
2595
-                    __FILE__,
2596
-                    __FUNCTION__,
2597
-                    __LINE__
2598
-                );
2599
-                // can't trash this registration because it has payments.
2600
-                continue;
2601
-            }
2602
-            $updated = $trash ? $REG->delete() : $REG->restore();
2603
-            if ($updated) {
2604
-                $success++;
2605
-            }
2606
-        }
2607
-        $this->_redirect_after_action(
2608
-            $success === $reg_count, // were ALL registrations affected?
2609
-            $success > 1
2610
-                ? esc_html__('Registrations', 'event_espresso')
2611
-                : esc_html__('Registration', 'event_espresso'),
2612
-            $trash
2613
-                ? esc_html__('moved to the trash', 'event_espresso')
2614
-                : esc_html__('restored', 'event_espresso'),
2615
-            $this->mergeExistingRequestParamsWithRedirectArgs(['action' => 'default']),
2616
-            $overwrite_msgs
2617
-        );
2618
-    }
2619
-
2620
-
2621
-    /**
2622
-     * This is used to permanently delete registrations.  Note, this will handle not only deleting permanently the
2623
-     * registration but also.
2624
-     * 1. Removing relations to EE_Attendee
2625
-     * 2. Deleting permanently the related transaction, but ONLY if all related registrations to the transaction are
2626
-     * ALSO trashed.
2627
-     * 3. Deleting permanently any related Line items but only if the above conditions are met.
2628
-     * 4. Removing relationships between all tickets and the related registrations
2629
-     * 5. Deleting permanently any related Answers (and the answers for other related registrations that were deleted.)
2630
-     * 6. Deleting permanently any related Checkins.
2631
-     *
2632
-     * @return void
2633
-     * @throws EE_Error
2634
-     * @throws InvalidArgumentException
2635
-     * @throws InvalidDataTypeException
2636
-     * @throws InvalidInterfaceException
2637
-     * @throws ReflectionException
2638
-     */
2639
-    protected function _delete_registrations()
2640
-    {
2641
-        $REG_MDL = $this->getRegistrationModel();
2642
-        $success = 0;
2643
-        // Checkboxes
2644
-        $REG_IDs = $this->request->getRequestParam('_REG_ID', [], 'int', true);
2645
-
2646
-        if (! empty($REG_IDs)) {
2647
-            // if array has more than one element than success message should be plural
2648
-            $success = count($REG_IDs) > 1 ? 2 : 1;
2649
-            // cycle thru checkboxes
2650
-            foreach ($REG_IDs as $REG_ID) {
2651
-                $REG = $REG_MDL->get_one_by_ID($REG_ID);
2652
-                if (! $REG instanceof EE_Registration) {
2653
-                    continue;
2654
-                }
2655
-                $deleted = $this->_delete_registration($REG);
2656
-                if (! $deleted) {
2657
-                    $success = 0;
2658
-                }
2659
-            }
2660
-        }
2661
-
2662
-        $what        = $success > 1
2663
-            ? esc_html__('Registrations', 'event_espresso')
2664
-            : esc_html__('Registration', 'event_espresso');
2665
-        $action_desc = esc_html__('permanently deleted.', 'event_espresso');
2666
-        $this->_redirect_after_action(
2667
-            $success,
2668
-            $what,
2669
-            $action_desc,
2670
-            $this->mergeExistingRequestParamsWithRedirectArgs(['action' => 'default']),
2671
-            true
2672
-        );
2673
-    }
2674
-
2675
-
2676
-    /**
2677
-     * handles the permanent deletion of a registration.  See comments with _delete_registrations() for details on what
2678
-     * models get affected.
2679
-     *
2680
-     * @param EE_Registration $REG registration to be deleted permanently
2681
-     * @return bool true = successful deletion, false = fail.
2682
-     * @throws EE_Error
2683
-     * @throws InvalidArgumentException
2684
-     * @throws InvalidDataTypeException
2685
-     * @throws InvalidInterfaceException
2686
-     * @throws ReflectionException
2687
-     */
2688
-    protected function _delete_registration(EE_Registration $REG)
2689
-    {
2690
-        // first we start with the transaction... ultimately, we WILL not delete permanently if there are any related
2691
-        // registrations on the transaction that are NOT trashed.
2692
-        $TXN = $REG->get_first_related('Transaction');
2693
-        if (! $TXN instanceof EE_Transaction) {
2694
-            EE_Error::add_error(
2695
-                sprintf(
2696
-                    esc_html__(
2697
-                        '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.',
2698
-                        'event_espresso'
2699
-                    ),
2700
-                    $REG->id()
2701
-                ),
2702
-                __FILE__,
2703
-                __FUNCTION__,
2704
-                __LINE__
2705
-            );
2706
-            return false;
2707
-        }
2708
-        $REGS        = $TXN->get_many_related('Registration');
2709
-        $all_trashed = true;
2710
-        foreach ($REGS as $registration) {
2711
-            if (! $registration->get('REG_deleted')) {
2712
-                $all_trashed = false;
2713
-            }
2714
-        }
2715
-        if (! $all_trashed) {
2716
-            EE_Error::add_error(
2717
-                esc_html__(
2718
-                    '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.',
2719
-                    'event_espresso'
2720
-                ),
2721
-                __FILE__,
2722
-                __FUNCTION__,
2723
-                __LINE__
2724
-            );
2725
-            return false;
2726
-        }
2727
-        // k made it here so that means we can delete all the related transactions and their answers (but let's do them
2728
-        // separately from THIS one).
2729
-        foreach ($REGS as $registration) {
2730
-            // delete related answers
2731
-            $registration->delete_related_permanently('Answer');
2732
-            // remove relationship to EE_Attendee (but we ALWAYS leave the contact record intact)
2733
-            $attendee = $registration->get_first_related('Attendee');
2734
-            if ($attendee instanceof EE_Attendee) {
2735
-                $registration->_remove_relation_to($attendee, 'Attendee');
2736
-            }
2737
-            // now remove relationships to tickets on this registration.
2738
-            $registration->_remove_relations('Ticket');
2739
-            // now delete permanently the checkins related to this registration.
2740
-            $registration->delete_related_permanently('Checkin');
2741
-            if ($registration->ID() === $REG->ID()) {
2742
-                continue;
2743
-            } //we don't want to delete permanently the existing registration just yet.
2744
-            // remove relation to transaction for these registrations if NOT the existing registrations
2745
-            $registration->_remove_relations('Transaction');
2746
-            // delete permanently any related messages.
2747
-            $registration->delete_related_permanently('Message');
2748
-            // now delete this registration permanently
2749
-            $registration->delete_permanently();
2750
-        }
2751
-        // now all related registrations on the transaction are handled.  So let's just handle this registration itself
2752
-        // (the transaction and line items should be all that's left).
2753
-        // delete the line items related to the transaction for this registration.
2754
-        $TXN->delete_related_permanently('Line_Item');
2755
-        // we need to remove all the relationships on the transaction
2756
-        $TXN->delete_related_permanently('Payment');
2757
-        $TXN->delete_related_permanently('Extra_Meta');
2758
-        $TXN->delete_related_permanently('Message');
2759
-        // now we can delete this REG permanently (and the transaction of course)
2760
-        $REG->delete_related_permanently('Transaction');
2761
-        return $REG->delete_permanently();
2762
-    }
2763
-
2764
-
2765
-    /**
2766
-     *    generates HTML for the Register New Attendee Admin page
2767
-     *
2768
-     * @throws DomainException
2769
-     * @throws EE_Error
2770
-     * @throws InvalidArgumentException
2771
-     * @throws InvalidDataTypeException
2772
-     * @throws InvalidInterfaceException
2773
-     * @throws ReflectionException
2774
-     */
2775
-    public function new_registration()
2776
-    {
2777
-        if (! $this->_set_reg_event()) {
2778
-            throw new EE_Error(
2779
-                esc_html__(
2780
-                    'Unable to continue with registering because there is no Event ID in the request',
2781
-                    'event_espresso'
2782
-                )
2783
-            );
2784
-        }
2785
-        /** @var CurrentPage $current_page */
2786
-        $current_page = $this->loader->getShared(CurrentPage::class);
2787
-        $current_page->setEspressoPage(true);
2788
-        // gotta start with a clean slate if we're not coming here via ajax
2789
-        if (
2790
-            ! $this->request->isAjax()
2791
-            && (
2792
-                ! $this->request->requestParamIsSet('processing_registration')
2793
-                || $this->request->requestParamIsSet('step_error')
2794
-            )
2795
-        ) {
2796
-            EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
2797
-        }
2798
-        $this->_template_args['event_name'] = '';
2799
-        // event name
2800
-        if ($this->_reg_event) {
2801
-            $this->_template_args['event_name'] = $this->_reg_event->name();
2802
-            $edit_event_url                     = self::add_query_args_and_nonce(
2803
-                [
2804
-                    'action' => 'edit',
2805
-                    'post'   => $this->_reg_event->ID(),
2806
-                ],
2807
-                EVENTS_ADMIN_URL
2808
-            );
2809
-            $edit_event_lnk                     = '<a href="'
2810
-                                                  . $edit_event_url
2811
-                                                  . '" aria-label="'
2812
-                                                  . esc_attr__('Edit ', 'event_espresso')
2813
-                                                  . $this->_reg_event->name()
2814
-                                                  . '">'
2815
-                                                  . esc_html__('Edit Event', 'event_espresso')
2816
-                                                  . '</a>';
2817
-            $this->_template_args['event_name'] .= ' <span class="admin-page-header-edit-lnk not-bold">'
2818
-                                                   . $edit_event_lnk
2819
-                                                   . '</span>';
2820
-        }
2821
-        $this->_template_args['step_content'] = $this->_get_registration_step_content();
2822
-        if ($this->request->isAjax()) {
2823
-            $this->_return_json();
2824
-        }
2825
-        // grab header
2826
-        $template_path                              =
2827
-            REG_TEMPLATE_PATH . 'reg_admin_register_new_attendee.template.php';
2828
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
2829
-            $template_path,
2830
-            $this->_template_args,
2831
-            true
2832
-        );
2833
-        // $this->_set_publish_post_box_vars( NULL, FALSE, FALSE, NULL, FALSE );
2834
-        // the details template wrapper
2835
-        $this->display_admin_page_with_sidebar();
2836
-    }
2837
-
2838
-
2839
-    /**
2840
-     * This returns the content for a registration step
2841
-     *
2842
-     * @return string html
2843
-     * @throws DomainException
2844
-     * @throws EE_Error
2845
-     * @throws InvalidArgumentException
2846
-     * @throws InvalidDataTypeException
2847
-     * @throws InvalidInterfaceException
2848
-     * @throws ReflectionException
2849
-     */
2850
-    protected function _get_registration_step_content()
2851
-    {
2852
-        if (isset($_COOKIE['ee_registration_added']) && $_COOKIE['ee_registration_added']) {
2853
-            $warning_msg = sprintf(
2854
-                esc_html__(
2855
-                    '%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',
2856
-                    'event_espresso'
2857
-                ),
2858
-                '<br />',
2859
-                '<h3 class="important-notice">',
2860
-                '</h3>',
2861
-                '<div class="float-right">',
2862
-                '<span id="redirect_timer" class="important-notice">30</span>',
2863
-                '</div>',
2864
-                '<b>',
2865
-                '</b>'
2866
-            );
2867
-            return '
2282
+	}
2283
+
2284
+
2285
+	/**
2286
+	 * Updates the registration's custom questions according to the form info, if the form is submitted.
2287
+	 * If it's not a post, the "view_registrations" route will be called next on the SAME request
2288
+	 * to display the page
2289
+	 *
2290
+	 * @return void
2291
+	 * @throws EE_Error
2292
+	 * @throws InvalidArgumentException
2293
+	 * @throws InvalidDataTypeException
2294
+	 * @throws InvalidInterfaceException
2295
+	 * @throws ReflectionException
2296
+	 */
2297
+	protected function _update_attendee_registration_form()
2298
+	{
2299
+		do_action('AHEE__Registrations_Admin_Page___update_attendee_registration_form__start', $this);
2300
+		if ($_SERVER['REQUEST_METHOD'] === 'POST') {
2301
+			$REG_ID  = $this->request->getRequestParam('_REG_ID', 0, 'int');
2302
+			$success = $this->_save_reg_custom_questions_form($REG_ID);
2303
+			if ($success) {
2304
+				$what  = esc_html__('Registration Form', 'event_espresso');
2305
+				$route = $REG_ID
2306
+					? ['action' => 'view_registration', '_REG_ID' => $REG_ID]
2307
+					: ['action' => 'default'];
2308
+				$this->_redirect_after_action(true, $what, esc_html__('updated', 'event_espresso'), $route);
2309
+			}
2310
+		}
2311
+	}
2312
+
2313
+
2314
+	/**
2315
+	 * Gets the form for saving registrations custom questions (if done
2316
+	 * previously retrieves the cached form object, which may have validation errors in it)
2317
+	 *
2318
+	 * @param int $REG_ID
2319
+	 * @return EE_Registration_Custom_Questions_Form
2320
+	 * @throws EE_Error
2321
+	 * @throws InvalidArgumentException
2322
+	 * @throws InvalidDataTypeException
2323
+	 * @throws InvalidInterfaceException
2324
+	 * @throws ReflectionException
2325
+	 */
2326
+	protected function _get_reg_custom_questions_form($REG_ID)
2327
+	{
2328
+		if (! $this->_reg_custom_questions_form) {
2329
+			require_once(REG_ADMIN . 'form_sections/EE_Registration_Custom_Questions_Form.form.php');
2330
+			$this->_reg_custom_questions_form = new EE_Registration_Custom_Questions_Form(
2331
+				$this->getRegistrationModel()->get_one_by_ID($REG_ID)
2332
+			);
2333
+			$this->_reg_custom_questions_form->_construct_finalize(null, null);
2334
+		}
2335
+		return $this->_reg_custom_questions_form;
2336
+	}
2337
+
2338
+
2339
+	/**
2340
+	 * Saves
2341
+	 *
2342
+	 * @param bool $REG_ID
2343
+	 * @return bool
2344
+	 * @throws EE_Error
2345
+	 * @throws InvalidArgumentException
2346
+	 * @throws InvalidDataTypeException
2347
+	 * @throws InvalidInterfaceException
2348
+	 * @throws ReflectionException
2349
+	 */
2350
+	private function _save_reg_custom_questions_form($REG_ID = 0)
2351
+	{
2352
+		if (! $REG_ID) {
2353
+			EE_Error::add_error(
2354
+				esc_html__(
2355
+					'An error occurred. No registration ID was received.',
2356
+					'event_espresso'
2357
+				),
2358
+				__FILE__,
2359
+				__FUNCTION__,
2360
+				__LINE__
2361
+			);
2362
+		}
2363
+		$form = $this->_get_reg_custom_questions_form($REG_ID);
2364
+		$form->receive_form_submission($this->request->requestParams());
2365
+		$success = false;
2366
+		if ($form->is_valid()) {
2367
+			foreach ($form->subforms() as $question_group_form) {
2368
+				foreach ($question_group_form->inputs() as $question_id => $input) {
2369
+					$where_conditions    = [
2370
+						'QST_ID' => $question_id,
2371
+						'REG_ID' => $REG_ID,
2372
+					];
2373
+					$possibly_new_values = [
2374
+						'ANS_value' => $input->normalized_value(),
2375
+					];
2376
+					$answer              = EEM_Answer::instance()->get_one([$where_conditions]);
2377
+					if ($answer instanceof EE_Answer) {
2378
+						$success = $answer->save($possibly_new_values);
2379
+					} else {
2380
+						// insert it then
2381
+						$cols_n_vals = array_merge($where_conditions, $possibly_new_values);
2382
+						$answer      = EE_Answer::new_instance($cols_n_vals);
2383
+						$success     = $answer->save();
2384
+					}
2385
+				}
2386
+			}
2387
+		} else {
2388
+			EE_Error::add_error($form->get_validation_error_string(), __FILE__, __FUNCTION__, __LINE__);
2389
+		}
2390
+		return $success;
2391
+	}
2392
+
2393
+
2394
+	/**
2395
+	 * generates HTML for the Registration main meta box
2396
+	 *
2397
+	 * @return void
2398
+	 * @throws DomainException
2399
+	 * @throws EE_Error
2400
+	 * @throws InvalidArgumentException
2401
+	 * @throws InvalidDataTypeException
2402
+	 * @throws InvalidInterfaceException
2403
+	 * @throws ReflectionException
2404
+	 */
2405
+	public function _reg_attendees_meta_box()
2406
+	{
2407
+		$REG = $this->getRegistrationModel();
2408
+		// get all other registrations on this transaction, and cache
2409
+		// the attendees for them so we don't have to run another query using force_join
2410
+		$registrations                           = $REG->get_all(
2411
+			[
2412
+				[
2413
+					'TXN_ID' => $this->_registration->transaction_ID(),
2414
+					'REG_ID' => ['!=', $this->_registration->ID()],
2415
+				],
2416
+				'force_join'               => ['Attendee'],
2417
+				'default_where_conditions' => 'other_models_only',
2418
+			]
2419
+		);
2420
+		$this->_template_args['attendees']       = [];
2421
+		$this->_template_args['attendee_notice'] = '';
2422
+		if (
2423
+			empty($registrations)
2424
+			|| (is_array($registrations)
2425
+				&& ! EEH_Array::get_one_item_from_array($registrations))
2426
+		) {
2427
+			EE_Error::add_error(
2428
+				esc_html__(
2429
+					'There are no records attached to this registration. Something may have gone wrong with the registration',
2430
+					'event_espresso'
2431
+				),
2432
+				__FILE__,
2433
+				__FUNCTION__,
2434
+				__LINE__
2435
+			);
2436
+			$this->_template_args['attendee_notice'] = EE_Error::get_notices();
2437
+		} else {
2438
+			$att_nmbr = 1;
2439
+			foreach ($registrations as $registration) {
2440
+				/* @var $registration EE_Registration */
2441
+				$attendee                                                      = $registration->attendee()
2442
+					? $registration->attendee()
2443
+					: $this->getAttendeeModel()->create_default_object();
2444
+				$this->_template_args['attendees'][ $att_nmbr ]['STS_ID']      = $registration->status_ID();
2445
+				$this->_template_args['attendees'][ $att_nmbr ]['fname']       = $attendee->fname();
2446
+				$this->_template_args['attendees'][ $att_nmbr ]['lname']       = $attendee->lname();
2447
+				$this->_template_args['attendees'][ $att_nmbr ]['email']       = $attendee->email();
2448
+				$this->_template_args['attendees'][ $att_nmbr ]['final_price'] = $registration->final_price();
2449
+				$this->_template_args['attendees'][ $att_nmbr ]['address']     = implode(
2450
+					', ',
2451
+					$attendee->full_address_as_array()
2452
+				);
2453
+				$this->_template_args['attendees'][ $att_nmbr ]['att_link']    = self::add_query_args_and_nonce(
2454
+					[
2455
+						'action' => 'edit_attendee',
2456
+						'post'   => $attendee->ID(),
2457
+					],
2458
+					REG_ADMIN_URL
2459
+				);
2460
+				$this->_template_args['attendees'][ $att_nmbr ]['event_name']  =
2461
+					$registration->event_obj() instanceof EE_Event
2462
+						? $registration->event_obj()->name()
2463
+						: '';
2464
+				$att_nmbr++;
2465
+			}
2466
+			$this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
2467
+		}
2468
+		$template_path = REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_attendees.template.php';
2469
+		EEH_Template::display_template($template_path, $this->_template_args);
2470
+	}
2471
+
2472
+
2473
+	/**
2474
+	 * generates HTML for the Edit Registration side meta box
2475
+	 *
2476
+	 * @return void
2477
+	 * @throws DomainException
2478
+	 * @throws EE_Error
2479
+	 * @throws InvalidArgumentException
2480
+	 * @throws InvalidDataTypeException
2481
+	 * @throws InvalidInterfaceException
2482
+	 * @throws ReflectionException
2483
+	 */
2484
+	public function _reg_registrant_side_meta_box()
2485
+	{
2486
+		/*@var $attendee EE_Attendee */
2487
+		$att_check = $this->_registration->attendee();
2488
+		$attendee  = $att_check instanceof EE_Attendee
2489
+			? $att_check
2490
+			: $this->getAttendeeModel()->create_default_object();
2491
+		// now let's determine if this is not the primary registration.  If it isn't then we set the
2492
+		// primary_registration object for reference BUT ONLY if the Attendee object loaded is not the same as the
2493
+		// primary registration object (that way we know if we need to show create button or not)
2494
+		if (! $this->_registration->is_primary_registrant()) {
2495
+			$primary_registration = $this->_registration->get_primary_registration();
2496
+			$primary_attendee     = $primary_registration instanceof EE_Registration ? $primary_registration->attendee()
2497
+				: null;
2498
+			if (! $primary_attendee instanceof EE_Attendee || $attendee->ID() !== $primary_attendee->ID()) {
2499
+				// in here?  This means the displayed registration is not the primary registrant but ALREADY HAS its own
2500
+				// custom attendee object so let's not worry about the primary reg.
2501
+				$primary_registration = null;
2502
+			}
2503
+		} else {
2504
+			$primary_registration = null;
2505
+		}
2506
+		$this->_template_args['ATT_ID']            = $attendee->ID();
2507
+		$this->_template_args['fname']             = $attendee->fname();
2508
+		$this->_template_args['lname']             = $attendee->lname();
2509
+		$this->_template_args['email']             = $attendee->email();
2510
+		$this->_template_args['phone']             = $attendee->phone();
2511
+		$this->_template_args['formatted_address'] = EEH_Address::format($attendee);
2512
+		// edit link
2513
+		$this->_template_args['att_edit_link']  = EE_Admin_Page::add_query_args_and_nonce(
2514
+			[
2515
+				'action' => 'edit_attendee',
2516
+				'post'   => $attendee->ID(),
2517
+			],
2518
+			REG_ADMIN_URL
2519
+		);
2520
+		$this->_template_args['att_edit_title'] = esc_html__('View details for this contact.', 'event_espresso');
2521
+		$this->_template_args['att_edit_label'] = esc_html__('View/Edit Contact', 'event_espresso');
2522
+		// create link
2523
+		$this->_template_args['create_link']  = $primary_registration instanceof EE_Registration
2524
+			? EE_Admin_Page::add_query_args_and_nonce(
2525
+				[
2526
+					'action'  => 'duplicate_attendee',
2527
+					'_REG_ID' => $this->_registration->ID(),
2528
+				],
2529
+				REG_ADMIN_URL
2530
+			) : '';
2531
+		$this->_template_args['create_label'] = esc_html__('Create Contact', 'event_espresso');
2532
+		$this->_template_args['att_check']    = $att_check;
2533
+		$template_path                        =
2534
+			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 DomainException
2545
+	 * @throws EE_Error
2546
+	 * @throws EntityNotFoundException
2547
+	 * @throws InvalidArgumentException
2548
+	 * @throws InvalidDataTypeException
2549
+	 * @throws InvalidInterfaceException
2550
+	 * @throws ReflectionException
2551
+	 * @throws RuntimeException
2552
+	 * @throws UnexpectedEntityException
2553
+	 */
2554
+	protected function _trash_or_restore_registrations($trash = true)
2555
+	{
2556
+		// if empty _REG_ID then get out because there's nothing to do
2557
+		$REG_IDs = $this->request->getRequestParam('_REG_ID', [], 'int', true);
2558
+		if (empty($REG_IDs)) {
2559
+			EE_Error::add_error(
2560
+				sprintf(
2561
+					esc_html__(
2562
+						'In order to %1$s registrations you must select which ones you wish to %1$s by clicking the checkboxes.',
2563
+						'event_espresso'
2564
+					),
2565
+					$trash ? 'trash' : 'restore'
2566
+				),
2567
+				__FILE__,
2568
+				__LINE__,
2569
+				__FUNCTION__
2570
+			);
2571
+			$this->_redirect_after_action(false, '', '', [], true);
2572
+		}
2573
+		$success        = 0;
2574
+		$overwrite_msgs = false;
2575
+		// Checkboxes
2576
+		$reg_count = count($REG_IDs);
2577
+		// cycle thru checkboxes
2578
+		foreach ($REG_IDs as $REG_ID) {
2579
+			/** @var EE_Registration $REG */
2580
+			$REG      = $this->getRegistrationModel()->get_one_by_ID($REG_ID);
2581
+			$payments = $REG->registration_payments();
2582
+			if (! empty($payments)) {
2583
+				$name           = $REG->attendee() instanceof EE_Attendee
2584
+					? $REG->attendee()->full_name()
2585
+					: esc_html__('Unknown Attendee', 'event_espresso');
2586
+				$overwrite_msgs = true;
2587
+				EE_Error::add_error(
2588
+					sprintf(
2589
+						esc_html__(
2590
+							'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.',
2591
+							'event_espresso'
2592
+						),
2593
+						$name
2594
+					),
2595
+					__FILE__,
2596
+					__FUNCTION__,
2597
+					__LINE__
2598
+				);
2599
+				// can't trash this registration because it has payments.
2600
+				continue;
2601
+			}
2602
+			$updated = $trash ? $REG->delete() : $REG->restore();
2603
+			if ($updated) {
2604
+				$success++;
2605
+			}
2606
+		}
2607
+		$this->_redirect_after_action(
2608
+			$success === $reg_count, // were ALL registrations affected?
2609
+			$success > 1
2610
+				? esc_html__('Registrations', 'event_espresso')
2611
+				: esc_html__('Registration', 'event_espresso'),
2612
+			$trash
2613
+				? esc_html__('moved to the trash', 'event_espresso')
2614
+				: esc_html__('restored', 'event_espresso'),
2615
+			$this->mergeExistingRequestParamsWithRedirectArgs(['action' => 'default']),
2616
+			$overwrite_msgs
2617
+		);
2618
+	}
2619
+
2620
+
2621
+	/**
2622
+	 * This is used to permanently delete registrations.  Note, this will handle not only deleting permanently the
2623
+	 * registration but also.
2624
+	 * 1. Removing relations to EE_Attendee
2625
+	 * 2. Deleting permanently the related transaction, but ONLY if all related registrations to the transaction are
2626
+	 * ALSO trashed.
2627
+	 * 3. Deleting permanently any related Line items but only if the above conditions are met.
2628
+	 * 4. Removing relationships between all tickets and the related registrations
2629
+	 * 5. Deleting permanently any related Answers (and the answers for other related registrations that were deleted.)
2630
+	 * 6. Deleting permanently any related Checkins.
2631
+	 *
2632
+	 * @return void
2633
+	 * @throws EE_Error
2634
+	 * @throws InvalidArgumentException
2635
+	 * @throws InvalidDataTypeException
2636
+	 * @throws InvalidInterfaceException
2637
+	 * @throws ReflectionException
2638
+	 */
2639
+	protected function _delete_registrations()
2640
+	{
2641
+		$REG_MDL = $this->getRegistrationModel();
2642
+		$success = 0;
2643
+		// Checkboxes
2644
+		$REG_IDs = $this->request->getRequestParam('_REG_ID', [], 'int', true);
2645
+
2646
+		if (! empty($REG_IDs)) {
2647
+			// if array has more than one element than success message should be plural
2648
+			$success = count($REG_IDs) > 1 ? 2 : 1;
2649
+			// cycle thru checkboxes
2650
+			foreach ($REG_IDs as $REG_ID) {
2651
+				$REG = $REG_MDL->get_one_by_ID($REG_ID);
2652
+				if (! $REG instanceof EE_Registration) {
2653
+					continue;
2654
+				}
2655
+				$deleted = $this->_delete_registration($REG);
2656
+				if (! $deleted) {
2657
+					$success = 0;
2658
+				}
2659
+			}
2660
+		}
2661
+
2662
+		$what        = $success > 1
2663
+			? esc_html__('Registrations', 'event_espresso')
2664
+			: esc_html__('Registration', 'event_espresso');
2665
+		$action_desc = esc_html__('permanently deleted.', 'event_espresso');
2666
+		$this->_redirect_after_action(
2667
+			$success,
2668
+			$what,
2669
+			$action_desc,
2670
+			$this->mergeExistingRequestParamsWithRedirectArgs(['action' => 'default']),
2671
+			true
2672
+		);
2673
+	}
2674
+
2675
+
2676
+	/**
2677
+	 * handles the permanent deletion of a registration.  See comments with _delete_registrations() for details on what
2678
+	 * models get affected.
2679
+	 *
2680
+	 * @param EE_Registration $REG registration to be deleted permanently
2681
+	 * @return bool true = successful deletion, false = fail.
2682
+	 * @throws EE_Error
2683
+	 * @throws InvalidArgumentException
2684
+	 * @throws InvalidDataTypeException
2685
+	 * @throws InvalidInterfaceException
2686
+	 * @throws ReflectionException
2687
+	 */
2688
+	protected function _delete_registration(EE_Registration $REG)
2689
+	{
2690
+		// first we start with the transaction... ultimately, we WILL not delete permanently if there are any related
2691
+		// registrations on the transaction that are NOT trashed.
2692
+		$TXN = $REG->get_first_related('Transaction');
2693
+		if (! $TXN instanceof EE_Transaction) {
2694
+			EE_Error::add_error(
2695
+				sprintf(
2696
+					esc_html__(
2697
+						'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.',
2698
+						'event_espresso'
2699
+					),
2700
+					$REG->id()
2701
+				),
2702
+				__FILE__,
2703
+				__FUNCTION__,
2704
+				__LINE__
2705
+			);
2706
+			return false;
2707
+		}
2708
+		$REGS        = $TXN->get_many_related('Registration');
2709
+		$all_trashed = true;
2710
+		foreach ($REGS as $registration) {
2711
+			if (! $registration->get('REG_deleted')) {
2712
+				$all_trashed = false;
2713
+			}
2714
+		}
2715
+		if (! $all_trashed) {
2716
+			EE_Error::add_error(
2717
+				esc_html__(
2718
+					'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.',
2719
+					'event_espresso'
2720
+				),
2721
+				__FILE__,
2722
+				__FUNCTION__,
2723
+				__LINE__
2724
+			);
2725
+			return false;
2726
+		}
2727
+		// k made it here so that means we can delete all the related transactions and their answers (but let's do them
2728
+		// separately from THIS one).
2729
+		foreach ($REGS as $registration) {
2730
+			// delete related answers
2731
+			$registration->delete_related_permanently('Answer');
2732
+			// remove relationship to EE_Attendee (but we ALWAYS leave the contact record intact)
2733
+			$attendee = $registration->get_first_related('Attendee');
2734
+			if ($attendee instanceof EE_Attendee) {
2735
+				$registration->_remove_relation_to($attendee, 'Attendee');
2736
+			}
2737
+			// now remove relationships to tickets on this registration.
2738
+			$registration->_remove_relations('Ticket');
2739
+			// now delete permanently the checkins related to this registration.
2740
+			$registration->delete_related_permanently('Checkin');
2741
+			if ($registration->ID() === $REG->ID()) {
2742
+				continue;
2743
+			} //we don't want to delete permanently the existing registration just yet.
2744
+			// remove relation to transaction for these registrations if NOT the existing registrations
2745
+			$registration->_remove_relations('Transaction');
2746
+			// delete permanently any related messages.
2747
+			$registration->delete_related_permanently('Message');
2748
+			// now delete this registration permanently
2749
+			$registration->delete_permanently();
2750
+		}
2751
+		// now all related registrations on the transaction are handled.  So let's just handle this registration itself
2752
+		// (the transaction and line items should be all that's left).
2753
+		// delete the line items related to the transaction for this registration.
2754
+		$TXN->delete_related_permanently('Line_Item');
2755
+		// we need to remove all the relationships on the transaction
2756
+		$TXN->delete_related_permanently('Payment');
2757
+		$TXN->delete_related_permanently('Extra_Meta');
2758
+		$TXN->delete_related_permanently('Message');
2759
+		// now we can delete this REG permanently (and the transaction of course)
2760
+		$REG->delete_related_permanently('Transaction');
2761
+		return $REG->delete_permanently();
2762
+	}
2763
+
2764
+
2765
+	/**
2766
+	 *    generates HTML for the Register New Attendee Admin page
2767
+	 *
2768
+	 * @throws DomainException
2769
+	 * @throws EE_Error
2770
+	 * @throws InvalidArgumentException
2771
+	 * @throws InvalidDataTypeException
2772
+	 * @throws InvalidInterfaceException
2773
+	 * @throws ReflectionException
2774
+	 */
2775
+	public function new_registration()
2776
+	{
2777
+		if (! $this->_set_reg_event()) {
2778
+			throw new EE_Error(
2779
+				esc_html__(
2780
+					'Unable to continue with registering because there is no Event ID in the request',
2781
+					'event_espresso'
2782
+				)
2783
+			);
2784
+		}
2785
+		/** @var CurrentPage $current_page */
2786
+		$current_page = $this->loader->getShared(CurrentPage::class);
2787
+		$current_page->setEspressoPage(true);
2788
+		// gotta start with a clean slate if we're not coming here via ajax
2789
+		if (
2790
+			! $this->request->isAjax()
2791
+			&& (
2792
+				! $this->request->requestParamIsSet('processing_registration')
2793
+				|| $this->request->requestParamIsSet('step_error')
2794
+			)
2795
+		) {
2796
+			EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
2797
+		}
2798
+		$this->_template_args['event_name'] = '';
2799
+		// event name
2800
+		if ($this->_reg_event) {
2801
+			$this->_template_args['event_name'] = $this->_reg_event->name();
2802
+			$edit_event_url                     = self::add_query_args_and_nonce(
2803
+				[
2804
+					'action' => 'edit',
2805
+					'post'   => $this->_reg_event->ID(),
2806
+				],
2807
+				EVENTS_ADMIN_URL
2808
+			);
2809
+			$edit_event_lnk                     = '<a href="'
2810
+												  . $edit_event_url
2811
+												  . '" aria-label="'
2812
+												  . esc_attr__('Edit ', 'event_espresso')
2813
+												  . $this->_reg_event->name()
2814
+												  . '">'
2815
+												  . esc_html__('Edit Event', 'event_espresso')
2816
+												  . '</a>';
2817
+			$this->_template_args['event_name'] .= ' <span class="admin-page-header-edit-lnk not-bold">'
2818
+												   . $edit_event_lnk
2819
+												   . '</span>';
2820
+		}
2821
+		$this->_template_args['step_content'] = $this->_get_registration_step_content();
2822
+		if ($this->request->isAjax()) {
2823
+			$this->_return_json();
2824
+		}
2825
+		// grab header
2826
+		$template_path                              =
2827
+			REG_TEMPLATE_PATH . 'reg_admin_register_new_attendee.template.php';
2828
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
2829
+			$template_path,
2830
+			$this->_template_args,
2831
+			true
2832
+		);
2833
+		// $this->_set_publish_post_box_vars( NULL, FALSE, FALSE, NULL, FALSE );
2834
+		// the details template wrapper
2835
+		$this->display_admin_page_with_sidebar();
2836
+	}
2837
+
2838
+
2839
+	/**
2840
+	 * This returns the content for a registration step
2841
+	 *
2842
+	 * @return string html
2843
+	 * @throws DomainException
2844
+	 * @throws EE_Error
2845
+	 * @throws InvalidArgumentException
2846
+	 * @throws InvalidDataTypeException
2847
+	 * @throws InvalidInterfaceException
2848
+	 * @throws ReflectionException
2849
+	 */
2850
+	protected function _get_registration_step_content()
2851
+	{
2852
+		if (isset($_COOKIE['ee_registration_added']) && $_COOKIE['ee_registration_added']) {
2853
+			$warning_msg = sprintf(
2854
+				esc_html__(
2855
+					'%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',
2856
+					'event_espresso'
2857
+				),
2858
+				'<br />',
2859
+				'<h3 class="important-notice">',
2860
+				'</h3>',
2861
+				'<div class="float-right">',
2862
+				'<span id="redirect_timer" class="important-notice">30</span>',
2863
+				'</div>',
2864
+				'<b>',
2865
+				'</b>'
2866
+			);
2867
+			return '
2868 2868
 	<div id="ee-add-reg-back-button-dv"><p>' . $warning_msg . '</p></div>
2869 2869
 	<script >
2870 2870
 		// WHOAH !!! it appears that someone is using the back button from the Transaction admin page
@@ -2877,845 +2877,845 @@  discard block
 block discarded – undo
2877 2877
 	        }
2878 2878
 	    }, 800 );
2879 2879
 	</script >';
2880
-        }
2881
-        $template_args = [
2882
-            'title'                    => '',
2883
-            'content'                  => '',
2884
-            'step_button_text'         => '',
2885
-            'show_notification_toggle' => false,
2886
-        ];
2887
-        // to indicate we're processing a new registration
2888
-        $hidden_fields = [
2889
-            'processing_registration' => [
2890
-                'type'  => 'hidden',
2891
-                'value' => 0,
2892
-            ],
2893
-            'event_id'                => [
2894
-                'type'  => 'hidden',
2895
-                'value' => $this->_reg_event->ID(),
2896
-            ],
2897
-        ];
2898
-        // if the cart is empty then we know we're at step one, so we'll display the ticket selector
2899
-        $cart = EE_Registry::instance()->SSN->cart();
2900
-        $step = ! $cart instanceof EE_Cart ? 'ticket' : 'questions';
2901
-        switch ($step) {
2902
-            case 'ticket':
2903
-                $hidden_fields['processing_registration']['value'] = 1;
2904
-                $template_args['title']                            = esc_html__(
2905
-                    'Step One: Select the Ticket for this registration',
2906
-                    'event_espresso'
2907
-                );
2908
-                $template_args['content']                          =
2909
-                    EED_Ticket_Selector::instance()->display_ticket_selector($this->_reg_event);
2910
-                $template_args['content']                          .= '</div>';
2911
-                $template_args['step_button_text']                 = esc_html__(
2912
-                    'Add Tickets and Continue to Registrant Details',
2913
-                    'event_espresso'
2914
-                );
2915
-                $template_args['show_notification_toggle']         = false;
2916
-                break;
2917
-            case 'questions':
2918
-                $hidden_fields['processing_registration']['value'] = 2;
2919
-                $template_args['title']                            = esc_html__(
2920
-                    'Step Two: Add Registrant Details for this Registration',
2921
-                    'event_espresso'
2922
-                );
2923
-                // in theory, we should be able to run EED_SPCO at this point
2924
-                // because the cart should have been set up properly by the first process_reg_step run.
2925
-                $template_args['content']                  =
2926
-                    EED_Single_Page_Checkout::registration_checkout_for_admin();
2927
-                $template_args['step_button_text']         = esc_html__(
2928
-                    'Save Registration and Continue to Details',
2929
-                    'event_espresso'
2930
-                );
2931
-                $template_args['show_notification_toggle'] = true;
2932
-                break;
2933
-        }
2934
-        // we come back to the process_registration_step route.
2935
-        $this->_set_add_edit_form_tags('process_reg_step', $hidden_fields);
2936
-        return EEH_Template::display_template(
2937
-            REG_TEMPLATE_PATH . 'reg_admin_register_new_attendee_step_content.template.php',
2938
-            $template_args,
2939
-            true
2940
-        );
2941
-    }
2942
-
2943
-
2944
-    /**
2945
-     * set_reg_event
2946
-     *
2947
-     * @return bool
2948
-     * @throws EE_Error
2949
-     * @throws InvalidArgumentException
2950
-     * @throws InvalidDataTypeException
2951
-     * @throws InvalidInterfaceException
2952
-     */
2953
-    private function _set_reg_event()
2954
-    {
2955
-        if (is_object($this->_reg_event)) {
2956
-            return true;
2957
-        }
2958
-
2959
-        $EVT_ID = $this->request->getRequestParam('event_id', 0, 'int');
2960
-        if (! $EVT_ID) {
2961
-            return false;
2962
-        }
2963
-        $this->_reg_event = $this->getEventModel()->get_one_by_ID($EVT_ID);
2964
-        return true;
2965
-    }
2966
-
2967
-
2968
-    /**
2969
-     * process_reg_step
2970
-     *
2971
-     * @return void
2972
-     * @throws DomainException
2973
-     * @throws EE_Error
2974
-     * @throws InvalidArgumentException
2975
-     * @throws InvalidDataTypeException
2976
-     * @throws InvalidInterfaceException
2977
-     * @throws ReflectionException
2978
-     * @throws RuntimeException
2979
-     */
2980
-    public function process_reg_step()
2981
-    {
2982
-        EE_System::do_not_cache();
2983
-        $this->_set_reg_event();
2984
-        /** @var CurrentPage $current_page */
2985
-        $current_page = $this->loader->getShared(CurrentPage::class);
2986
-        $current_page->setEspressoPage(true);
2987
-        $this->request->setRequestParam('uts', time());
2988
-        // what step are we on?
2989
-        $cart = EE_Registry::instance()->SSN->cart();
2990
-        $step = ! $cart instanceof EE_Cart ? 'ticket' : 'questions';
2991
-        // if doing ajax then we need to verify the nonce
2992
-        if ($this->request->isAjax()) {
2993
-            $nonce = $this->request->getRequestParam($this->_req_nonce, '');
2994
-            $this->_verify_nonce($nonce, $this->_req_nonce);
2995
-        }
2996
-        switch ($step) {
2997
-            case 'ticket':
2998
-                // process ticket selection
2999
-                $success = EED_Ticket_Selector::instance()->process_ticket_selections();
3000
-                if ($success) {
3001
-                    EE_Error::add_success(
3002
-                        esc_html__(
3003
-                            'Tickets Selected. Now complete the registration.',
3004
-                            'event_espresso'
3005
-                        )
3006
-                    );
3007
-                } else {
3008
-                    $this->request->setRequestParam('step_error', true);
3009
-                    $query_args['step_error'] = $this->request->getRequestParam('step_error', true, 'bool');
3010
-                }
3011
-                if ($this->request->isAjax()) {
3012
-                    $this->new_registration(); // display next step
3013
-                } else {
3014
-                    $query_args = [
3015
-                        'action'                  => 'new_registration',
3016
-                        'processing_registration' => 1,
3017
-                        'event_id'                => $this->_reg_event->ID(),
3018
-                        'uts'                     => time(),
3019
-                    ];
3020
-                    $this->_redirect_after_action(
3021
-                        false,
3022
-                        '',
3023
-                        '',
3024
-                        $query_args,
3025
-                        true
3026
-                    );
3027
-                }
3028
-                break;
3029
-            case 'questions':
3030
-                if (! $this->request->requestParamIsSet('txn_reg_status_change[send_notifications]')) {
3031
-                    add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_false', 15);
3032
-                }
3033
-                // process registration
3034
-                $transaction = EED_Single_Page_Checkout::instance()->process_registration_from_admin();
3035
-                if ($cart instanceof EE_Cart) {
3036
-                    $grand_total = $cart->get_grand_total();
3037
-                    if ($grand_total instanceof EE_Line_Item) {
3038
-                        $grand_total->save_this_and_descendants_to_txn();
3039
-                    }
3040
-                }
3041
-                if (! $transaction instanceof EE_Transaction) {
3042
-                    $query_args = [
3043
-                        'action'                  => 'new_registration',
3044
-                        'processing_registration' => 2,
3045
-                        'event_id'                => $this->_reg_event->ID(),
3046
-                        'uts'                     => time(),
3047
-                    ];
3048
-                    if ($this->request->isAjax()) {
3049
-                        // display registration form again because there are errors (maybe validation?)
3050
-                        $this->new_registration();
3051
-                        return;
3052
-                    }
3053
-                    $this->_redirect_after_action(
3054
-                        false,
3055
-                        '',
3056
-                        '',
3057
-                        $query_args,
3058
-                        true
3059
-                    );
3060
-                    return;
3061
-                }
3062
-                // maybe update status, and make sure to save transaction if not done already
3063
-                if (! $transaction->update_status_based_on_total_paid()) {
3064
-                    $transaction->save();
3065
-                }
3066
-                EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
3067
-                $query_args = [
3068
-                    'action'        => 'redirect_to_txn',
3069
-                    'TXN_ID'        => $transaction->ID(),
3070
-                    'EVT_ID'        => $this->_reg_event->ID(),
3071
-                    'event_name'    => urlencode($this->_reg_event->name()),
3072
-                    'redirect_from' => 'new_registration',
3073
-                ];
3074
-                $this->_redirect_after_action(false, '', '', $query_args, true);
3075
-                break;
3076
-        }
3077
-        // what are you looking here for?  Should be nothing to do at this point.
3078
-    }
3079
-
3080
-
3081
-    /**
3082
-     * redirect_to_txn
3083
-     *
3084
-     * @return void
3085
-     * @throws EE_Error
3086
-     * @throws InvalidArgumentException
3087
-     * @throws InvalidDataTypeException
3088
-     * @throws InvalidInterfaceException
3089
-     * @throws ReflectionException
3090
-     */
3091
-    public function redirect_to_txn()
3092
-    {
3093
-        EE_System::do_not_cache();
3094
-        EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
3095
-        $query_args = [
3096
-            'action' => 'view_transaction',
3097
-            'TXN_ID' => $this->request->getRequestParam('TXN_ID', 0, 'int'),
3098
-            'page'   => 'espresso_transactions',
3099
-        ];
3100
-        if ($this->request->requestParamIsSet('EVT_ID') && $this->request->requestParamIsSet('redirect_from')) {
3101
-            $query_args['EVT_ID']        = $this->request->getRequestParam('EVT_ID', 0, 'int');
3102
-            $query_args['event_name']    = urlencode($this->request->getRequestParam('event_name'));
3103
-            $query_args['redirect_from'] = $this->request->getRequestParam('redirect_from');
3104
-        }
3105
-        EE_Error::add_success(
3106
-            esc_html__(
3107
-                'Registration Created.  Please review the transaction and add any payments as necessary',
3108
-                'event_espresso'
3109
-            )
3110
-        );
3111
-        $this->_redirect_after_action(false, '', '', $query_args, true);
3112
-    }
3113
-
3114
-
3115
-    /**
3116
-     * generates HTML for the Attendee Contact List
3117
-     *
3118
-     * @return void
3119
-     * @throws DomainException
3120
-     * @throws EE_Error
3121
-     */
3122
-    protected function _attendee_contact_list_table()
3123
-    {
3124
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3125
-        $this->_search_btn_label = esc_html__('Contacts', 'event_espresso');
3126
-        $this->display_admin_list_table_page_with_no_sidebar();
3127
-    }
3128
-
3129
-
3130
-    /**
3131
-     * get_attendees
3132
-     *
3133
-     * @param      $per_page
3134
-     * @param bool $count whether to return count or data.
3135
-     * @param bool $trash
3136
-     * @return array|int
3137
-     * @throws EE_Error
3138
-     * @throws InvalidArgumentException
3139
-     * @throws InvalidDataTypeException
3140
-     * @throws InvalidInterfaceException
3141
-     */
3142
-    public function get_attendees($per_page, $count = false, $trash = false)
3143
-    {
3144
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3145
-        require_once(REG_ADMIN . 'EE_Attendee_Contact_List_Table.class.php');
3146
-        $orderby = $this->request->getRequestParam('orderby');
3147
-        switch ($orderby) {
3148
-            case 'ATT_ID':
3149
-            case 'ATT_fname':
3150
-            case 'ATT_email':
3151
-            case 'ATT_city':
3152
-            case 'STA_ID':
3153
-            case 'CNT_ID':
3154
-                break;
3155
-            case 'Registration_Count':
3156
-                $orderby = 'Registration_Count';
3157
-                break;
3158
-            default:
3159
-                $orderby = 'ATT_lname';
3160
-        }
3161
-        $sort         = $this->request->getRequestParam('order', 'ASC');
3162
-        $current_page = $this->request->getRequestParam('paged', 1, 'int');
3163
-        $per_page     = absint($per_page) ? $per_page : 10;
3164
-        $per_page     = $this->request->getRequestParam('perpage', $per_page, 'int');
3165
-        $_where       = [];
3166
-        $search_term  = $this->request->getRequestParam('s');
3167
-        if ($search_term) {
3168
-            $search_term  = '%' . $search_term . '%';
3169
-            $_where['OR'] = [
3170
-                'Registration.Event.EVT_name'       => ['LIKE', $search_term],
3171
-                'Registration.Event.EVT_desc'       => ['LIKE', $search_term],
3172
-                'Registration.Event.EVT_short_desc' => ['LIKE', $search_term],
3173
-                'ATT_fname'                         => ['LIKE', $search_term],
3174
-                'ATT_lname'                         => ['LIKE', $search_term],
3175
-                'ATT_short_bio'                     => ['LIKE', $search_term],
3176
-                'ATT_email'                         => ['LIKE', $search_term],
3177
-                'ATT_address'                       => ['LIKE', $search_term],
3178
-                'ATT_address2'                      => ['LIKE', $search_term],
3179
-                'ATT_city'                          => ['LIKE', $search_term],
3180
-                'Country.CNT_name'                  => ['LIKE', $search_term],
3181
-                'State.STA_name'                    => ['LIKE', $search_term],
3182
-                'ATT_phone'                         => ['LIKE', $search_term],
3183
-                'Registration.REG_final_price'      => ['LIKE', $search_term],
3184
-                'Registration.REG_code'             => ['LIKE', $search_term],
3185
-                'Registration.REG_group_size'       => ['LIKE', $search_term],
3186
-            ];
3187
-        }
3188
-        $offset     = ($current_page - 1) * $per_page;
3189
-        $limit      = $count ? null : [$offset, $per_page];
3190
-        $query_args = [
3191
-            $_where,
3192
-            'extra_selects' => ['Registration_Count' => ['Registration.REG_ID', 'count', '%d']],
3193
-            'limit'         => $limit,
3194
-        ];
3195
-        if (! $count) {
3196
-            $query_args['order_by'] = [$orderby => $sort];
3197
-        }
3198
-        $query_args[0]['status'] = $trash ? ['!=', 'publish'] : ['IN', ['publish']];
3199
-        return $count
3200
-            ? $this->getAttendeeModel()->count($query_args, 'ATT_ID', true)
3201
-            : $this->getAttendeeModel()->get_all($query_args);
3202
-    }
3203
-
3204
-
3205
-    /**
3206
-     * This is just taking care of resending the registration confirmation
3207
-     *
3208
-     * @return void
3209
-     * @throws EE_Error
3210
-     * @throws InvalidArgumentException
3211
-     * @throws InvalidDataTypeException
3212
-     * @throws InvalidInterfaceException
3213
-     * @throws ReflectionException
3214
-     */
3215
-    protected function _resend_registration()
3216
-    {
3217
-        $this->_process_resend_registration();
3218
-        $REG_ID      = $this->request->getRequestParam('_REG_ID', 0, 'int');
3219
-        $redirect_to = $this->request->getRequestParam('redirect_to');
3220
-        $query_args  = $redirect_to
3221
-            ? ['action' => $redirect_to, '_REG_ID' => $REG_ID]
3222
-            : ['action' => 'default'];
3223
-        $this->_redirect_after_action(false, '', '', $query_args, true);
3224
-    }
3225
-
3226
-
3227
-    /**
3228
-     * Creates a registration report, but accepts the name of a method to use for preparing the query parameters
3229
-     * to use when selecting registrations
3230
-     *
3231
-     * @param string $method_name_for_getting_query_params the name of the method (on this class) to use for preparing
3232
-     *                                                     the query parameters from the request
3233
-     * @return void ends the request with a redirect or download
3234
-     */
3235
-    public function _registrations_report_base($method_name_for_getting_query_params)
3236
-    {
3237
-        $EVT_ID = $this->request->requestParamIsSet('EVT_ID')
3238
-            ? $this->request->getRequestParam('EVT_ID', 0, DataType::INT)
3239
-            : null;
3240
-        if (! defined('EE_USE_OLD_CSV_REPORT_CLASS')) {
3241
-            $return_url    = $this->request->getRequestParam('return_url', '', DataType::URL);
3242
-            $filters       = $this->request->getRequestParam('filters', [], DataType::STRING, true);
3243
-            $report_params = $this->$method_name_for_getting_query_params($filters);
3244
-            $use_filters   = $this->request->getRequestParam('use_filters', false, DataType::BOOL);
3245
-            wp_redirect(
3246
-                EE_Admin_Page::add_query_args_and_nonce(
3247
-                    [
3248
-                        'page'        => EED_Batch::PAGE_SLUG,
3249
-                        'batch'       => EED_Batch::batch_file_job,
3250
-                        'EVT_ID'      => $EVT_ID,
3251
-                        'filters'     => urlencode(serialize($report_params)),
3252
-                        'use_filters' => urlencode($use_filters),
3253
-                        'job_handler' => urlencode('EventEspresso\core\libraries\batch\JobHandlers\RegistrationsReport'),
3254
-                        'return_url'  => urlencode($return_url),
3255
-                    ]
3256
-                )
3257
-            );
3258
-        } else {
3259
-            // Pull the current request params
3260
-            $request_args = $this->request->requestParams();
3261
-            // Set the required request_args to be passed to the export
3262
-            $required_request_args = [
3263
-                'export' => 'report',
3264
-                'action' => 'registrations_report_for_event',
3265
-                'EVT_ID' => $EVT_ID,
3266
-            ];
3267
-            // Merge required request args, overriding any currently set
3268
-            $request_args = array_merge($request_args, $required_request_args);
3269
-            if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3270
-                require_once(EE_CLASSES . 'EE_Export.class.php');
3271
-                $EE_Export = EE_Export::instance($request_args);
3272
-                $EE_Export->export();
3273
-            }
3274
-        }
3275
-    }
3276
-
3277
-
3278
-    /**
3279
-     * Creates a registration report using only query parameters in the request
3280
-     *
3281
-     * @return void
3282
-     */
3283
-    public function _registrations_report()
3284
-    {
3285
-        $this->_registrations_report_base('_get_registration_query_parameters');
3286
-    }
3287
-
3288
-
3289
-    public function _contact_list_export()
3290
-    {
3291
-        if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3292
-            require_once(EE_CLASSES . 'EE_Export.class.php');
3293
-            $EE_Export = EE_Export::instance($this->request->requestParams());
3294
-            $EE_Export->export_attendees();
3295
-        }
3296
-    }
3297
-
3298
-
3299
-    public function _contact_list_report()
3300
-    {
3301
-        if (! defined('EE_USE_OLD_CSV_REPORT_CLASS')) {
3302
-            wp_redirect(
3303
-                EE_Admin_Page::add_query_args_and_nonce(
3304
-                    [
3305
-                        'page'        => EED_Batch::PAGE_SLUG,
3306
-                        'batch'       => EED_Batch::batch_file_job,
3307
-                        'job_handler' => urlencode('EventEspresso\core\libraries\batch\JobHandlers\AttendeesReport'),
3308
-                        'return_url'  => urlencode($this->request->getRequestParam('return_url', '', DataType::URL)),
3309
-                    ]
3310
-                )
3311
-            );
3312
-        } else {
3313
-            if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3314
-                require_once(EE_CLASSES . 'EE_Export.class.php');
3315
-                $EE_Export = EE_Export::instance($this->request->requestParams());
3316
-                $EE_Export->report_attendees();
3317
-            }
3318
-        }
3319
-    }
3320
-
3321
-
3322
-
3323
-
3324
-
3325
-    /***************************************        ATTENDEE DETAILS        ***************************************/
3326
-    /**
3327
-     * This duplicates the attendee object for the given incoming registration id and attendee_id.
3328
-     *
3329
-     * @return void
3330
-     * @throws EE_Error
3331
-     * @throws InvalidArgumentException
3332
-     * @throws InvalidDataTypeException
3333
-     * @throws InvalidInterfaceException
3334
-     * @throws ReflectionException
3335
-     */
3336
-    protected function _duplicate_attendee()
3337
-    {
3338
-        $REG_ID = $this->request->getRequestParam('_REG_ID', 0, 'int');
3339
-        $action = $this->request->getRequestParam('return', 'default');
3340
-        // verify we have necessary info
3341
-        if (! $REG_ID) {
3342
-            EE_Error::add_error(
3343
-                esc_html__(
3344
-                    'Unable to create the contact for the registration because the required parameters are not present (_REG_ID )',
3345
-                    'event_espresso'
3346
-                ),
3347
-                __FILE__,
3348
-                __LINE__,
3349
-                __FUNCTION__
3350
-            );
3351
-            $query_args = ['action' => $action];
3352
-            $this->_redirect_after_action('', '', '', $query_args, true);
3353
-        }
3354
-        // okay necessary deets present... let's dupe the incoming attendee and attach to incoming registration.
3355
-        $registration = $this->getRegistrationModel()->get_one_by_ID($REG_ID);
3356
-        if (! $registration instanceof EE_Registration) {
3357
-            throw new RuntimeException(
3358
-                sprintf(
3359
-                    esc_html__(
3360
-                        'Unable to create the contact because a valid registration could not be retrieved for REG ID: %1$d',
3361
-                        'event_espresso'
3362
-                    ),
3363
-                    $REG_ID
3364
-                )
3365
-            );
3366
-        }
3367
-        $attendee = $registration->attendee();
3368
-        // remove relation of existing attendee on registration
3369
-        $registration->_remove_relation_to($attendee, 'Attendee');
3370
-        // new attendee
3371
-        $new_attendee = clone $attendee;
3372
-        $new_attendee->set('ATT_ID', 0);
3373
-        $new_attendee->save();
3374
-        // add new attendee to reg
3375
-        $registration->_add_relation_to($new_attendee, 'Attendee');
3376
-        EE_Error::add_success(
3377
-            esc_html__(
3378
-                'New Contact record created.  Now make any edits you wish to make for this contact.',
3379
-                'event_espresso'
3380
-            )
3381
-        );
3382
-        // redirect to edit page for attendee
3383
-        $query_args = ['post' => $new_attendee->ID(), 'action' => 'edit_attendee'];
3384
-        $this->_redirect_after_action('', '', '', $query_args, true);
3385
-    }
3386
-
3387
-
3388
-    /**
3389
-     * Callback invoked by parent EE_Admin_CPT class hooked in on `save_post` wp hook.
3390
-     *
3391
-     * @param int     $post_id
3392
-     * @param WP_Post $post
3393
-     * @throws DomainException
3394
-     * @throws EE_Error
3395
-     * @throws InvalidArgumentException
3396
-     * @throws InvalidDataTypeException
3397
-     * @throws InvalidInterfaceException
3398
-     * @throws LogicException
3399
-     * @throws InvalidFormSubmissionException
3400
-     * @throws ReflectionException
3401
-     */
3402
-    protected function _insert_update_cpt_item($post_id, $post)
3403
-    {
3404
-        $success  = true;
3405
-        $attendee = $post instanceof WP_Post && $post->post_type === 'espresso_attendees'
3406
-            ? $this->getAttendeeModel()->get_one_by_ID($post_id)
3407
-            : null;
3408
-        // for attendee updates
3409
-        if ($attendee instanceof EE_Attendee) {
3410
-            // note we should only be UPDATING attendees at this point.
3411
-            $fname          = $this->request->getRequestParam('ATT_fname', '');
3412
-            $lname          = $this->request->getRequestParam('ATT_lname', '');
3413
-            $updated_fields = [
3414
-                'ATT_fname'     => $fname,
3415
-                'ATT_lname'     => $lname,
3416
-                'ATT_full_name' => "{$fname} {$lname}",
3417
-                'ATT_address'   => $this->request->getRequestParam('ATT_address', ''),
3418
-                'ATT_address2'  => $this->request->getRequestParam('ATT_address2', ''),
3419
-                'ATT_city'      => $this->request->getRequestParam('ATT_city', ''),
3420
-                'STA_ID'        => $this->request->getRequestParam('STA_ID', ''),
3421
-                'CNT_ISO'       => $this->request->getRequestParam('CNT_ISO', ''),
3422
-                'ATT_zip'       => $this->request->getRequestParam('ATT_zip', ''),
3423
-            ];
3424
-            foreach ($updated_fields as $field => $value) {
3425
-                $attendee->set($field, $value);
3426
-            }
3427
-
3428
-            // process contact details metabox form handler (which will also save the attendee)
3429
-            $contact_details_form = $this->getAttendeeContactDetailsMetaboxFormHandler($attendee);
3430
-            $success              = $contact_details_form->process($this->request->requestParams());
3431
-
3432
-            $attendee_update_callbacks = apply_filters(
3433
-                'FHEE__Registrations_Admin_Page__insert_update_cpt_item__attendee_update',
3434
-                []
3435
-            );
3436
-            foreach ($attendee_update_callbacks as $a_callback) {
3437
-                if (false === call_user_func_array($a_callback, [$attendee, $this->request->requestParams()])) {
3438
-                    throw new EE_Error(
3439
-                        sprintf(
3440
-                            esc_html__(
3441
-                                '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.',
3442
-                                'event_espresso'
3443
-                            ),
3444
-                            $a_callback
3445
-                        )
3446
-                    );
3447
-                }
3448
-            }
3449
-        }
3450
-
3451
-        if ($success === false) {
3452
-            EE_Error::add_error(
3453
-                esc_html__(
3454
-                    'Something went wrong with updating the meta table data for the registration.',
3455
-                    'event_espresso'
3456
-                ),
3457
-                __FILE__,
3458
-                __FUNCTION__,
3459
-                __LINE__
3460
-            );
3461
-        }
3462
-    }
3463
-
3464
-
3465
-    public function trash_cpt_item($post_id)
3466
-    {
3467
-    }
3468
-
3469
-
3470
-    public function delete_cpt_item($post_id)
3471
-    {
3472
-    }
3473
-
3474
-
3475
-    public function restore_cpt_item($post_id)
3476
-    {
3477
-    }
3478
-
3479
-
3480
-    protected function _restore_cpt_item($post_id, $revision_id)
3481
-    {
3482
-    }
3483
-
3484
-
3485
-    /**
3486
-     * @throws EE_Error
3487
-     * @throws ReflectionException
3488
-     * @since 4.10.2.p
3489
-     */
3490
-    public function attendee_editor_metaboxes()
3491
-    {
3492
-        $this->verify_cpt_object();
3493
-        remove_meta_box(
3494
-            'postexcerpt',
3495
-            $this->_cpt_routes[ $this->_req_action ],
3496
-            'normal'
3497
-        );
3498
-        remove_meta_box('commentstatusdiv', $this->_cpt_routes[ $this->_req_action ], 'normal');
3499
-        if (post_type_supports('espresso_attendees', 'excerpt')) {
3500
-            $this->addMetaBox(
3501
-                'postexcerpt',
3502
-                esc_html__('Short Biography', 'event_espresso'),
3503
-                'post_excerpt_meta_box',
3504
-                $this->_cpt_routes[ $this->_req_action ]
3505
-            );
3506
-        }
3507
-        if (post_type_supports('espresso_attendees', 'comments')) {
3508
-            $this->addMetaBox(
3509
-                'commentsdiv',
3510
-                esc_html__('Notes on the Contact', 'event_espresso'),
3511
-                'post_comment_meta_box',
3512
-                $this->_cpt_routes[ $this->_req_action ],
3513
-                'normal',
3514
-                'core'
3515
-            );
3516
-        }
3517
-        $this->addMetaBox(
3518
-            'attendee_contact_info',
3519
-            esc_html__('Contact Info', 'event_espresso'),
3520
-            [$this, 'attendee_contact_info'],
3521
-            $this->_cpt_routes[ $this->_req_action ],
3522
-            'side',
3523
-            'core'
3524
-        );
3525
-        $this->addMetaBox(
3526
-            'attendee_details_address',
3527
-            esc_html__('Address Details', 'event_espresso'),
3528
-            [$this, 'attendee_address_details'],
3529
-            $this->_cpt_routes[ $this->_req_action ],
3530
-            'normal',
3531
-            'core'
3532
-        );
3533
-        $this->addMetaBox(
3534
-            'attendee_registrations',
3535
-            esc_html__('Registrations for this Contact', 'event_espresso'),
3536
-            [$this, 'attendee_registrations_meta_box'],
3537
-            $this->_cpt_routes[ $this->_req_action ]
3538
-        );
3539
-    }
3540
-
3541
-
3542
-    /**
3543
-     * Metabox for attendee contact info
3544
-     *
3545
-     * @param WP_Post $post wp post object
3546
-     * @return void attendee contact info ( and form )
3547
-     * @throws EE_Error
3548
-     * @throws InvalidArgumentException
3549
-     * @throws InvalidDataTypeException
3550
-     * @throws InvalidInterfaceException
3551
-     * @throws LogicException
3552
-     * @throws DomainException
3553
-     */
3554
-    public function attendee_contact_info($post)
3555
-    {
3556
-        // get attendee object ( should already have it )
3557
-        $form = $this->getAttendeeContactDetailsMetaboxFormHandler($this->_cpt_model_obj);
3558
-        $form->enqueueStylesAndScripts();
3559
-        echo wp_kses($form->display(), AllowedTags::getWithFormTags());
3560
-    }
3561
-
3562
-
3563
-    /**
3564
-     * Return form handler for the contact details metabox
3565
-     *
3566
-     * @param EE_Attendee $attendee
3567
-     * @return AttendeeContactDetailsMetaboxFormHandler
3568
-     * @throws DomainException
3569
-     * @throws InvalidArgumentException
3570
-     * @throws InvalidDataTypeException
3571
-     * @throws InvalidInterfaceException
3572
-     */
3573
-    protected function getAttendeeContactDetailsMetaboxFormHandler(EE_Attendee $attendee)
3574
-    {
3575
-        return new AttendeeContactDetailsMetaboxFormHandler($attendee, EE_Registry::instance());
3576
-    }
3577
-
3578
-
3579
-    /**
3580
-     * Metabox for attendee details
3581
-     *
3582
-     * @param WP_Post $post wp post object
3583
-     * @throws EE_Error
3584
-     * @throws ReflectionException
3585
-     */
3586
-    public function attendee_address_details($post)
3587
-    {
3588
-        // get attendee object (should already have it)
3589
-        $this->_template_args['attendee']     = $this->_cpt_model_obj;
3590
-        $this->_template_args['state_html']   = EEH_Form_Fields::generate_form_input(
3591
-            new EE_Question_Form_Input(
3592
-                EE_Question::new_instance(
3593
-                    [
3594
-                        'QST_ID'           => 0,
3595
-                        'QST_display_text' => esc_html__('State/Province', 'event_espresso'),
3596
-                        'QST_system'       => 'admin-state',
3597
-                    ]
3598
-                ),
3599
-                EE_Answer::new_instance(
3600
-                    [
3601
-                        'ANS_ID'    => 0,
3602
-                        'ANS_value' => $this->_cpt_model_obj->state_ID(),
3603
-                    ]
3604
-                ),
3605
-                [
3606
-                    'input_id'       => 'STA_ID',
3607
-                    'input_name'     => 'STA_ID',
3608
-                    'input_prefix'   => '',
3609
-                    'append_qstn_id' => false,
3610
-                ]
3611
-            )
3612
-        );
3613
-        $this->_template_args['country_html'] = EEH_Form_Fields::generate_form_input(
3614
-            new EE_Question_Form_Input(
3615
-                EE_Question::new_instance(
3616
-                    [
3617
-                        'QST_ID'           => 0,
3618
-                        'QST_display_text' => esc_html__('Country', 'event_espresso'),
3619
-                        'QST_system'       => 'admin-country',
3620
-                    ]
3621
-                ),
3622
-                EE_Answer::new_instance(
3623
-                    [
3624
-                        'ANS_ID'    => 0,
3625
-                        'ANS_value' => $this->_cpt_model_obj->country_ID(),
3626
-                    ]
3627
-                ),
3628
-                [
3629
-                    'input_id'       => 'CNT_ISO',
3630
-                    'input_name'     => 'CNT_ISO',
3631
-                    'input_prefix'   => '',
3632
-                    'append_qstn_id' => false,
3633
-                ]
3634
-            )
3635
-        );
3636
-        $template                             =
3637
-            REG_TEMPLATE_PATH . 'attendee_address_details_metabox_content.template.php';
3638
-        EEH_Template::display_template($template, $this->_template_args);
3639
-    }
3640
-
3641
-
3642
-    /**
3643
-     * _attendee_details
3644
-     *
3645
-     * @param $post
3646
-     * @return void
3647
-     * @throws DomainException
3648
-     * @throws EE_Error
3649
-     * @throws InvalidArgumentException
3650
-     * @throws InvalidDataTypeException
3651
-     * @throws InvalidInterfaceException
3652
-     * @throws ReflectionException
3653
-     */
3654
-    public function attendee_registrations_meta_box($post)
3655
-    {
3656
-        $this->_template_args['attendee']      = $this->_cpt_model_obj;
3657
-        $this->_template_args['registrations'] = $this->_cpt_model_obj->get_many_related('Registration');
3658
-        $template                              =
3659
-            REG_TEMPLATE_PATH . 'attendee_registrations_main_meta_box.template.php';
3660
-        EEH_Template::display_template($template, $this->_template_args);
3661
-    }
3662
-
3663
-
3664
-    /**
3665
-     * add in the form fields for the attendee edit
3666
-     *
3667
-     * @param WP_Post $post wp post object
3668
-     * @return void echos html for new form.
3669
-     * @throws DomainException
3670
-     */
3671
-    public function after_title_form_fields($post)
3672
-    {
3673
-        if ($post->post_type === 'espresso_attendees') {
3674
-            $template                  = REG_TEMPLATE_PATH . 'attendee_details_after_title_form_fields.template.php';
3675
-            $template_args['attendee'] = $this->_cpt_model_obj;
3676
-            EEH_Template::display_template($template, $template_args);
3677
-        }
3678
-    }
3679
-
3680
-
3681
-    /**
3682
-     * _trash_or_restore_attendee
3683
-     *
3684
-     * @param boolean $trash - whether to move item to trash (TRUE) or restore it (FALSE)
3685
-     * @return void
3686
-     * @throws EE_Error
3687
-     * @throws InvalidArgumentException
3688
-     * @throws InvalidDataTypeException
3689
-     * @throws InvalidInterfaceException
3690
-     */
3691
-    protected function _trash_or_restore_attendees($trash = true)
3692
-    {
3693
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3694
-        $status = $trash ? 'trash' : 'publish';
3695
-        // Checkboxes
3696
-        if ($this->request->requestParamIsSet('checkbox')) {
3697
-            $ATT_IDs = $this->request->getRequestParam('checkbox', [], 'int', true);
3698
-            // if array has more than one element than success message should be plural
3699
-            $success = count($ATT_IDs) > 1 ? 2 : 1;
3700
-            // cycle thru checkboxes
3701
-            foreach ($ATT_IDs as $ATT_ID) {
3702
-                $updated = $this->getAttendeeModel()->update_by_ID(['status' => $status], $ATT_ID);
3703
-                if (! $updated) {
3704
-                    $success = 0;
3705
-                }
3706
-            }
3707
-        } else {
3708
-            // grab single id and delete
3709
-            $ATT_ID = $this->request->getRequestParam('ATT_ID', 0, 'int');
3710
-            // update attendee
3711
-            $success = $this->getAttendeeModel()->update_by_ID(['status' => $status], $ATT_ID) ? 1 : 0;
3712
-        }
3713
-        $what        = $success > 1
3714
-            ? esc_html__('Contacts', 'event_espresso')
3715
-            : esc_html__('Contact', 'event_espresso');
3716
-        $action_desc = $trash
3717
-            ? esc_html__('moved to the trash', 'event_espresso')
3718
-            : esc_html__('restored', 'event_espresso');
3719
-        $this->_redirect_after_action($success, $what, $action_desc, ['action' => 'contact_list']);
3720
-    }
2880
+		}
2881
+		$template_args = [
2882
+			'title'                    => '',
2883
+			'content'                  => '',
2884
+			'step_button_text'         => '',
2885
+			'show_notification_toggle' => false,
2886
+		];
2887
+		// to indicate we're processing a new registration
2888
+		$hidden_fields = [
2889
+			'processing_registration' => [
2890
+				'type'  => 'hidden',
2891
+				'value' => 0,
2892
+			],
2893
+			'event_id'                => [
2894
+				'type'  => 'hidden',
2895
+				'value' => $this->_reg_event->ID(),
2896
+			],
2897
+		];
2898
+		// if the cart is empty then we know we're at step one, so we'll display the ticket selector
2899
+		$cart = EE_Registry::instance()->SSN->cart();
2900
+		$step = ! $cart instanceof EE_Cart ? 'ticket' : 'questions';
2901
+		switch ($step) {
2902
+			case 'ticket':
2903
+				$hidden_fields['processing_registration']['value'] = 1;
2904
+				$template_args['title']                            = esc_html__(
2905
+					'Step One: Select the Ticket for this registration',
2906
+					'event_espresso'
2907
+				);
2908
+				$template_args['content']                          =
2909
+					EED_Ticket_Selector::instance()->display_ticket_selector($this->_reg_event);
2910
+				$template_args['content']                          .= '</div>';
2911
+				$template_args['step_button_text']                 = esc_html__(
2912
+					'Add Tickets and Continue to Registrant Details',
2913
+					'event_espresso'
2914
+				);
2915
+				$template_args['show_notification_toggle']         = false;
2916
+				break;
2917
+			case 'questions':
2918
+				$hidden_fields['processing_registration']['value'] = 2;
2919
+				$template_args['title']                            = esc_html__(
2920
+					'Step Two: Add Registrant Details for this Registration',
2921
+					'event_espresso'
2922
+				);
2923
+				// in theory, we should be able to run EED_SPCO at this point
2924
+				// because the cart should have been set up properly by the first process_reg_step run.
2925
+				$template_args['content']                  =
2926
+					EED_Single_Page_Checkout::registration_checkout_for_admin();
2927
+				$template_args['step_button_text']         = esc_html__(
2928
+					'Save Registration and Continue to Details',
2929
+					'event_espresso'
2930
+				);
2931
+				$template_args['show_notification_toggle'] = true;
2932
+				break;
2933
+		}
2934
+		// we come back to the process_registration_step route.
2935
+		$this->_set_add_edit_form_tags('process_reg_step', $hidden_fields);
2936
+		return EEH_Template::display_template(
2937
+			REG_TEMPLATE_PATH . 'reg_admin_register_new_attendee_step_content.template.php',
2938
+			$template_args,
2939
+			true
2940
+		);
2941
+	}
2942
+
2943
+
2944
+	/**
2945
+	 * set_reg_event
2946
+	 *
2947
+	 * @return bool
2948
+	 * @throws EE_Error
2949
+	 * @throws InvalidArgumentException
2950
+	 * @throws InvalidDataTypeException
2951
+	 * @throws InvalidInterfaceException
2952
+	 */
2953
+	private function _set_reg_event()
2954
+	{
2955
+		if (is_object($this->_reg_event)) {
2956
+			return true;
2957
+		}
2958
+
2959
+		$EVT_ID = $this->request->getRequestParam('event_id', 0, 'int');
2960
+		if (! $EVT_ID) {
2961
+			return false;
2962
+		}
2963
+		$this->_reg_event = $this->getEventModel()->get_one_by_ID($EVT_ID);
2964
+		return true;
2965
+	}
2966
+
2967
+
2968
+	/**
2969
+	 * process_reg_step
2970
+	 *
2971
+	 * @return void
2972
+	 * @throws DomainException
2973
+	 * @throws EE_Error
2974
+	 * @throws InvalidArgumentException
2975
+	 * @throws InvalidDataTypeException
2976
+	 * @throws InvalidInterfaceException
2977
+	 * @throws ReflectionException
2978
+	 * @throws RuntimeException
2979
+	 */
2980
+	public function process_reg_step()
2981
+	{
2982
+		EE_System::do_not_cache();
2983
+		$this->_set_reg_event();
2984
+		/** @var CurrentPage $current_page */
2985
+		$current_page = $this->loader->getShared(CurrentPage::class);
2986
+		$current_page->setEspressoPage(true);
2987
+		$this->request->setRequestParam('uts', time());
2988
+		// what step are we on?
2989
+		$cart = EE_Registry::instance()->SSN->cart();
2990
+		$step = ! $cart instanceof EE_Cart ? 'ticket' : 'questions';
2991
+		// if doing ajax then we need to verify the nonce
2992
+		if ($this->request->isAjax()) {
2993
+			$nonce = $this->request->getRequestParam($this->_req_nonce, '');
2994
+			$this->_verify_nonce($nonce, $this->_req_nonce);
2995
+		}
2996
+		switch ($step) {
2997
+			case 'ticket':
2998
+				// process ticket selection
2999
+				$success = EED_Ticket_Selector::instance()->process_ticket_selections();
3000
+				if ($success) {
3001
+					EE_Error::add_success(
3002
+						esc_html__(
3003
+							'Tickets Selected. Now complete the registration.',
3004
+							'event_espresso'
3005
+						)
3006
+					);
3007
+				} else {
3008
+					$this->request->setRequestParam('step_error', true);
3009
+					$query_args['step_error'] = $this->request->getRequestParam('step_error', true, 'bool');
3010
+				}
3011
+				if ($this->request->isAjax()) {
3012
+					$this->new_registration(); // display next step
3013
+				} else {
3014
+					$query_args = [
3015
+						'action'                  => 'new_registration',
3016
+						'processing_registration' => 1,
3017
+						'event_id'                => $this->_reg_event->ID(),
3018
+						'uts'                     => time(),
3019
+					];
3020
+					$this->_redirect_after_action(
3021
+						false,
3022
+						'',
3023
+						'',
3024
+						$query_args,
3025
+						true
3026
+					);
3027
+				}
3028
+				break;
3029
+			case 'questions':
3030
+				if (! $this->request->requestParamIsSet('txn_reg_status_change[send_notifications]')) {
3031
+					add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_false', 15);
3032
+				}
3033
+				// process registration
3034
+				$transaction = EED_Single_Page_Checkout::instance()->process_registration_from_admin();
3035
+				if ($cart instanceof EE_Cart) {
3036
+					$grand_total = $cart->get_grand_total();
3037
+					if ($grand_total instanceof EE_Line_Item) {
3038
+						$grand_total->save_this_and_descendants_to_txn();
3039
+					}
3040
+				}
3041
+				if (! $transaction instanceof EE_Transaction) {
3042
+					$query_args = [
3043
+						'action'                  => 'new_registration',
3044
+						'processing_registration' => 2,
3045
+						'event_id'                => $this->_reg_event->ID(),
3046
+						'uts'                     => time(),
3047
+					];
3048
+					if ($this->request->isAjax()) {
3049
+						// display registration form again because there are errors (maybe validation?)
3050
+						$this->new_registration();
3051
+						return;
3052
+					}
3053
+					$this->_redirect_after_action(
3054
+						false,
3055
+						'',
3056
+						'',
3057
+						$query_args,
3058
+						true
3059
+					);
3060
+					return;
3061
+				}
3062
+				// maybe update status, and make sure to save transaction if not done already
3063
+				if (! $transaction->update_status_based_on_total_paid()) {
3064
+					$transaction->save();
3065
+				}
3066
+				EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
3067
+				$query_args = [
3068
+					'action'        => 'redirect_to_txn',
3069
+					'TXN_ID'        => $transaction->ID(),
3070
+					'EVT_ID'        => $this->_reg_event->ID(),
3071
+					'event_name'    => urlencode($this->_reg_event->name()),
3072
+					'redirect_from' => 'new_registration',
3073
+				];
3074
+				$this->_redirect_after_action(false, '', '', $query_args, true);
3075
+				break;
3076
+		}
3077
+		// what are you looking here for?  Should be nothing to do at this point.
3078
+	}
3079
+
3080
+
3081
+	/**
3082
+	 * redirect_to_txn
3083
+	 *
3084
+	 * @return void
3085
+	 * @throws EE_Error
3086
+	 * @throws InvalidArgumentException
3087
+	 * @throws InvalidDataTypeException
3088
+	 * @throws InvalidInterfaceException
3089
+	 * @throws ReflectionException
3090
+	 */
3091
+	public function redirect_to_txn()
3092
+	{
3093
+		EE_System::do_not_cache();
3094
+		EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
3095
+		$query_args = [
3096
+			'action' => 'view_transaction',
3097
+			'TXN_ID' => $this->request->getRequestParam('TXN_ID', 0, 'int'),
3098
+			'page'   => 'espresso_transactions',
3099
+		];
3100
+		if ($this->request->requestParamIsSet('EVT_ID') && $this->request->requestParamIsSet('redirect_from')) {
3101
+			$query_args['EVT_ID']        = $this->request->getRequestParam('EVT_ID', 0, 'int');
3102
+			$query_args['event_name']    = urlencode($this->request->getRequestParam('event_name'));
3103
+			$query_args['redirect_from'] = $this->request->getRequestParam('redirect_from');
3104
+		}
3105
+		EE_Error::add_success(
3106
+			esc_html__(
3107
+				'Registration Created.  Please review the transaction and add any payments as necessary',
3108
+				'event_espresso'
3109
+			)
3110
+		);
3111
+		$this->_redirect_after_action(false, '', '', $query_args, true);
3112
+	}
3113
+
3114
+
3115
+	/**
3116
+	 * generates HTML for the Attendee Contact List
3117
+	 *
3118
+	 * @return void
3119
+	 * @throws DomainException
3120
+	 * @throws EE_Error
3121
+	 */
3122
+	protected function _attendee_contact_list_table()
3123
+	{
3124
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3125
+		$this->_search_btn_label = esc_html__('Contacts', 'event_espresso');
3126
+		$this->display_admin_list_table_page_with_no_sidebar();
3127
+	}
3128
+
3129
+
3130
+	/**
3131
+	 * get_attendees
3132
+	 *
3133
+	 * @param      $per_page
3134
+	 * @param bool $count whether to return count or data.
3135
+	 * @param bool $trash
3136
+	 * @return array|int
3137
+	 * @throws EE_Error
3138
+	 * @throws InvalidArgumentException
3139
+	 * @throws InvalidDataTypeException
3140
+	 * @throws InvalidInterfaceException
3141
+	 */
3142
+	public function get_attendees($per_page, $count = false, $trash = false)
3143
+	{
3144
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3145
+		require_once(REG_ADMIN . 'EE_Attendee_Contact_List_Table.class.php');
3146
+		$orderby = $this->request->getRequestParam('orderby');
3147
+		switch ($orderby) {
3148
+			case 'ATT_ID':
3149
+			case 'ATT_fname':
3150
+			case 'ATT_email':
3151
+			case 'ATT_city':
3152
+			case 'STA_ID':
3153
+			case 'CNT_ID':
3154
+				break;
3155
+			case 'Registration_Count':
3156
+				$orderby = 'Registration_Count';
3157
+				break;
3158
+			default:
3159
+				$orderby = 'ATT_lname';
3160
+		}
3161
+		$sort         = $this->request->getRequestParam('order', 'ASC');
3162
+		$current_page = $this->request->getRequestParam('paged', 1, 'int');
3163
+		$per_page     = absint($per_page) ? $per_page : 10;
3164
+		$per_page     = $this->request->getRequestParam('perpage', $per_page, 'int');
3165
+		$_where       = [];
3166
+		$search_term  = $this->request->getRequestParam('s');
3167
+		if ($search_term) {
3168
+			$search_term  = '%' . $search_term . '%';
3169
+			$_where['OR'] = [
3170
+				'Registration.Event.EVT_name'       => ['LIKE', $search_term],
3171
+				'Registration.Event.EVT_desc'       => ['LIKE', $search_term],
3172
+				'Registration.Event.EVT_short_desc' => ['LIKE', $search_term],
3173
+				'ATT_fname'                         => ['LIKE', $search_term],
3174
+				'ATT_lname'                         => ['LIKE', $search_term],
3175
+				'ATT_short_bio'                     => ['LIKE', $search_term],
3176
+				'ATT_email'                         => ['LIKE', $search_term],
3177
+				'ATT_address'                       => ['LIKE', $search_term],
3178
+				'ATT_address2'                      => ['LIKE', $search_term],
3179
+				'ATT_city'                          => ['LIKE', $search_term],
3180
+				'Country.CNT_name'                  => ['LIKE', $search_term],
3181
+				'State.STA_name'                    => ['LIKE', $search_term],
3182
+				'ATT_phone'                         => ['LIKE', $search_term],
3183
+				'Registration.REG_final_price'      => ['LIKE', $search_term],
3184
+				'Registration.REG_code'             => ['LIKE', $search_term],
3185
+				'Registration.REG_group_size'       => ['LIKE', $search_term],
3186
+			];
3187
+		}
3188
+		$offset     = ($current_page - 1) * $per_page;
3189
+		$limit      = $count ? null : [$offset, $per_page];
3190
+		$query_args = [
3191
+			$_where,
3192
+			'extra_selects' => ['Registration_Count' => ['Registration.REG_ID', 'count', '%d']],
3193
+			'limit'         => $limit,
3194
+		];
3195
+		if (! $count) {
3196
+			$query_args['order_by'] = [$orderby => $sort];
3197
+		}
3198
+		$query_args[0]['status'] = $trash ? ['!=', 'publish'] : ['IN', ['publish']];
3199
+		return $count
3200
+			? $this->getAttendeeModel()->count($query_args, 'ATT_ID', true)
3201
+			: $this->getAttendeeModel()->get_all($query_args);
3202
+	}
3203
+
3204
+
3205
+	/**
3206
+	 * This is just taking care of resending the registration confirmation
3207
+	 *
3208
+	 * @return void
3209
+	 * @throws EE_Error
3210
+	 * @throws InvalidArgumentException
3211
+	 * @throws InvalidDataTypeException
3212
+	 * @throws InvalidInterfaceException
3213
+	 * @throws ReflectionException
3214
+	 */
3215
+	protected function _resend_registration()
3216
+	{
3217
+		$this->_process_resend_registration();
3218
+		$REG_ID      = $this->request->getRequestParam('_REG_ID', 0, 'int');
3219
+		$redirect_to = $this->request->getRequestParam('redirect_to');
3220
+		$query_args  = $redirect_to
3221
+			? ['action' => $redirect_to, '_REG_ID' => $REG_ID]
3222
+			: ['action' => 'default'];
3223
+		$this->_redirect_after_action(false, '', '', $query_args, true);
3224
+	}
3225
+
3226
+
3227
+	/**
3228
+	 * Creates a registration report, but accepts the name of a method to use for preparing the query parameters
3229
+	 * to use when selecting registrations
3230
+	 *
3231
+	 * @param string $method_name_for_getting_query_params the name of the method (on this class) to use for preparing
3232
+	 *                                                     the query parameters from the request
3233
+	 * @return void ends the request with a redirect or download
3234
+	 */
3235
+	public function _registrations_report_base($method_name_for_getting_query_params)
3236
+	{
3237
+		$EVT_ID = $this->request->requestParamIsSet('EVT_ID')
3238
+			? $this->request->getRequestParam('EVT_ID', 0, DataType::INT)
3239
+			: null;
3240
+		if (! defined('EE_USE_OLD_CSV_REPORT_CLASS')) {
3241
+			$return_url    = $this->request->getRequestParam('return_url', '', DataType::URL);
3242
+			$filters       = $this->request->getRequestParam('filters', [], DataType::STRING, true);
3243
+			$report_params = $this->$method_name_for_getting_query_params($filters);
3244
+			$use_filters   = $this->request->getRequestParam('use_filters', false, DataType::BOOL);
3245
+			wp_redirect(
3246
+				EE_Admin_Page::add_query_args_and_nonce(
3247
+					[
3248
+						'page'        => EED_Batch::PAGE_SLUG,
3249
+						'batch'       => EED_Batch::batch_file_job,
3250
+						'EVT_ID'      => $EVT_ID,
3251
+						'filters'     => urlencode(serialize($report_params)),
3252
+						'use_filters' => urlencode($use_filters),
3253
+						'job_handler' => urlencode('EventEspresso\core\libraries\batch\JobHandlers\RegistrationsReport'),
3254
+						'return_url'  => urlencode($return_url),
3255
+					]
3256
+				)
3257
+			);
3258
+		} else {
3259
+			// Pull the current request params
3260
+			$request_args = $this->request->requestParams();
3261
+			// Set the required request_args to be passed to the export
3262
+			$required_request_args = [
3263
+				'export' => 'report',
3264
+				'action' => 'registrations_report_for_event',
3265
+				'EVT_ID' => $EVT_ID,
3266
+			];
3267
+			// Merge required request args, overriding any currently set
3268
+			$request_args = array_merge($request_args, $required_request_args);
3269
+			if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3270
+				require_once(EE_CLASSES . 'EE_Export.class.php');
3271
+				$EE_Export = EE_Export::instance($request_args);
3272
+				$EE_Export->export();
3273
+			}
3274
+		}
3275
+	}
3276
+
3277
+
3278
+	/**
3279
+	 * Creates a registration report using only query parameters in the request
3280
+	 *
3281
+	 * @return void
3282
+	 */
3283
+	public function _registrations_report()
3284
+	{
3285
+		$this->_registrations_report_base('_get_registration_query_parameters');
3286
+	}
3287
+
3288
+
3289
+	public function _contact_list_export()
3290
+	{
3291
+		if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3292
+			require_once(EE_CLASSES . 'EE_Export.class.php');
3293
+			$EE_Export = EE_Export::instance($this->request->requestParams());
3294
+			$EE_Export->export_attendees();
3295
+		}
3296
+	}
3297
+
3298
+
3299
+	public function _contact_list_report()
3300
+	{
3301
+		if (! defined('EE_USE_OLD_CSV_REPORT_CLASS')) {
3302
+			wp_redirect(
3303
+				EE_Admin_Page::add_query_args_and_nonce(
3304
+					[
3305
+						'page'        => EED_Batch::PAGE_SLUG,
3306
+						'batch'       => EED_Batch::batch_file_job,
3307
+						'job_handler' => urlencode('EventEspresso\core\libraries\batch\JobHandlers\AttendeesReport'),
3308
+						'return_url'  => urlencode($this->request->getRequestParam('return_url', '', DataType::URL)),
3309
+					]
3310
+				)
3311
+			);
3312
+		} else {
3313
+			if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3314
+				require_once(EE_CLASSES . 'EE_Export.class.php');
3315
+				$EE_Export = EE_Export::instance($this->request->requestParams());
3316
+				$EE_Export->report_attendees();
3317
+			}
3318
+		}
3319
+	}
3320
+
3321
+
3322
+
3323
+
3324
+
3325
+	/***************************************        ATTENDEE DETAILS        ***************************************/
3326
+	/**
3327
+	 * This duplicates the attendee object for the given incoming registration id and attendee_id.
3328
+	 *
3329
+	 * @return void
3330
+	 * @throws EE_Error
3331
+	 * @throws InvalidArgumentException
3332
+	 * @throws InvalidDataTypeException
3333
+	 * @throws InvalidInterfaceException
3334
+	 * @throws ReflectionException
3335
+	 */
3336
+	protected function _duplicate_attendee()
3337
+	{
3338
+		$REG_ID = $this->request->getRequestParam('_REG_ID', 0, 'int');
3339
+		$action = $this->request->getRequestParam('return', 'default');
3340
+		// verify we have necessary info
3341
+		if (! $REG_ID) {
3342
+			EE_Error::add_error(
3343
+				esc_html__(
3344
+					'Unable to create the contact for the registration because the required parameters are not present (_REG_ID )',
3345
+					'event_espresso'
3346
+				),
3347
+				__FILE__,
3348
+				__LINE__,
3349
+				__FUNCTION__
3350
+			);
3351
+			$query_args = ['action' => $action];
3352
+			$this->_redirect_after_action('', '', '', $query_args, true);
3353
+		}
3354
+		// okay necessary deets present... let's dupe the incoming attendee and attach to incoming registration.
3355
+		$registration = $this->getRegistrationModel()->get_one_by_ID($REG_ID);
3356
+		if (! $registration instanceof EE_Registration) {
3357
+			throw new RuntimeException(
3358
+				sprintf(
3359
+					esc_html__(
3360
+						'Unable to create the contact because a valid registration could not be retrieved for REG ID: %1$d',
3361
+						'event_espresso'
3362
+					),
3363
+					$REG_ID
3364
+				)
3365
+			);
3366
+		}
3367
+		$attendee = $registration->attendee();
3368
+		// remove relation of existing attendee on registration
3369
+		$registration->_remove_relation_to($attendee, 'Attendee');
3370
+		// new attendee
3371
+		$new_attendee = clone $attendee;
3372
+		$new_attendee->set('ATT_ID', 0);
3373
+		$new_attendee->save();
3374
+		// add new attendee to reg
3375
+		$registration->_add_relation_to($new_attendee, 'Attendee');
3376
+		EE_Error::add_success(
3377
+			esc_html__(
3378
+				'New Contact record created.  Now make any edits you wish to make for this contact.',
3379
+				'event_espresso'
3380
+			)
3381
+		);
3382
+		// redirect to edit page for attendee
3383
+		$query_args = ['post' => $new_attendee->ID(), 'action' => 'edit_attendee'];
3384
+		$this->_redirect_after_action('', '', '', $query_args, true);
3385
+	}
3386
+
3387
+
3388
+	/**
3389
+	 * Callback invoked by parent EE_Admin_CPT class hooked in on `save_post` wp hook.
3390
+	 *
3391
+	 * @param int     $post_id
3392
+	 * @param WP_Post $post
3393
+	 * @throws DomainException
3394
+	 * @throws EE_Error
3395
+	 * @throws InvalidArgumentException
3396
+	 * @throws InvalidDataTypeException
3397
+	 * @throws InvalidInterfaceException
3398
+	 * @throws LogicException
3399
+	 * @throws InvalidFormSubmissionException
3400
+	 * @throws ReflectionException
3401
+	 */
3402
+	protected function _insert_update_cpt_item($post_id, $post)
3403
+	{
3404
+		$success  = true;
3405
+		$attendee = $post instanceof WP_Post && $post->post_type === 'espresso_attendees'
3406
+			? $this->getAttendeeModel()->get_one_by_ID($post_id)
3407
+			: null;
3408
+		// for attendee updates
3409
+		if ($attendee instanceof EE_Attendee) {
3410
+			// note we should only be UPDATING attendees at this point.
3411
+			$fname          = $this->request->getRequestParam('ATT_fname', '');
3412
+			$lname          = $this->request->getRequestParam('ATT_lname', '');
3413
+			$updated_fields = [
3414
+				'ATT_fname'     => $fname,
3415
+				'ATT_lname'     => $lname,
3416
+				'ATT_full_name' => "{$fname} {$lname}",
3417
+				'ATT_address'   => $this->request->getRequestParam('ATT_address', ''),
3418
+				'ATT_address2'  => $this->request->getRequestParam('ATT_address2', ''),
3419
+				'ATT_city'      => $this->request->getRequestParam('ATT_city', ''),
3420
+				'STA_ID'        => $this->request->getRequestParam('STA_ID', ''),
3421
+				'CNT_ISO'       => $this->request->getRequestParam('CNT_ISO', ''),
3422
+				'ATT_zip'       => $this->request->getRequestParam('ATT_zip', ''),
3423
+			];
3424
+			foreach ($updated_fields as $field => $value) {
3425
+				$attendee->set($field, $value);
3426
+			}
3427
+
3428
+			// process contact details metabox form handler (which will also save the attendee)
3429
+			$contact_details_form = $this->getAttendeeContactDetailsMetaboxFormHandler($attendee);
3430
+			$success              = $contact_details_form->process($this->request->requestParams());
3431
+
3432
+			$attendee_update_callbacks = apply_filters(
3433
+				'FHEE__Registrations_Admin_Page__insert_update_cpt_item__attendee_update',
3434
+				[]
3435
+			);
3436
+			foreach ($attendee_update_callbacks as $a_callback) {
3437
+				if (false === call_user_func_array($a_callback, [$attendee, $this->request->requestParams()])) {
3438
+					throw new EE_Error(
3439
+						sprintf(
3440
+							esc_html__(
3441
+								'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.',
3442
+								'event_espresso'
3443
+							),
3444
+							$a_callback
3445
+						)
3446
+					);
3447
+				}
3448
+			}
3449
+		}
3450
+
3451
+		if ($success === false) {
3452
+			EE_Error::add_error(
3453
+				esc_html__(
3454
+					'Something went wrong with updating the meta table data for the registration.',
3455
+					'event_espresso'
3456
+				),
3457
+				__FILE__,
3458
+				__FUNCTION__,
3459
+				__LINE__
3460
+			);
3461
+		}
3462
+	}
3463
+
3464
+
3465
+	public function trash_cpt_item($post_id)
3466
+	{
3467
+	}
3468
+
3469
+
3470
+	public function delete_cpt_item($post_id)
3471
+	{
3472
+	}
3473
+
3474
+
3475
+	public function restore_cpt_item($post_id)
3476
+	{
3477
+	}
3478
+
3479
+
3480
+	protected function _restore_cpt_item($post_id, $revision_id)
3481
+	{
3482
+	}
3483
+
3484
+
3485
+	/**
3486
+	 * @throws EE_Error
3487
+	 * @throws ReflectionException
3488
+	 * @since 4.10.2.p
3489
+	 */
3490
+	public function attendee_editor_metaboxes()
3491
+	{
3492
+		$this->verify_cpt_object();
3493
+		remove_meta_box(
3494
+			'postexcerpt',
3495
+			$this->_cpt_routes[ $this->_req_action ],
3496
+			'normal'
3497
+		);
3498
+		remove_meta_box('commentstatusdiv', $this->_cpt_routes[ $this->_req_action ], 'normal');
3499
+		if (post_type_supports('espresso_attendees', 'excerpt')) {
3500
+			$this->addMetaBox(
3501
+				'postexcerpt',
3502
+				esc_html__('Short Biography', 'event_espresso'),
3503
+				'post_excerpt_meta_box',
3504
+				$this->_cpt_routes[ $this->_req_action ]
3505
+			);
3506
+		}
3507
+		if (post_type_supports('espresso_attendees', 'comments')) {
3508
+			$this->addMetaBox(
3509
+				'commentsdiv',
3510
+				esc_html__('Notes on the Contact', 'event_espresso'),
3511
+				'post_comment_meta_box',
3512
+				$this->_cpt_routes[ $this->_req_action ],
3513
+				'normal',
3514
+				'core'
3515
+			);
3516
+		}
3517
+		$this->addMetaBox(
3518
+			'attendee_contact_info',
3519
+			esc_html__('Contact Info', 'event_espresso'),
3520
+			[$this, 'attendee_contact_info'],
3521
+			$this->_cpt_routes[ $this->_req_action ],
3522
+			'side',
3523
+			'core'
3524
+		);
3525
+		$this->addMetaBox(
3526
+			'attendee_details_address',
3527
+			esc_html__('Address Details', 'event_espresso'),
3528
+			[$this, 'attendee_address_details'],
3529
+			$this->_cpt_routes[ $this->_req_action ],
3530
+			'normal',
3531
+			'core'
3532
+		);
3533
+		$this->addMetaBox(
3534
+			'attendee_registrations',
3535
+			esc_html__('Registrations for this Contact', 'event_espresso'),
3536
+			[$this, 'attendee_registrations_meta_box'],
3537
+			$this->_cpt_routes[ $this->_req_action ]
3538
+		);
3539
+	}
3540
+
3541
+
3542
+	/**
3543
+	 * Metabox for attendee contact info
3544
+	 *
3545
+	 * @param WP_Post $post wp post object
3546
+	 * @return void attendee contact info ( and form )
3547
+	 * @throws EE_Error
3548
+	 * @throws InvalidArgumentException
3549
+	 * @throws InvalidDataTypeException
3550
+	 * @throws InvalidInterfaceException
3551
+	 * @throws LogicException
3552
+	 * @throws DomainException
3553
+	 */
3554
+	public function attendee_contact_info($post)
3555
+	{
3556
+		// get attendee object ( should already have it )
3557
+		$form = $this->getAttendeeContactDetailsMetaboxFormHandler($this->_cpt_model_obj);
3558
+		$form->enqueueStylesAndScripts();
3559
+		echo wp_kses($form->display(), AllowedTags::getWithFormTags());
3560
+	}
3561
+
3562
+
3563
+	/**
3564
+	 * Return form handler for the contact details metabox
3565
+	 *
3566
+	 * @param EE_Attendee $attendee
3567
+	 * @return AttendeeContactDetailsMetaboxFormHandler
3568
+	 * @throws DomainException
3569
+	 * @throws InvalidArgumentException
3570
+	 * @throws InvalidDataTypeException
3571
+	 * @throws InvalidInterfaceException
3572
+	 */
3573
+	protected function getAttendeeContactDetailsMetaboxFormHandler(EE_Attendee $attendee)
3574
+	{
3575
+		return new AttendeeContactDetailsMetaboxFormHandler($attendee, EE_Registry::instance());
3576
+	}
3577
+
3578
+
3579
+	/**
3580
+	 * Metabox for attendee details
3581
+	 *
3582
+	 * @param WP_Post $post wp post object
3583
+	 * @throws EE_Error
3584
+	 * @throws ReflectionException
3585
+	 */
3586
+	public function attendee_address_details($post)
3587
+	{
3588
+		// get attendee object (should already have it)
3589
+		$this->_template_args['attendee']     = $this->_cpt_model_obj;
3590
+		$this->_template_args['state_html']   = EEH_Form_Fields::generate_form_input(
3591
+			new EE_Question_Form_Input(
3592
+				EE_Question::new_instance(
3593
+					[
3594
+						'QST_ID'           => 0,
3595
+						'QST_display_text' => esc_html__('State/Province', 'event_espresso'),
3596
+						'QST_system'       => 'admin-state',
3597
+					]
3598
+				),
3599
+				EE_Answer::new_instance(
3600
+					[
3601
+						'ANS_ID'    => 0,
3602
+						'ANS_value' => $this->_cpt_model_obj->state_ID(),
3603
+					]
3604
+				),
3605
+				[
3606
+					'input_id'       => 'STA_ID',
3607
+					'input_name'     => 'STA_ID',
3608
+					'input_prefix'   => '',
3609
+					'append_qstn_id' => false,
3610
+				]
3611
+			)
3612
+		);
3613
+		$this->_template_args['country_html'] = EEH_Form_Fields::generate_form_input(
3614
+			new EE_Question_Form_Input(
3615
+				EE_Question::new_instance(
3616
+					[
3617
+						'QST_ID'           => 0,
3618
+						'QST_display_text' => esc_html__('Country', 'event_espresso'),
3619
+						'QST_system'       => 'admin-country',
3620
+					]
3621
+				),
3622
+				EE_Answer::new_instance(
3623
+					[
3624
+						'ANS_ID'    => 0,
3625
+						'ANS_value' => $this->_cpt_model_obj->country_ID(),
3626
+					]
3627
+				),
3628
+				[
3629
+					'input_id'       => 'CNT_ISO',
3630
+					'input_name'     => 'CNT_ISO',
3631
+					'input_prefix'   => '',
3632
+					'append_qstn_id' => false,
3633
+				]
3634
+			)
3635
+		);
3636
+		$template                             =
3637
+			REG_TEMPLATE_PATH . 'attendee_address_details_metabox_content.template.php';
3638
+		EEH_Template::display_template($template, $this->_template_args);
3639
+	}
3640
+
3641
+
3642
+	/**
3643
+	 * _attendee_details
3644
+	 *
3645
+	 * @param $post
3646
+	 * @return void
3647
+	 * @throws DomainException
3648
+	 * @throws EE_Error
3649
+	 * @throws InvalidArgumentException
3650
+	 * @throws InvalidDataTypeException
3651
+	 * @throws InvalidInterfaceException
3652
+	 * @throws ReflectionException
3653
+	 */
3654
+	public function attendee_registrations_meta_box($post)
3655
+	{
3656
+		$this->_template_args['attendee']      = $this->_cpt_model_obj;
3657
+		$this->_template_args['registrations'] = $this->_cpt_model_obj->get_many_related('Registration');
3658
+		$template                              =
3659
+			REG_TEMPLATE_PATH . 'attendee_registrations_main_meta_box.template.php';
3660
+		EEH_Template::display_template($template, $this->_template_args);
3661
+	}
3662
+
3663
+
3664
+	/**
3665
+	 * add in the form fields for the attendee edit
3666
+	 *
3667
+	 * @param WP_Post $post wp post object
3668
+	 * @return void echos html for new form.
3669
+	 * @throws DomainException
3670
+	 */
3671
+	public function after_title_form_fields($post)
3672
+	{
3673
+		if ($post->post_type === 'espresso_attendees') {
3674
+			$template                  = REG_TEMPLATE_PATH . 'attendee_details_after_title_form_fields.template.php';
3675
+			$template_args['attendee'] = $this->_cpt_model_obj;
3676
+			EEH_Template::display_template($template, $template_args);
3677
+		}
3678
+	}
3679
+
3680
+
3681
+	/**
3682
+	 * _trash_or_restore_attendee
3683
+	 *
3684
+	 * @param boolean $trash - whether to move item to trash (TRUE) or restore it (FALSE)
3685
+	 * @return void
3686
+	 * @throws EE_Error
3687
+	 * @throws InvalidArgumentException
3688
+	 * @throws InvalidDataTypeException
3689
+	 * @throws InvalidInterfaceException
3690
+	 */
3691
+	protected function _trash_or_restore_attendees($trash = true)
3692
+	{
3693
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3694
+		$status = $trash ? 'trash' : 'publish';
3695
+		// Checkboxes
3696
+		if ($this->request->requestParamIsSet('checkbox')) {
3697
+			$ATT_IDs = $this->request->getRequestParam('checkbox', [], 'int', true);
3698
+			// if array has more than one element than success message should be plural
3699
+			$success = count($ATT_IDs) > 1 ? 2 : 1;
3700
+			// cycle thru checkboxes
3701
+			foreach ($ATT_IDs as $ATT_ID) {
3702
+				$updated = $this->getAttendeeModel()->update_by_ID(['status' => $status], $ATT_ID);
3703
+				if (! $updated) {
3704
+					$success = 0;
3705
+				}
3706
+			}
3707
+		} else {
3708
+			// grab single id and delete
3709
+			$ATT_ID = $this->request->getRequestParam('ATT_ID', 0, 'int');
3710
+			// update attendee
3711
+			$success = $this->getAttendeeModel()->update_by_ID(['status' => $status], $ATT_ID) ? 1 : 0;
3712
+		}
3713
+		$what        = $success > 1
3714
+			? esc_html__('Contacts', 'event_espresso')
3715
+			: esc_html__('Contact', 'event_espresso');
3716
+		$action_desc = $trash
3717
+			? esc_html__('moved to the trash', 'event_espresso')
3718
+			: esc_html__('restored', 'event_espresso');
3719
+		$this->_redirect_after_action($success, $what, $action_desc, ['action' => 'contact_list']);
3720
+	}
3721 3721
 }
Please login to merge, or discard this patch.
admin_pages/maintenance/Maintenance_Admin_Page.core.php 1 patch
Indentation   +955 added lines, -955 removed lines patch added patch discarded remove patch
@@ -14,959 +14,959 @@
 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
-        $this->capabilities->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                               =
527
-            EE_MAINTENANCE_TEMPLATE_PATH . 'ee_system_stati_page.template.php';
528
-        $this->_template_args['system_stati']               = EEM_System_Status::instance()->get_system_stati();
529
-        $this->_template_args['download_system_status_url'] = EE_Admin_Page::add_query_args_and_nonce(
530
-            [
531
-                'action' => 'download_system_status',
532
-            ],
533
-            EE_MAINTENANCE_ADMIN_URL
534
-        );
535
-        $this->_template_args['admin_page_content']         = EEH_Template::display_template(
536
-            $this->_template_path,
537
-            $this->_template_args,
538
-            true
539
-        );
540
-        $this->display_admin_page_with_no_sidebar();
541
-    }
542
-
543
-
544
-    /**
545
-     * Downloads an HTML file of the system status that can be easily stored or emailed
546
-     */
547
-    public function _download_system_status()
548
-    {
549
-        $status_info = EEM_System_Status::instance()->get_system_stati();
550
-        header('Content-Disposition: attachment');
551
-        header("Content-Disposition: attachment; filename=system_status_" . sanitize_key(site_url()) . ".html");
552
-        $output = '<style>table{border:1px solid darkgrey;}td{vertical-align:top}</style>';
553
-        $output .= '<h1>' . sprintf(
554
-                __('System Information for %1$s', 'event_espresso'),
555
-                esc_url_raw(site_url())
556
-            ) . '</h1>';
557
-        $output .= EEH_Template::layout_array_as_table($status_info);
558
-        echo esc_html($output);
559
-        die;
560
-    }
561
-
562
-
563
-    /**
564
-     * @throws EE_Error
565
-     */
566
-    public function _send_migration_crash_report()
567
-    {
568
-        $from      = $this->_req_data['from'];
569
-        $from_name = $this->_req_data['from_name'];
570
-        $body      = $this->_req_data['body'];
571
-        try {
572
-            $success = wp_mail(
573
-                EE_SUPPORT_EMAIL,
574
-                'Migration Crash Report',
575
-                $body . "/r/n<br>" . print_r(EEM_System_Status::instance()->get_system_stati(), true),
576
-                [
577
-                    "from:$from_name<$from>",
578
-                ]
579
-            );
580
-        } catch (Exception $e) {
581
-            $success = false;
582
-        }
583
-        $this->_redirect_after_action(
584
-            $success,
585
-            esc_html__("Migration Crash Report", "event_espresso"),
586
-            esc_html__("sent", "event_espresso"),
587
-            ['success' => $success, 'action' => 'confirm_migration_crash_report_sent']
588
-        );
589
-    }
590
-
591
-
592
-    /**
593
-     * @throws EE_Error
594
-     */
595
-    public function _confirm_migration_crash_report_sent()
596
-    {
597
-        try {
598
-            $most_recent_migration = $this->migration_manager->get_last_ran_script(true);
599
-        } catch (EE_Error $e) {
600
-            $this->migration_manager->add_error_to_migrations_ran($e->getMessage());
601
-            // now, just so we can display the page correctly, make an error migration script stage object
602
-            // and also put the error on it. It only persists for the duration of this request
603
-            $most_recent_migration = new EE_DMS_Unknown_1_0_0();
604
-            $most_recent_migration->add_error($e->getMessage());
605
-        }
606
-        $success                                       = $this->_req_data['success'] === '1';
607
-        $this->_template_args['success']               = $success;
608
-        $this->_template_args['most_recent_migration'] = $most_recent_migration;
609
-        $this->_template_args['reset_db_action_url']   = EE_Admin_Page::add_query_args_and_nonce(
610
-            ['action' => 'reset_db'],
611
-            EE_MAINTENANCE_ADMIN_URL
612
-        );
613
-        $this->_template_args['reset_db_page_url']     = EE_Admin_Page::add_query_args_and_nonce(
614
-            ['action' => 'data_reset'],
615
-            EE_MAINTENANCE_ADMIN_URL
616
-        );
617
-        $this->_template_args['reattempt_action_url']  = EE_Admin_Page::add_query_args_and_nonce(
618
-            ['action' => 'reattempt_migration'],
619
-            EE_MAINTENANCE_ADMIN_URL
620
-        );
621
-        $this->_template_path                          =
622
-            EE_MAINTENANCE_TEMPLATE_PATH . 'ee_confirm_migration_crash_report_sent.template.php';
623
-        $this->_template_args['admin_page_content']    = EEH_Template::display_template(
624
-            $this->_template_path,
625
-            $this->_template_args,
626
-            true
627
-        );
628
-        $this->display_admin_page_with_sidebar();
629
-    }
630
-
631
-
632
-    /**
633
-     * Resets the entire EE4 database.
634
-     * only sets up ee4 database for a fresh install-
635
-     * doesn't actually clean out the old wp options, or cpts
636
-     * (although it does erase old ee table data)
637
-     *
638
-     * @param boolean $nuke_old_ee4_data controls whether we destroy the old ee4 data,
639
-     *                                   or just try initializing ee4 default data
640
-     * @throws EE_Error
641
-     * @throws ReflectionException
642
-     */
643
-    public function _reset_db($nuke_old_ee4_data = true)
644
-    {
645
-        $this->maintenance_mode->set_maintenance_level(EE_Maintenance_Mode::level_0_not_in_maintenance);
646
-        if ($nuke_old_ee4_data) {
647
-            EEH_Activation::delete_all_espresso_cpt_data();
648
-            EEH_Activation::delete_all_espresso_tables_and_data(false);
649
-            EEH_Activation::remove_cron_tasks();
650
-        }
651
-        // make sure when we reset the registry's config that it
652
-        // switches to using the new singleton
653
-        EE_Registry::instance()->CFG = EE_Registry::instance()->CFG->reset(true);
654
-        EE_System::instance()->initialize_db_if_no_migrations_required(true);
655
-        EE_System::instance()->redirect_to_about_ee();
656
-    }
657
-
658
-
659
-    /**
660
-     * Deletes ALL EE tables, Records, and Options from the database.
661
-     *
662
-     * @throws EE_Error
663
-     * @throws ReflectionException
664
-     */
665
-    public function _delete_db()
666
-    {
667
-        $this->maintenance_mode->set_maintenance_level(EE_Maintenance_Mode::level_0_not_in_maintenance);
668
-        EEH_Activation::delete_all_espresso_cpt_data();
669
-        EEH_Activation::delete_all_espresso_tables_and_data();
670
-        EEH_Activation::remove_cron_tasks();
671
-        EEH_Activation::deactivate_event_espresso();
672
-        wp_safe_redirect(admin_url('plugins.php'));
673
-        exit;
674
-    }
675
-
676
-
677
-    /**
678
-     * sets up EE4 to rerun the migrations from ee3 to ee4
679
-     *
680
-     * @throws EE_Error
681
-     * @throws ReflectionException
682
-     */
683
-    public function _rerun_migration_from_ee3()
684
-    {
685
-        $this->maintenance_mode->set_maintenance_level(EE_Maintenance_Mode::level_0_not_in_maintenance);
686
-        EEH_Activation::delete_all_espresso_cpt_data();
687
-        EEH_Activation::delete_all_espresso_tables_and_data(false);
688
-        // set the db state to something that will require migrations
689
-        update_option(EE_Data_Migration_Manager::current_database_state, '3.1.36.0');
690
-        $this->maintenance_mode->set_maintenance_level(EE_Maintenance_Mode::level_2_complete_maintenance);
691
-        $this->_redirect_after_action(
692
-            true,
693
-            esc_html__("Database", 'event_espresso'),
694
-            esc_html__("reset", 'event_espresso')
695
-        );
696
-    }
697
-
698
-
699
-    // none of the below group are currently used for Gateway Settings
700
-    protected function _add_screen_options()
701
-    {
702
-    }
703
-
704
-
705
-    protected function _add_feature_pointers()
706
-    {
707
-    }
708
-
709
-
710
-    public function admin_init()
711
-    {
712
-    }
713
-
714
-
715
-    public function admin_notices()
716
-    {
717
-    }
718
-
719
-
720
-    public function admin_footer_scripts()
721
-    {
722
-    }
723
-
724
-
725
-    public function load_scripts_styles()
726
-    {
727
-        wp_enqueue_script('ee_admin_js');
728
-        wp_enqueue_script(
729
-            'ee-maintenance',
730
-            EE_MAINTENANCE_ASSETS_URL . 'ee-maintenance.js',
731
-            ['jquery'],
732
-            EVENT_ESPRESSO_VERSION,
733
-            true
734
-        );
735
-        wp_register_style(
736
-            'espresso_maintenance',
737
-            EE_MAINTENANCE_ASSETS_URL . 'ee-maintenance.css',
738
-            [],
739
-            EVENT_ESPRESSO_VERSION
740
-        );
741
-        wp_enqueue_style('espresso_maintenance');
742
-        // localize script stuff
743
-        wp_localize_script(
744
-            'ee-maintenance',
745
-            'ee_maintenance',
746
-            [
747
-                'migrating'                        => wp_strip_all_tags(__("Updating Database...", "event_espresso")),
748
-                'next'                             => wp_strip_all_tags(__("Next", "event_espresso")),
749
-                'fatal_error'                      => wp_strip_all_tags(
750
-                    __(
751
-                        "A Fatal Error Has Occurred",
752
-                        "event_espresso"
753
-                    )
754
-                ),
755
-                'click_next_when_ready'            => wp_strip_all_tags(
756
-                    __(
757
-                        "The current Database Update has ended. Click 'next' when ready to proceed",
758
-                        "event_espresso"
759
-                    )
760
-                ),
761
-                'status_no_more_migration_scripts' => EE_Data_Migration_Manager::status_no_more_migration_scripts,
762
-                'status_fatal_error'               => EE_Data_Migration_Manager::status_fatal_error,
763
-                'status_completed'                 => EE_Data_Migration_Manager::status_completed,
764
-                'confirm'                          => wp_strip_all_tags(
765
-                    __(
766
-                        'Are you sure you want to do this? It CANNOT be undone!',
767
-                        'event_espresso'
768
-                    )
769
-                ),
770
-                'confirm_skip_migration'           => wp_strip_all_tags(
771
-                    __(
772
-                        'You have chosen to NOT migrate your existing data. Are you sure you want to continue?',
773
-                        'event_espresso'
774
-                    )
775
-                ),
776
-            ]
777
-        );
778
-    }
779
-
780
-
781
-    public function load_scripts_styles_default()
782
-    {
783
-    }
784
-
785
-
786
-    /**
787
-     * Enqueue scripts and styles for the datetime tools page.
788
-     */
789
-    public function load_scripts_styles_datetime_tools()
790
-    {
791
-        EE_Datepicker_Input::enqueue_styles_and_scripts();
792
-    }
793
-
794
-
795
-    /**
796
-     * @throws EE_Error
797
-     */
798
-    protected function _datetime_tools()
799
-    {
800
-        $form_action                                = EE_Admin_Page::add_query_args_and_nonce(
801
-            [
802
-                'action'        => 'run_datetime_offset_fix',
803
-                'return_action' => $this->_req_action,
804
-            ],
805
-            EE_MAINTENANCE_ADMIN_URL
806
-        );
807
-        $form                                       = $this->_get_datetime_offset_fix_form();
808
-        $this->_admin_page_title                    = esc_html__('Datetime Utilities', 'event_espresso');
809
-        $this->_template_args['admin_page_content'] = $form->form_open($form_action, 'post')
810
-                                                      . $form->get_html_and_js()
811
-                                                      . $form->form_close();
812
-        $this->display_admin_page_with_sidebar();
813
-    }
814
-
815
-
816
-    /**
817
-     * @throws EE_Error
818
-     */
819
-    protected function _get_datetime_offset_fix_form()
820
-    {
821
-        if (! $this->datetime_fix_offset_form instanceof EE_Form_Section_Proper) {
822
-            $this->datetime_fix_offset_form = new EE_Form_Section_Proper(
823
-                [
824
-                    'name'            => 'datetime_offset_fix_option',
825
-                    'layout_strategy' => new EE_Admin_Two_Column_Layout(),
826
-                    'subsections'     => [
827
-                        'title'                  => new EE_Form_Section_HTML(
828
-                            EEH_HTML::h2(
829
-                                esc_html__('Datetime Offset Tool', 'event_espresso')
830
-                            )
831
-                        ),
832
-                        'explanation'            => new EE_Form_Section_HTML(
833
-                            EEH_HTML::p(
834
-                                esc_html__(
835
-                                    'Use this tool to automatically apply the provided offset to all Event Espresso records in your database that involve dates and times.',
836
-                                    'event_espresso'
837
-                                )
838
-                            )
839
-                            . EEH_HTML::p(
840
-                                esc_html__(
841
-                                    '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.',
842
-                                    'event_espresso'
843
-                                )
844
-                            )
845
-                        ),
846
-                        'offset_input'           => new EE_Float_Input(
847
-                            [
848
-                                'html_name'       => 'offset_for_datetimes',
849
-                                'html_label_text' => esc_html__(
850
-                                    'Offset to apply (in hours):',
851
-                                    'event_espresso'
852
-                                ),
853
-                                'min_value'       => '-12',
854
-                                'max_value'       => '14',
855
-                                'step_value'      => '.25',
856
-                                'default'         => DatetimeOffsetFix::getOffset(),
857
-                            ]
858
-                        ),
859
-                        'date_range_explanation' => new EE_Form_Section_HTML(
860
-                            EEH_HTML::p(
861
-                                esc_html__(
862
-                                    '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.',
863
-                                    'event_espresso'
864
-                                )
865
-                            )
866
-                            . EEH_HTML::p(
867
-                                EEH_HTML::strong(
868
-                                    sprintf(
869
-                                        esc_html__(
870
-                                            'Note: please enter the dates in UTC (You can use %1$sthis online tool%2$s to assist with conversions).',
871
-                                            'event_espresso'
872
-                                        ),
873
-                                        '<a href="https://www.timeanddate.com/worldclock/converter.html">',
874
-                                        '</a>'
875
-                                    )
876
-                                )
877
-                            )
878
-                        ),
879
-                        'date_range_start_date'  => new EE_Datepicker_Input(
880
-                            [
881
-                                'html_name'       => 'offset_date_start_range',
882
-                                'html_label_text' => esc_html__(
883
-                                    'Start Date for dates the offset applied to:',
884
-                                    'event_espresso'
885
-                                ),
886
-                            ]
887
-                        ),
888
-                        'date_range_end_date'    => new EE_Datepicker_Input(
889
-                            [
890
-                                'html_name'       => 'offset_date_end_range',
891
-                                'html_label_text' => esc_html__(
892
-                                    'End Date for dates the offset is applied to:',
893
-                                    'event_espresso'
894
-                                ),
895
-                            ]
896
-                        ),
897
-                        'submit'                 => new EE_Submit_Input(
898
-                            [
899
-                                'html_label_text' => '',
900
-                                'default'         => esc_html__('Apply Offset', 'event_espresso'),
901
-                            ]
902
-                        ),
903
-                    ],
904
-                ]
905
-            );
906
-        }
907
-        return $this->datetime_fix_offset_form;
908
-    }
909
-
910
-
911
-    /**
912
-     * Callback for the run_datetime_offset_fix route.
913
-     *
914
-     * @throws EE_Error
915
-     */
916
-    protected function _apply_datetime_offset()
917
-    {
918
-        if ($_SERVER['REQUEST_METHOD'] === 'POST') {
919
-            $form = $this->_get_datetime_offset_fix_form();
920
-            $form->receive_form_submission($this->_req_data);
921
-            if ($form->is_valid()) {
922
-                // save offset data so batch processor can get it.
923
-                DatetimeOffsetFix::updateOffset((float) $form->get_input_value('offset_input'));
924
-                $utc_timezone          = new DateTimeZone('UTC');
925
-                $date_range_start_date = DateTime::createFromFormat(
926
-                    'm/d/Y H:i:s',
927
-                    $form->get_input_value('date_range_start_date') . ' 00:00:00',
928
-                    $utc_timezone
929
-                );
930
-                $date_range_end_date   = DateTime::createFromFormat(
931
-                    'm/d/Y H:i:s',
932
-                    $form->get_input_value('date_range_end_date') . ' 23:59:59',
933
-                    $utc_timezone
934
-                );
935
-                if ($date_range_start_date instanceof DateTime) {
936
-                    DatetimeOffsetFix::updateStartDateRange(DbSafeDateTime::createFromDateTime($date_range_start_date));
937
-                }
938
-                if ($date_range_end_date instanceof DateTime) {
939
-                    DatetimeOffsetFix::updateEndDateRange(DbSafeDateTime::createFromDateTime($date_range_end_date));
940
-                }
941
-                // redirect to batch tool
942
-                wp_redirect(
943
-                    EE_Admin_Page::add_query_args_and_nonce(
944
-                        [
945
-                            'page'        => EED_Batch::PAGE_SLUG,
946
-                            'batch'       => EED_Batch::batch_job,
947
-                            'label'       => esc_html__('Applying Offset', 'event_espresso'),
948
-                            'job_handler' => urlencode('EventEspresso\core\libraries\batch\JobHandlers\DatetimeOffsetFix'),
949
-                            'return_url'  => urlencode(
950
-                                add_query_arg(
951
-                                    [
952
-                                        'action' => 'datetime_tools',
953
-                                    ],
954
-                                    EEH_URL::current_url_without_query_paramaters(
955
-                                        [
956
-                                            'return_action',
957
-                                            'run_datetime_offset_fix_nonce',
958
-                                            'return',
959
-                                            'datetime_tools_nonce',
960
-                                        ]
961
-                                    )
962
-                                )
963
-                            ),
964
-                        ],
965
-                        admin_url()
966
-                    )
967
-                );
968
-                exit;
969
-            }
970
-        }
971
-    }
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
+		$this->capabilities->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                               =
527
+			EE_MAINTENANCE_TEMPLATE_PATH . 'ee_system_stati_page.template.php';
528
+		$this->_template_args['system_stati']               = EEM_System_Status::instance()->get_system_stati();
529
+		$this->_template_args['download_system_status_url'] = EE_Admin_Page::add_query_args_and_nonce(
530
+			[
531
+				'action' => 'download_system_status',
532
+			],
533
+			EE_MAINTENANCE_ADMIN_URL
534
+		);
535
+		$this->_template_args['admin_page_content']         = EEH_Template::display_template(
536
+			$this->_template_path,
537
+			$this->_template_args,
538
+			true
539
+		);
540
+		$this->display_admin_page_with_no_sidebar();
541
+	}
542
+
543
+
544
+	/**
545
+	 * Downloads an HTML file of the system status that can be easily stored or emailed
546
+	 */
547
+	public function _download_system_status()
548
+	{
549
+		$status_info = EEM_System_Status::instance()->get_system_stati();
550
+		header('Content-Disposition: attachment');
551
+		header("Content-Disposition: attachment; filename=system_status_" . sanitize_key(site_url()) . ".html");
552
+		$output = '<style>table{border:1px solid darkgrey;}td{vertical-align:top}</style>';
553
+		$output .= '<h1>' . sprintf(
554
+				__('System Information for %1$s', 'event_espresso'),
555
+				esc_url_raw(site_url())
556
+			) . '</h1>';
557
+		$output .= EEH_Template::layout_array_as_table($status_info);
558
+		echo esc_html($output);
559
+		die;
560
+	}
561
+
562
+
563
+	/**
564
+	 * @throws EE_Error
565
+	 */
566
+	public function _send_migration_crash_report()
567
+	{
568
+		$from      = $this->_req_data['from'];
569
+		$from_name = $this->_req_data['from_name'];
570
+		$body      = $this->_req_data['body'];
571
+		try {
572
+			$success = wp_mail(
573
+				EE_SUPPORT_EMAIL,
574
+				'Migration Crash Report',
575
+				$body . "/r/n<br>" . print_r(EEM_System_Status::instance()->get_system_stati(), true),
576
+				[
577
+					"from:$from_name<$from>",
578
+				]
579
+			);
580
+		} catch (Exception $e) {
581
+			$success = false;
582
+		}
583
+		$this->_redirect_after_action(
584
+			$success,
585
+			esc_html__("Migration Crash Report", "event_espresso"),
586
+			esc_html__("sent", "event_espresso"),
587
+			['success' => $success, 'action' => 'confirm_migration_crash_report_sent']
588
+		);
589
+	}
590
+
591
+
592
+	/**
593
+	 * @throws EE_Error
594
+	 */
595
+	public function _confirm_migration_crash_report_sent()
596
+	{
597
+		try {
598
+			$most_recent_migration = $this->migration_manager->get_last_ran_script(true);
599
+		} catch (EE_Error $e) {
600
+			$this->migration_manager->add_error_to_migrations_ran($e->getMessage());
601
+			// now, just so we can display the page correctly, make an error migration script stage object
602
+			// and also put the error on it. It only persists for the duration of this request
603
+			$most_recent_migration = new EE_DMS_Unknown_1_0_0();
604
+			$most_recent_migration->add_error($e->getMessage());
605
+		}
606
+		$success                                       = $this->_req_data['success'] === '1';
607
+		$this->_template_args['success']               = $success;
608
+		$this->_template_args['most_recent_migration'] = $most_recent_migration;
609
+		$this->_template_args['reset_db_action_url']   = EE_Admin_Page::add_query_args_and_nonce(
610
+			['action' => 'reset_db'],
611
+			EE_MAINTENANCE_ADMIN_URL
612
+		);
613
+		$this->_template_args['reset_db_page_url']     = EE_Admin_Page::add_query_args_and_nonce(
614
+			['action' => 'data_reset'],
615
+			EE_MAINTENANCE_ADMIN_URL
616
+		);
617
+		$this->_template_args['reattempt_action_url']  = EE_Admin_Page::add_query_args_and_nonce(
618
+			['action' => 'reattempt_migration'],
619
+			EE_MAINTENANCE_ADMIN_URL
620
+		);
621
+		$this->_template_path                          =
622
+			EE_MAINTENANCE_TEMPLATE_PATH . 'ee_confirm_migration_crash_report_sent.template.php';
623
+		$this->_template_args['admin_page_content']    = EEH_Template::display_template(
624
+			$this->_template_path,
625
+			$this->_template_args,
626
+			true
627
+		);
628
+		$this->display_admin_page_with_sidebar();
629
+	}
630
+
631
+
632
+	/**
633
+	 * Resets the entire EE4 database.
634
+	 * only sets up ee4 database for a fresh install-
635
+	 * doesn't actually clean out the old wp options, or cpts
636
+	 * (although it does erase old ee table data)
637
+	 *
638
+	 * @param boolean $nuke_old_ee4_data controls whether we destroy the old ee4 data,
639
+	 *                                   or just try initializing ee4 default data
640
+	 * @throws EE_Error
641
+	 * @throws ReflectionException
642
+	 */
643
+	public function _reset_db($nuke_old_ee4_data = true)
644
+	{
645
+		$this->maintenance_mode->set_maintenance_level(EE_Maintenance_Mode::level_0_not_in_maintenance);
646
+		if ($nuke_old_ee4_data) {
647
+			EEH_Activation::delete_all_espresso_cpt_data();
648
+			EEH_Activation::delete_all_espresso_tables_and_data(false);
649
+			EEH_Activation::remove_cron_tasks();
650
+		}
651
+		// make sure when we reset the registry's config that it
652
+		// switches to using the new singleton
653
+		EE_Registry::instance()->CFG = EE_Registry::instance()->CFG->reset(true);
654
+		EE_System::instance()->initialize_db_if_no_migrations_required(true);
655
+		EE_System::instance()->redirect_to_about_ee();
656
+	}
657
+
658
+
659
+	/**
660
+	 * Deletes ALL EE tables, Records, and Options from the database.
661
+	 *
662
+	 * @throws EE_Error
663
+	 * @throws ReflectionException
664
+	 */
665
+	public function _delete_db()
666
+	{
667
+		$this->maintenance_mode->set_maintenance_level(EE_Maintenance_Mode::level_0_not_in_maintenance);
668
+		EEH_Activation::delete_all_espresso_cpt_data();
669
+		EEH_Activation::delete_all_espresso_tables_and_data();
670
+		EEH_Activation::remove_cron_tasks();
671
+		EEH_Activation::deactivate_event_espresso();
672
+		wp_safe_redirect(admin_url('plugins.php'));
673
+		exit;
674
+	}
675
+
676
+
677
+	/**
678
+	 * sets up EE4 to rerun the migrations from ee3 to ee4
679
+	 *
680
+	 * @throws EE_Error
681
+	 * @throws ReflectionException
682
+	 */
683
+	public function _rerun_migration_from_ee3()
684
+	{
685
+		$this->maintenance_mode->set_maintenance_level(EE_Maintenance_Mode::level_0_not_in_maintenance);
686
+		EEH_Activation::delete_all_espresso_cpt_data();
687
+		EEH_Activation::delete_all_espresso_tables_and_data(false);
688
+		// set the db state to something that will require migrations
689
+		update_option(EE_Data_Migration_Manager::current_database_state, '3.1.36.0');
690
+		$this->maintenance_mode->set_maintenance_level(EE_Maintenance_Mode::level_2_complete_maintenance);
691
+		$this->_redirect_after_action(
692
+			true,
693
+			esc_html__("Database", 'event_espresso'),
694
+			esc_html__("reset", 'event_espresso')
695
+		);
696
+	}
697
+
698
+
699
+	// none of the below group are currently used for Gateway Settings
700
+	protected function _add_screen_options()
701
+	{
702
+	}
703
+
704
+
705
+	protected function _add_feature_pointers()
706
+	{
707
+	}
708
+
709
+
710
+	public function admin_init()
711
+	{
712
+	}
713
+
714
+
715
+	public function admin_notices()
716
+	{
717
+	}
718
+
719
+
720
+	public function admin_footer_scripts()
721
+	{
722
+	}
723
+
724
+
725
+	public function load_scripts_styles()
726
+	{
727
+		wp_enqueue_script('ee_admin_js');
728
+		wp_enqueue_script(
729
+			'ee-maintenance',
730
+			EE_MAINTENANCE_ASSETS_URL . 'ee-maintenance.js',
731
+			['jquery'],
732
+			EVENT_ESPRESSO_VERSION,
733
+			true
734
+		);
735
+		wp_register_style(
736
+			'espresso_maintenance',
737
+			EE_MAINTENANCE_ASSETS_URL . 'ee-maintenance.css',
738
+			[],
739
+			EVENT_ESPRESSO_VERSION
740
+		);
741
+		wp_enqueue_style('espresso_maintenance');
742
+		// localize script stuff
743
+		wp_localize_script(
744
+			'ee-maintenance',
745
+			'ee_maintenance',
746
+			[
747
+				'migrating'                        => wp_strip_all_tags(__("Updating Database...", "event_espresso")),
748
+				'next'                             => wp_strip_all_tags(__("Next", "event_espresso")),
749
+				'fatal_error'                      => wp_strip_all_tags(
750
+					__(
751
+						"A Fatal Error Has Occurred",
752
+						"event_espresso"
753
+					)
754
+				),
755
+				'click_next_when_ready'            => wp_strip_all_tags(
756
+					__(
757
+						"The current Database Update has ended. Click 'next' when ready to proceed",
758
+						"event_espresso"
759
+					)
760
+				),
761
+				'status_no_more_migration_scripts' => EE_Data_Migration_Manager::status_no_more_migration_scripts,
762
+				'status_fatal_error'               => EE_Data_Migration_Manager::status_fatal_error,
763
+				'status_completed'                 => EE_Data_Migration_Manager::status_completed,
764
+				'confirm'                          => wp_strip_all_tags(
765
+					__(
766
+						'Are you sure you want to do this? It CANNOT be undone!',
767
+						'event_espresso'
768
+					)
769
+				),
770
+				'confirm_skip_migration'           => wp_strip_all_tags(
771
+					__(
772
+						'You have chosen to NOT migrate your existing data. Are you sure you want to continue?',
773
+						'event_espresso'
774
+					)
775
+				),
776
+			]
777
+		);
778
+	}
779
+
780
+
781
+	public function load_scripts_styles_default()
782
+	{
783
+	}
784
+
785
+
786
+	/**
787
+	 * Enqueue scripts and styles for the datetime tools page.
788
+	 */
789
+	public function load_scripts_styles_datetime_tools()
790
+	{
791
+		EE_Datepicker_Input::enqueue_styles_and_scripts();
792
+	}
793
+
794
+
795
+	/**
796
+	 * @throws EE_Error
797
+	 */
798
+	protected function _datetime_tools()
799
+	{
800
+		$form_action                                = EE_Admin_Page::add_query_args_and_nonce(
801
+			[
802
+				'action'        => 'run_datetime_offset_fix',
803
+				'return_action' => $this->_req_action,
804
+			],
805
+			EE_MAINTENANCE_ADMIN_URL
806
+		);
807
+		$form                                       = $this->_get_datetime_offset_fix_form();
808
+		$this->_admin_page_title                    = esc_html__('Datetime Utilities', 'event_espresso');
809
+		$this->_template_args['admin_page_content'] = $form->form_open($form_action, 'post')
810
+													  . $form->get_html_and_js()
811
+													  . $form->form_close();
812
+		$this->display_admin_page_with_sidebar();
813
+	}
814
+
815
+
816
+	/**
817
+	 * @throws EE_Error
818
+	 */
819
+	protected function _get_datetime_offset_fix_form()
820
+	{
821
+		if (! $this->datetime_fix_offset_form instanceof EE_Form_Section_Proper) {
822
+			$this->datetime_fix_offset_form = new EE_Form_Section_Proper(
823
+				[
824
+					'name'            => 'datetime_offset_fix_option',
825
+					'layout_strategy' => new EE_Admin_Two_Column_Layout(),
826
+					'subsections'     => [
827
+						'title'                  => new EE_Form_Section_HTML(
828
+							EEH_HTML::h2(
829
+								esc_html__('Datetime Offset Tool', 'event_espresso')
830
+							)
831
+						),
832
+						'explanation'            => new EE_Form_Section_HTML(
833
+							EEH_HTML::p(
834
+								esc_html__(
835
+									'Use this tool to automatically apply the provided offset to all Event Espresso records in your database that involve dates and times.',
836
+									'event_espresso'
837
+								)
838
+							)
839
+							. EEH_HTML::p(
840
+								esc_html__(
841
+									'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.',
842
+									'event_espresso'
843
+								)
844
+							)
845
+						),
846
+						'offset_input'           => new EE_Float_Input(
847
+							[
848
+								'html_name'       => 'offset_for_datetimes',
849
+								'html_label_text' => esc_html__(
850
+									'Offset to apply (in hours):',
851
+									'event_espresso'
852
+								),
853
+								'min_value'       => '-12',
854
+								'max_value'       => '14',
855
+								'step_value'      => '.25',
856
+								'default'         => DatetimeOffsetFix::getOffset(),
857
+							]
858
+						),
859
+						'date_range_explanation' => new EE_Form_Section_HTML(
860
+							EEH_HTML::p(
861
+								esc_html__(
862
+									'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.',
863
+									'event_espresso'
864
+								)
865
+							)
866
+							. EEH_HTML::p(
867
+								EEH_HTML::strong(
868
+									sprintf(
869
+										esc_html__(
870
+											'Note: please enter the dates in UTC (You can use %1$sthis online tool%2$s to assist with conversions).',
871
+											'event_espresso'
872
+										),
873
+										'<a href="https://www.timeanddate.com/worldclock/converter.html">',
874
+										'</a>'
875
+									)
876
+								)
877
+							)
878
+						),
879
+						'date_range_start_date'  => new EE_Datepicker_Input(
880
+							[
881
+								'html_name'       => 'offset_date_start_range',
882
+								'html_label_text' => esc_html__(
883
+									'Start Date for dates the offset applied to:',
884
+									'event_espresso'
885
+								),
886
+							]
887
+						),
888
+						'date_range_end_date'    => new EE_Datepicker_Input(
889
+							[
890
+								'html_name'       => 'offset_date_end_range',
891
+								'html_label_text' => esc_html__(
892
+									'End Date for dates the offset is applied to:',
893
+									'event_espresso'
894
+								),
895
+							]
896
+						),
897
+						'submit'                 => new EE_Submit_Input(
898
+							[
899
+								'html_label_text' => '',
900
+								'default'         => esc_html__('Apply Offset', 'event_espresso'),
901
+							]
902
+						),
903
+					],
904
+				]
905
+			);
906
+		}
907
+		return $this->datetime_fix_offset_form;
908
+	}
909
+
910
+
911
+	/**
912
+	 * Callback for the run_datetime_offset_fix route.
913
+	 *
914
+	 * @throws EE_Error
915
+	 */
916
+	protected function _apply_datetime_offset()
917
+	{
918
+		if ($_SERVER['REQUEST_METHOD'] === 'POST') {
919
+			$form = $this->_get_datetime_offset_fix_form();
920
+			$form->receive_form_submission($this->_req_data);
921
+			if ($form->is_valid()) {
922
+				// save offset data so batch processor can get it.
923
+				DatetimeOffsetFix::updateOffset((float) $form->get_input_value('offset_input'));
924
+				$utc_timezone          = new DateTimeZone('UTC');
925
+				$date_range_start_date = DateTime::createFromFormat(
926
+					'm/d/Y H:i:s',
927
+					$form->get_input_value('date_range_start_date') . ' 00:00:00',
928
+					$utc_timezone
929
+				);
930
+				$date_range_end_date   = DateTime::createFromFormat(
931
+					'm/d/Y H:i:s',
932
+					$form->get_input_value('date_range_end_date') . ' 23:59:59',
933
+					$utc_timezone
934
+				);
935
+				if ($date_range_start_date instanceof DateTime) {
936
+					DatetimeOffsetFix::updateStartDateRange(DbSafeDateTime::createFromDateTime($date_range_start_date));
937
+				}
938
+				if ($date_range_end_date instanceof DateTime) {
939
+					DatetimeOffsetFix::updateEndDateRange(DbSafeDateTime::createFromDateTime($date_range_end_date));
940
+				}
941
+				// redirect to batch tool
942
+				wp_redirect(
943
+					EE_Admin_Page::add_query_args_and_nonce(
944
+						[
945
+							'page'        => EED_Batch::PAGE_SLUG,
946
+							'batch'       => EED_Batch::batch_job,
947
+							'label'       => esc_html__('Applying Offset', 'event_espresso'),
948
+							'job_handler' => urlencode('EventEspresso\core\libraries\batch\JobHandlers\DatetimeOffsetFix'),
949
+							'return_url'  => urlencode(
950
+								add_query_arg(
951
+									[
952
+										'action' => 'datetime_tools',
953
+									],
954
+									EEH_URL::current_url_without_query_paramaters(
955
+										[
956
+											'return_action',
957
+											'run_datetime_offset_fix_nonce',
958
+											'return',
959
+											'datetime_tools_nonce',
960
+										]
961
+									)
962
+								)
963
+							),
964
+						],
965
+						admin_url()
966
+					)
967
+				);
968
+				exit;
969
+			}
970
+		}
971
+	}
972 972
 }
Please login to merge, or discard this patch.
espresso.php 1 patch
Indentation   +107 added lines, -107 removed lines patch added patch discarded remove patch
@@ -37,138 +37,138 @@
 block discarded – undo
37 37
  * @since           4.0
38 38
  */
39 39
 if (function_exists('espresso_version')) {
40
-    if (! function_exists('espresso_duplicate_plugin_error')) {
41
-        /**
42
-         *    espresso_duplicate_plugin_error
43
-         *    displays if more than one version of EE is activated at the same time.
44
-         */
45
-        function espresso_duplicate_plugin_error()
46
-        {
47
-            ?>
40
+	if (! function_exists('espresso_duplicate_plugin_error')) {
41
+		/**
42
+		 *    espresso_duplicate_plugin_error
43
+		 *    displays if more than one version of EE is activated at the same time.
44
+		 */
45
+		function espresso_duplicate_plugin_error()
46
+		{
47
+			?>
48 48
 <div class="error">
49 49
 	<p>
50 50
 		<?php
51
-                    echo esc_html__(
52
-                        'Can not run multiple versions of Event Espresso! One version has been automatically deactivated. Please verify that you have the correct version you want still active.',
53
-                        'event_espresso'
54
-                    ); ?>
51
+					echo esc_html__(
52
+						'Can not run multiple versions of Event Espresso! One version has been automatically deactivated. Please verify that you have the correct version you want still active.',
53
+						'event_espresso'
54
+					); ?>
55 55
 	</p>
56 56
 </div>
57 57
 <?php
58
-            espresso_deactivate_plugin(plugin_basename(__FILE__));
59
-        }
60
-    }
61
-    add_action('admin_notices', 'espresso_duplicate_plugin_error', 1);
58
+			espresso_deactivate_plugin(plugin_basename(__FILE__));
59
+		}
60
+	}
61
+	add_action('admin_notices', 'espresso_duplicate_plugin_error', 1);
62 62
 } else {
63
-    define('EE_MIN_PHP_VER_REQUIRED', '7.4.0');
64
-    if (! version_compare(PHP_VERSION, EE_MIN_PHP_VER_REQUIRED, '>=')) {
65
-        /**
66
-         * espresso_minimum_php_version_error
67
-         *
68
-         * @return void
69
-         */
70
-        function espresso_minimum_php_version_error()
71
-        {
72
-            ?>
63
+	define('EE_MIN_PHP_VER_REQUIRED', '7.4.0');
64
+	if (! version_compare(PHP_VERSION, EE_MIN_PHP_VER_REQUIRED, '>=')) {
65
+		/**
66
+		 * espresso_minimum_php_version_error
67
+		 *
68
+		 * @return void
69
+		 */
70
+		function espresso_minimum_php_version_error()
71
+		{
72
+			?>
73 73
 <div class="error">
74 74
 	<p>
75 75
 		<?php
76
-                    printf(
77
-                        esc_html__(
78
-                            'We\'re sorry, but Event Espresso requires PHP version %1$s or greater in order to operate. You are currently running version %2$s.%3$sIn order to update your version of PHP, you will need to contact your current hosting provider.%3$sFor information on stable PHP versions, please go to %4$s.',
79
-                            'event_espresso'
80
-                        ),
81
-                        EE_MIN_PHP_VER_REQUIRED,
82
-                        PHP_VERSION,
83
-                        '<br/>',
84
-                        '<a href="https://www.php.net/downloads.php">https://php.net/downloads.php</a>'
85
-                    );
86
-                    ?>
76
+					printf(
77
+						esc_html__(
78
+							'We\'re sorry, but Event Espresso requires PHP version %1$s or greater in order to operate. You are currently running version %2$s.%3$sIn order to update your version of PHP, you will need to contact your current hosting provider.%3$sFor information on stable PHP versions, please go to %4$s.',
79
+							'event_espresso'
80
+						),
81
+						EE_MIN_PHP_VER_REQUIRED,
82
+						PHP_VERSION,
83
+						'<br/>',
84
+						'<a href="https://www.php.net/downloads.php">https://php.net/downloads.php</a>'
85
+					);
86
+					?>
87 87
 	</p>
88 88
 </div>
89 89
 <?php
90
-            espresso_deactivate_plugin(plugin_basename(__FILE__));
91
-        }
90
+			espresso_deactivate_plugin(plugin_basename(__FILE__));
91
+		}
92 92
 
93
-        add_action('admin_notices', 'espresso_minimum_php_version_error', 1);
94
-    } else {
95
-        define('EVENT_ESPRESSO_MAIN_FILE', __FILE__);
93
+		add_action('admin_notices', 'espresso_minimum_php_version_error', 1);
94
+	} else {
95
+		define('EVENT_ESPRESSO_MAIN_FILE', __FILE__);
96 96
 
97
-        require_once __DIR__ . '/vendor/autoload.php';
97
+		require_once __DIR__ . '/vendor/autoload.php';
98 98
 
99
-        /**
100
-         * espresso_version
101
-         * Returns the plugin version
102
-         *
103
-         * @return string
104
-         */
105
-        function espresso_version(): string
106
-        {
107
-            return apply_filters('FHEE__espresso__espresso_version', '5.0.11.rc.000');
108
-        }
99
+		/**
100
+		 * espresso_version
101
+		 * Returns the plugin version
102
+		 *
103
+		 * @return string
104
+		 */
105
+		function espresso_version(): string
106
+		{
107
+			return apply_filters('FHEE__espresso__espresso_version', '5.0.11.rc.000');
108
+		}
109 109
 
110
-        /**
111
-         * espresso_plugin_activation
112
-         * adds a wp-option to indicate that EE has been activated via the WP admin plugins page
113
-         */
114
-        function espresso_plugin_activation()
115
-        {
116
-            update_option('ee_espresso_activation', true);
117
-            update_option('event-espresso-core_allow_tracking', 'no');
118
-            update_option('event-espresso-core_tracking_notice', 'hide');
119
-            // Run WP GraphQL activation callback
120
-            espressoLoadWpGraphQL();
121
-            graphql_activation_callback();
122
-        }
110
+		/**
111
+		 * espresso_plugin_activation
112
+		 * adds a wp-option to indicate that EE has been activated via the WP admin plugins page
113
+		 */
114
+		function espresso_plugin_activation()
115
+		{
116
+			update_option('ee_espresso_activation', true);
117
+			update_option('event-espresso-core_allow_tracking', 'no');
118
+			update_option('event-espresso-core_tracking_notice', 'hide');
119
+			// Run WP GraphQL activation callback
120
+			espressoLoadWpGraphQL();
121
+			graphql_activation_callback();
122
+		}
123 123
 
124
-        register_activation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_activation');
124
+		register_activation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_activation');
125 125
 
126
-        /**
127
-         * espresso_plugin_deactivation
128
-         */
129
-        function espresso_plugin_deactivation()
130
-        {
131
-            // Run WP GraphQL deactivation callback
132
-            espressoLoadWpGraphQL();
133
-            graphql_deactivation_callback();
134
-            delete_option('event-espresso-core_allow_tracking');
135
-            delete_option('event-espresso-core_tracking_notice');
136
-        }
137
-        register_deactivation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_deactivation');
126
+		/**
127
+		 * espresso_plugin_deactivation
128
+		 */
129
+		function espresso_plugin_deactivation()
130
+		{
131
+			// Run WP GraphQL deactivation callback
132
+			espressoLoadWpGraphQL();
133
+			graphql_deactivation_callback();
134
+			delete_option('event-espresso-core_allow_tracking');
135
+			delete_option('event-espresso-core_tracking_notice');
136
+		}
137
+		register_deactivation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_deactivation');
138 138
 
139
-        require_once __DIR__ . '/core/bootstrap_espresso.php';
140
-        bootstrap_espresso();
141
-    }
139
+		require_once __DIR__ . '/core/bootstrap_espresso.php';
140
+		bootstrap_espresso();
141
+	}
142 142
 }
143 143
 
144 144
 if (! function_exists('espresso_deactivate_plugin')) {
145
-    /**
146
-     *    deactivate_plugin
147
-     * usage:  espresso_deactivate_plugin( plugin_basename( __FILE__ ));
148
-     *
149
-     * @access public
150
-     * @param string $plugin_basename - the results of plugin_basename( __FILE__ ) for the plugin's main file
151
-     * @return    void
152
-     */
153
-    function espresso_deactivate_plugin(string $plugin_basename = '')
154
-    {
155
-        if (! function_exists('deactivate_plugins')) {
156
-            require_once ABSPATH . 'wp-admin/includes/plugin.php';
157
-        }
158
-        unset($_GET['activate'], $_REQUEST['activate']);
159
-        deactivate_plugins($plugin_basename);
160
-    }
145
+	/**
146
+	 *    deactivate_plugin
147
+	 * usage:  espresso_deactivate_plugin( plugin_basename( __FILE__ ));
148
+	 *
149
+	 * @access public
150
+	 * @param string $plugin_basename - the results of plugin_basename( __FILE__ ) for the plugin's main file
151
+	 * @return    void
152
+	 */
153
+	function espresso_deactivate_plugin(string $plugin_basename = '')
154
+	{
155
+		if (! function_exists('deactivate_plugins')) {
156
+			require_once ABSPATH . 'wp-admin/includes/plugin.php';
157
+		}
158
+		unset($_GET['activate'], $_REQUEST['activate']);
159
+		deactivate_plugins($plugin_basename);
160
+	}
161 161
 }
162 162
 
163 163
 
164 164
 if (! function_exists('espressoLoadWpGraphQL')) {
165
-    function espressoLoadWpGraphQL()
166
-    {
167
-        if (
168
-            ! class_exists('WPGraphQL')
169
-            && is_readable(__DIR__ . '/vendor/wp-graphql/wp-graphql/wp-graphql.php')
170
-        ) {
171
-            require_once __DIR__ . '/vendor/wp-graphql/wp-graphql/wp-graphql.php';
172
-        }
173
-    }
165
+	function espressoLoadWpGraphQL()
166
+	{
167
+		if (
168
+			! class_exists('WPGraphQL')
169
+			&& is_readable(__DIR__ . '/vendor/wp-graphql/wp-graphql/wp-graphql.php')
170
+		) {
171
+			require_once __DIR__ . '/vendor/wp-graphql/wp-graphql/wp-graphql.php';
172
+		}
173
+	}
174 174
 }
Please login to merge, or discard this patch.
core/EE_Maintenance_Mode.core.php 2 patches
Indentation   +358 added lines, -358 removed lines patch added patch discarded remove patch
@@ -16,364 +16,364 @@
 block discarded – undo
16 16
  */
17 17
 class EE_Maintenance_Mode implements ResettableInterface
18 18
 {
19
-    /**
20
-     * constants available to client code for interpreting the values of EE_Maintenance_Mode::level().
21
-     * level_0_not_in_maintenance means the site is NOT in maintenance mode (so everything's normal)
22
-     */
23
-    const level_0_not_in_maintenance = 0;
24
-
25
-    /**
26
-     * level_1_frontend_only_maintenance means that the site's frontend EE code should be completely disabled
27
-     * but the admin backend should be running as normal. Maybe an admin can view the frontend though
28
-     */
29
-    const level_1_frontend_only_maintenance = 1;
30
-
31
-    /**
32
-     * level_2_complete_maintenance means the frontend AND EE backend code are disabled. The only system running
33
-     * is the maintenance mode stuff, which will require users to update all addons, and then finish running all
34
-     * migration scripts before taking the site out of maintenance mode
35
-     */
36
-    const level_2_complete_maintenance = 2;
37
-
38
-    /**
39
-     * the name of the option which stores the current level of maintenance mode
40
-     */
41
-    const option_name_maintenance_mode = 'ee_maintenance_mode';
42
-
43
-
44
-    /**
45
-     * @var EE_Maintenance_Mode $_instance
46
-     */
47
-    private static $_instance;
48
-
49
-    /**
50
-     * @var EE_Registry $EE
51
-     */
52
-    protected $EE;
53
-
54
-
55
-    /**
56
-     * @singleton method used to instantiate class object
57
-     * @return EE_Maintenance_Mode
58
-     */
59
-    public static function instance()
60
-    {
61
-        // check if class object is instantiated
62
-        if (! self::$_instance instanceof EE_Maintenance_Mode) {
63
-            self::$_instance = new self();
64
-        }
65
-        return self::$_instance;
66
-    }
67
-
68
-
69
-    /**
70
-     * Resets maintenance mode (mostly just re-checks whether we should be in maintenance mode)
71
-     *
72
-     * @return EE_Maintenance_Mode
73
-     * @throws EE_Error
74
-     */
75
-    public static function reset()
76
-    {
77
-        self::instance()->set_maintenance_mode_if_db_old();
78
-        return self::instance();
79
-    }
80
-
81
-
82
-    /**
83
-     *private constructor to prevent direct creation
84
-     */
85
-    private function __construct()
86
-    {
87
-        // if M-Mode level 2 is engaged, we still need basic assets loaded
88
-        add_action('wp_enqueue_scripts', [$this, 'load_assets_required_for_m_mode']);
89
-        // shut 'er down for maintenance ?
90
-        add_filter('the_content', [$this, 'the_content'], 2);
91
-        // redirect ee menus to maintenance page
92
-        add_action('admin_page_access_denied', [$this, 'redirect_to_maintenance']);
93
-        // add powered by EE msg
94
-        add_action('shutdown', [$this, 'display_maintenance_mode_notice'], 10);
95
-    }
96
-
97
-
98
-    /**
99
-     * retrieves the maintenance mode option value from the db
100
-     *
101
-     * @return int
102
-     */
103
-    public function real_level()
104
-    {
105
-        return (int) get_option(self::option_name_maintenance_mode, EE_Maintenance_Mode::level_0_not_in_maintenance);
106
-    }
107
-
108
-
109
-    /**
110
-     * Returns whether the models reportedly are able to run queries or not
111
-     * (ie, if the system thinks their tables are present and up-to-date).
112
-     *
113
-     * @return boolean
114
-     */
115
-    public function models_can_query()
116
-    {
117
-        return $this->real_level() !== EE_Maintenance_Mode::level_2_complete_maintenance;
118
-    }
119
-
120
-
121
-    /**
122
-     * Determines whether we're in maintenance mode and what level. However, while the site
123
-     * is in level 1 maintenance, and an admin visits the frontend, this function makes it appear
124
-     * to them as if teh site isn't in maintenance mode.
125
-     * EE_Maintenance_Mode::level_0_not_in_maintenance => not in maintenance mode (in normal mode)
126
-     * EE_Maintenance_Mode::level_1_frontend_only_maintenance=> frontend-only maintenance mode
127
-     * EE_Maintenance_Mode::level_2_complete_maintenance => frontend and backend maintenance mode
128
-     *
129
-     * @return int
130
-     */
131
-    public function level()
132
-    {
133
-        $maintenance_mode_level = $this->real_level();
134
-        // if this is an admin request, we'll be honest... except if it's ajax, because that might be from the frontend
135
-        if (
136
-            $maintenance_mode_level === EE_Maintenance_Mode::level_1_frontend_only_maintenance// we're in level 1
137
-            && ((defined('DOING_AJAX') && DOING_AJAX) || ! is_admin()) // on non-ajax frontend requests
138
-            && current_user_can('administrator') // when the user is an admin
139
-        ) {
140
-            $maintenance_mode_level = EE_Maintenance_Mode::level_0_not_in_maintenance;
141
-        }
142
-        return $maintenance_mode_level;
143
-    }
144
-
145
-
146
-    /**
147
-     * Determines if we need to put EE in maintenance mode because the database needs updating
148
-     *
149
-     * @return boolean true if DB is old and maintenance mode was triggered; false otherwise
150
-     * @throws EE_Error
151
-     */
152
-    public function set_maintenance_mode_if_db_old()
153
-    {
154
-        LoaderFactory::getLoader()->getShared('Data_Migration_Manager');
155
-        if (EE_Data_Migration_Manager::instance()->check_for_applicable_data_migration_scripts()) {
156
-            update_option(self::option_name_maintenance_mode, self::level_2_complete_maintenance);
157
-            return true;
158
-        }
159
-        if ($this->level() === self::level_2_complete_maintenance) {
160
-            // we also want to handle the opposite: if the site is mm2, but there aren't any migrations to run
161
-            // then we shouldn't be in mm2. (Maybe an addon got deactivated?)
162
-            update_option(self::option_name_maintenance_mode, self::level_0_not_in_maintenance);
163
-            return false;
164
-        }
165
-        return false;
166
-    }
167
-
168
-
169
-    /**
170
-     * Updates the maintenance level on the site
171
-     *
172
-     * @param int $level
173
-     * @return void
174
-     */
175
-    public function set_maintenance_level($level)
176
-    {
177
-        do_action('AHEE__EE_Maintenance_Mode__set_maintenance_level', $level);
178
-        update_option(self::option_name_maintenance_mode, (int) $level);
179
-    }
180
-
181
-
182
-    /**
183
-     * returns TRUE if M-Mode is engaged and the current request is not for the admin
184
-     *
185
-     * @return bool
186
-     */
187
-    public static function disable_frontend_for_maintenance()
188
-    {
189
-        return (! is_admin() && EE_Maintenance_Mode::instance()->level());
190
-    }
191
-
192
-
193
-    /**
194
-     * @return void
195
-     */
196
-    public function load_assets_required_for_m_mode()
197
-    {
198
-        if (
199
-            $this->real_level() === EE_Maintenance_Mode::level_2_complete_maintenance
200
-            && ! wp_script_is('espresso_core')
201
-        ) {
202
-            wp_register_style(
203
-                'espresso_default',
204
-                EE_GLOBAL_ASSETS_URL . 'css/espresso_default.css',
205
-                ['dashicons'],
206
-                EVENT_ESPRESSO_VERSION
207
-            );
208
-            wp_enqueue_style('espresso_default');
209
-            wp_register_script(
210
-                'espresso_core',
211
-                EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js',
212
-                ['jquery'],
213
-                EVENT_ESPRESSO_VERSION,
214
-                true
215
-            );
216
-            wp_enqueue_script('espresso_core');
217
-        }
218
-    }
219
-
220
-
221
-    /**
222
-     * replacement EE CPT template that displays message notifying site visitors
223
-     * that EE has been temporarily placed into maintenance mode
224
-     * does NOT get called on non-EE-CPT requests
225
-     *
226
-     * @return    string
227
-     */
228
-    public static function template_include()
229
-    {
230
-        // shut 'er down for maintenance ? then don't use any of our templates for our endpoints
231
-        return get_template_directory() . '/index.php';
232
-    }
233
-
234
-
235
-    /**
236
-     * displays message notifying site visitors that EE has been temporarily
237
-     * placed into maintenance mode when post_type != EE CPT
238
-     *
239
-     * @param string $the_content
240
-     * @return string
241
-     */
242
-    public function the_content($the_content)
243
-    {
244
-        // check if M-mode is engaged and for EE shortcode
245
-        if ($this->level() && strpos($the_content, '[ESPRESSO_') !== false) {
246
-            // this can eventually be moved to a template, or edited via admin. But for now...
247
-            $the_content = sprintf(
248
-                esc_html__(
249
-                    '%sMaintenance Mode%sEvent Registration has been temporarily closed while system maintenance is being performed. We\'re sorry for any inconveniences this may have caused. Please try back again later.%s',
250
-                    'event_espresso'
251
-                ),
252
-                '<h3>',
253
-                '</h3><p>',
254
-                '</p>'
255
-            );
256
-        }
257
-        return $the_content;
258
-    }
259
-
260
-
261
-    /**
262
-     * displays message on frontend of site notifying admin that EE has been temporarily placed into maintenance mode
263
-     */
264
-    public function display_maintenance_mode_notice()
265
-    {
266
-        if (! did_action('AHEE__EE_System__load_core_configuration__complete')) {
267
-            return;
268
-        }
269
-        /** @var CurrentPage $current_page */
270
-        $current_page = LoaderFactory::getLoader()->getShared(CurrentPage::class);
271
-        // check if M-mode is engaged and for EE shortcode
272
-        if (
273
-            ! (defined('DOING_AJAX') && DOING_AJAX)
274
-            && $this->real_level()
275
-            && ! is_admin()
276
-            && current_user_can('administrator')
277
-            && $current_page->isEspressoPage()
278
-        ) {
279
-            printf(
280
-                esc_html__(
281
-                    '%sclose%sEvent Registration is currently disabled because Event Espresso has been placed into Maintenance Mode. To change Maintenance Mode settings, click here %sEE Maintenance Mode Admin Page%s',
282
-                    'event_espresso'
283
-                ),
284
-                '<div id="ee-m-mode-admin-notice-dv" class="ee-really-important-notice-dv"><a class="close-espresso-notice" title="',
285
-                '"><span class="dashicons dashicons-no"></span></a><p>',
286
-                ' &raquo; <a href="' . add_query_arg(
287
-                    ['page' => 'espresso_maintenance_settings'],
288
-                    admin_url('admin.php')
289
-                ) . '">',
290
-                '</a></p></div>'
291
-            );
292
-        }
293
-    }
294
-    // espresso-notices important-notice ee-attention
295
-
296
-    /**
297
-     * Redirects EE admin menu requests to the maintenance page
298
-     */
299
-    public function redirect_to_maintenance()
300
-    {
301
-        global $pagenow;
302
-        $request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
303
-        $page   = $request->getRequestParam('page');
304
-
305
-        if (
306
-            $pagenow == 'admin.php'
307
-            && $page !== 'espresso_maintenance_settings'
308
-            && strpos($page, 'espresso_') !== false
309
-            && $this->real_level() == EE_Maintenance_Mode::level_2_complete_maintenance
310
-        ) {
311
-            EEH_URL::safeRedirectAndExit('admin.php?page=espresso_maintenance_settings');
312
-        }
313
-    }
314
-
315
-
316
-    /**
317
-     * override magic methods
318
-     */
319
-    final public function __destruct()
320
-    {
321
-    }
322
-
323
-
324
-    final public function __call($a, $b)
325
-    {
326
-    }
327
-
328
-
329
-    final public function __get($a)
330
-    {
331
-    }
332
-
333
-
334
-    final public function __set($a, $b)
335
-    {
336
-    }
337
-
338
-
339
-    final public function __isset($a)
340
-    {
341
-    }
342
-
343
-
344
-    final public function __unset($a)
345
-    {
346
-    }
347
-
348
-
349
-    final public function __sleep()
350
-    {
351
-        return [];
352
-    }
353
-
354
-
355
-    final public function __wakeup()
356
-    {
357
-    }
358
-
359
-
360
-    final public function __invoke()
361
-    {
362
-    }
363
-
364
-
365
-    final public static function __set_state($a = null)
366
-    {
367
-        return EE_Maintenance_Mode::instance();
368
-    }
369
-
370
-
371
-    final public function __clone()
372
-    {
373
-    }
19
+	/**
20
+	 * constants available to client code for interpreting the values of EE_Maintenance_Mode::level().
21
+	 * level_0_not_in_maintenance means the site is NOT in maintenance mode (so everything's normal)
22
+	 */
23
+	const level_0_not_in_maintenance = 0;
24
+
25
+	/**
26
+	 * level_1_frontend_only_maintenance means that the site's frontend EE code should be completely disabled
27
+	 * but the admin backend should be running as normal. Maybe an admin can view the frontend though
28
+	 */
29
+	const level_1_frontend_only_maintenance = 1;
30
+
31
+	/**
32
+	 * level_2_complete_maintenance means the frontend AND EE backend code are disabled. The only system running
33
+	 * is the maintenance mode stuff, which will require users to update all addons, and then finish running all
34
+	 * migration scripts before taking the site out of maintenance mode
35
+	 */
36
+	const level_2_complete_maintenance = 2;
37
+
38
+	/**
39
+	 * the name of the option which stores the current level of maintenance mode
40
+	 */
41
+	const option_name_maintenance_mode = 'ee_maintenance_mode';
42
+
43
+
44
+	/**
45
+	 * @var EE_Maintenance_Mode $_instance
46
+	 */
47
+	private static $_instance;
48
+
49
+	/**
50
+	 * @var EE_Registry $EE
51
+	 */
52
+	protected $EE;
53
+
54
+
55
+	/**
56
+	 * @singleton method used to instantiate class object
57
+	 * @return EE_Maintenance_Mode
58
+	 */
59
+	public static function instance()
60
+	{
61
+		// check if class object is instantiated
62
+		if (! self::$_instance instanceof EE_Maintenance_Mode) {
63
+			self::$_instance = new self();
64
+		}
65
+		return self::$_instance;
66
+	}
67
+
68
+
69
+	/**
70
+	 * Resets maintenance mode (mostly just re-checks whether we should be in maintenance mode)
71
+	 *
72
+	 * @return EE_Maintenance_Mode
73
+	 * @throws EE_Error
74
+	 */
75
+	public static function reset()
76
+	{
77
+		self::instance()->set_maintenance_mode_if_db_old();
78
+		return self::instance();
79
+	}
80
+
81
+
82
+	/**
83
+	 *private constructor to prevent direct creation
84
+	 */
85
+	private function __construct()
86
+	{
87
+		// if M-Mode level 2 is engaged, we still need basic assets loaded
88
+		add_action('wp_enqueue_scripts', [$this, 'load_assets_required_for_m_mode']);
89
+		// shut 'er down for maintenance ?
90
+		add_filter('the_content', [$this, 'the_content'], 2);
91
+		// redirect ee menus to maintenance page
92
+		add_action('admin_page_access_denied', [$this, 'redirect_to_maintenance']);
93
+		// add powered by EE msg
94
+		add_action('shutdown', [$this, 'display_maintenance_mode_notice'], 10);
95
+	}
96
+
97
+
98
+	/**
99
+	 * retrieves the maintenance mode option value from the db
100
+	 *
101
+	 * @return int
102
+	 */
103
+	public function real_level()
104
+	{
105
+		return (int) get_option(self::option_name_maintenance_mode, EE_Maintenance_Mode::level_0_not_in_maintenance);
106
+	}
107
+
108
+
109
+	/**
110
+	 * Returns whether the models reportedly are able to run queries or not
111
+	 * (ie, if the system thinks their tables are present and up-to-date).
112
+	 *
113
+	 * @return boolean
114
+	 */
115
+	public function models_can_query()
116
+	{
117
+		return $this->real_level() !== EE_Maintenance_Mode::level_2_complete_maintenance;
118
+	}
119
+
120
+
121
+	/**
122
+	 * Determines whether we're in maintenance mode and what level. However, while the site
123
+	 * is in level 1 maintenance, and an admin visits the frontend, this function makes it appear
124
+	 * to them as if teh site isn't in maintenance mode.
125
+	 * EE_Maintenance_Mode::level_0_not_in_maintenance => not in maintenance mode (in normal mode)
126
+	 * EE_Maintenance_Mode::level_1_frontend_only_maintenance=> frontend-only maintenance mode
127
+	 * EE_Maintenance_Mode::level_2_complete_maintenance => frontend and backend maintenance mode
128
+	 *
129
+	 * @return int
130
+	 */
131
+	public function level()
132
+	{
133
+		$maintenance_mode_level = $this->real_level();
134
+		// if this is an admin request, we'll be honest... except if it's ajax, because that might be from the frontend
135
+		if (
136
+			$maintenance_mode_level === EE_Maintenance_Mode::level_1_frontend_only_maintenance// we're in level 1
137
+			&& ((defined('DOING_AJAX') && DOING_AJAX) || ! is_admin()) // on non-ajax frontend requests
138
+			&& current_user_can('administrator') // when the user is an admin
139
+		) {
140
+			$maintenance_mode_level = EE_Maintenance_Mode::level_0_not_in_maintenance;
141
+		}
142
+		return $maintenance_mode_level;
143
+	}
144
+
145
+
146
+	/**
147
+	 * Determines if we need to put EE in maintenance mode because the database needs updating
148
+	 *
149
+	 * @return boolean true if DB is old and maintenance mode was triggered; false otherwise
150
+	 * @throws EE_Error
151
+	 */
152
+	public function set_maintenance_mode_if_db_old()
153
+	{
154
+		LoaderFactory::getLoader()->getShared('Data_Migration_Manager');
155
+		if (EE_Data_Migration_Manager::instance()->check_for_applicable_data_migration_scripts()) {
156
+			update_option(self::option_name_maintenance_mode, self::level_2_complete_maintenance);
157
+			return true;
158
+		}
159
+		if ($this->level() === self::level_2_complete_maintenance) {
160
+			// we also want to handle the opposite: if the site is mm2, but there aren't any migrations to run
161
+			// then we shouldn't be in mm2. (Maybe an addon got deactivated?)
162
+			update_option(self::option_name_maintenance_mode, self::level_0_not_in_maintenance);
163
+			return false;
164
+		}
165
+		return false;
166
+	}
167
+
168
+
169
+	/**
170
+	 * Updates the maintenance level on the site
171
+	 *
172
+	 * @param int $level
173
+	 * @return void
174
+	 */
175
+	public function set_maintenance_level($level)
176
+	{
177
+		do_action('AHEE__EE_Maintenance_Mode__set_maintenance_level', $level);
178
+		update_option(self::option_name_maintenance_mode, (int) $level);
179
+	}
180
+
181
+
182
+	/**
183
+	 * returns TRUE if M-Mode is engaged and the current request is not for the admin
184
+	 *
185
+	 * @return bool
186
+	 */
187
+	public static function disable_frontend_for_maintenance()
188
+	{
189
+		return (! is_admin() && EE_Maintenance_Mode::instance()->level());
190
+	}
191
+
192
+
193
+	/**
194
+	 * @return void
195
+	 */
196
+	public function load_assets_required_for_m_mode()
197
+	{
198
+		if (
199
+			$this->real_level() === EE_Maintenance_Mode::level_2_complete_maintenance
200
+			&& ! wp_script_is('espresso_core')
201
+		) {
202
+			wp_register_style(
203
+				'espresso_default',
204
+				EE_GLOBAL_ASSETS_URL . 'css/espresso_default.css',
205
+				['dashicons'],
206
+				EVENT_ESPRESSO_VERSION
207
+			);
208
+			wp_enqueue_style('espresso_default');
209
+			wp_register_script(
210
+				'espresso_core',
211
+				EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js',
212
+				['jquery'],
213
+				EVENT_ESPRESSO_VERSION,
214
+				true
215
+			);
216
+			wp_enqueue_script('espresso_core');
217
+		}
218
+	}
219
+
220
+
221
+	/**
222
+	 * replacement EE CPT template that displays message notifying site visitors
223
+	 * that EE has been temporarily placed into maintenance mode
224
+	 * does NOT get called on non-EE-CPT requests
225
+	 *
226
+	 * @return    string
227
+	 */
228
+	public static function template_include()
229
+	{
230
+		// shut 'er down for maintenance ? then don't use any of our templates for our endpoints
231
+		return get_template_directory() . '/index.php';
232
+	}
233
+
234
+
235
+	/**
236
+	 * displays message notifying site visitors that EE has been temporarily
237
+	 * placed into maintenance mode when post_type != EE CPT
238
+	 *
239
+	 * @param string $the_content
240
+	 * @return string
241
+	 */
242
+	public function the_content($the_content)
243
+	{
244
+		// check if M-mode is engaged and for EE shortcode
245
+		if ($this->level() && strpos($the_content, '[ESPRESSO_') !== false) {
246
+			// this can eventually be moved to a template, or edited via admin. But for now...
247
+			$the_content = sprintf(
248
+				esc_html__(
249
+					'%sMaintenance Mode%sEvent Registration has been temporarily closed while system maintenance is being performed. We\'re sorry for any inconveniences this may have caused. Please try back again later.%s',
250
+					'event_espresso'
251
+				),
252
+				'<h3>',
253
+				'</h3><p>',
254
+				'</p>'
255
+			);
256
+		}
257
+		return $the_content;
258
+	}
259
+
260
+
261
+	/**
262
+	 * displays message on frontend of site notifying admin that EE has been temporarily placed into maintenance mode
263
+	 */
264
+	public function display_maintenance_mode_notice()
265
+	{
266
+		if (! did_action('AHEE__EE_System__load_core_configuration__complete')) {
267
+			return;
268
+		}
269
+		/** @var CurrentPage $current_page */
270
+		$current_page = LoaderFactory::getLoader()->getShared(CurrentPage::class);
271
+		// check if M-mode is engaged and for EE shortcode
272
+		if (
273
+			! (defined('DOING_AJAX') && DOING_AJAX)
274
+			&& $this->real_level()
275
+			&& ! is_admin()
276
+			&& current_user_can('administrator')
277
+			&& $current_page->isEspressoPage()
278
+		) {
279
+			printf(
280
+				esc_html__(
281
+					'%sclose%sEvent Registration is currently disabled because Event Espresso has been placed into Maintenance Mode. To change Maintenance Mode settings, click here %sEE Maintenance Mode Admin Page%s',
282
+					'event_espresso'
283
+				),
284
+				'<div id="ee-m-mode-admin-notice-dv" class="ee-really-important-notice-dv"><a class="close-espresso-notice" title="',
285
+				'"><span class="dashicons dashicons-no"></span></a><p>',
286
+				' &raquo; <a href="' . add_query_arg(
287
+					['page' => 'espresso_maintenance_settings'],
288
+					admin_url('admin.php')
289
+				) . '">',
290
+				'</a></p></div>'
291
+			);
292
+		}
293
+	}
294
+	// espresso-notices important-notice ee-attention
295
+
296
+	/**
297
+	 * Redirects EE admin menu requests to the maintenance page
298
+	 */
299
+	public function redirect_to_maintenance()
300
+	{
301
+		global $pagenow;
302
+		$request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
303
+		$page   = $request->getRequestParam('page');
304
+
305
+		if (
306
+			$pagenow == 'admin.php'
307
+			&& $page !== 'espresso_maintenance_settings'
308
+			&& strpos($page, 'espresso_') !== false
309
+			&& $this->real_level() == EE_Maintenance_Mode::level_2_complete_maintenance
310
+		) {
311
+			EEH_URL::safeRedirectAndExit('admin.php?page=espresso_maintenance_settings');
312
+		}
313
+	}
314
+
315
+
316
+	/**
317
+	 * override magic methods
318
+	 */
319
+	final public function __destruct()
320
+	{
321
+	}
322
+
323
+
324
+	final public function __call($a, $b)
325
+	{
326
+	}
327
+
328
+
329
+	final public function __get($a)
330
+	{
331
+	}
332
+
333
+
334
+	final public function __set($a, $b)
335
+	{
336
+	}
337
+
338
+
339
+	final public function __isset($a)
340
+	{
341
+	}
342
+
343
+
344
+	final public function __unset($a)
345
+	{
346
+	}
347
+
348
+
349
+	final public function __sleep()
350
+	{
351
+		return [];
352
+	}
353
+
354
+
355
+	final public function __wakeup()
356
+	{
357
+	}
358
+
359
+
360
+	final public function __invoke()
361
+	{
362
+	}
363
+
364
+
365
+	final public static function __set_state($a = null)
366
+	{
367
+		return EE_Maintenance_Mode::instance();
368
+	}
369
+
370
+
371
+	final public function __clone()
372
+	{
373
+	}
374 374
 
375 375
 
376
-    final public static function __callStatic($a, $b)
377
-    {
378
-    }
376
+	final public static function __callStatic($a, $b)
377
+	{
378
+	}
379 379
 }
Please login to merge, or discard this patch.
Spacing   +9 added lines, -9 removed lines patch added patch discarded remove patch
@@ -59,7 +59,7 @@  discard block
 block discarded – undo
59 59
     public static function instance()
60 60
     {
61 61
         // check if class object is instantiated
62
-        if (! self::$_instance instanceof EE_Maintenance_Mode) {
62
+        if ( ! self::$_instance instanceof EE_Maintenance_Mode) {
63 63
             self::$_instance = new self();
64 64
         }
65 65
         return self::$_instance;
@@ -186,7 +186,7 @@  discard block
 block discarded – undo
186 186
      */
187 187
     public static function disable_frontend_for_maintenance()
188 188
     {
189
-        return (! is_admin() && EE_Maintenance_Mode::instance()->level());
189
+        return ( ! is_admin() && EE_Maintenance_Mode::instance()->level());
190 190
     }
191 191
 
192 192
 
@@ -201,14 +201,14 @@  discard block
 block discarded – undo
201 201
         ) {
202 202
             wp_register_style(
203 203
                 'espresso_default',
204
-                EE_GLOBAL_ASSETS_URL . 'css/espresso_default.css',
204
+                EE_GLOBAL_ASSETS_URL.'css/espresso_default.css',
205 205
                 ['dashicons'],
206 206
                 EVENT_ESPRESSO_VERSION
207 207
             );
208 208
             wp_enqueue_style('espresso_default');
209 209
             wp_register_script(
210 210
                 'espresso_core',
211
-                EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js',
211
+                EE_GLOBAL_ASSETS_URL.'scripts/espresso_core.js',
212 212
                 ['jquery'],
213 213
                 EVENT_ESPRESSO_VERSION,
214 214
                 true
@@ -228,7 +228,7 @@  discard block
 block discarded – undo
228 228
     public static function template_include()
229 229
     {
230 230
         // shut 'er down for maintenance ? then don't use any of our templates for our endpoints
231
-        return get_template_directory() . '/index.php';
231
+        return get_template_directory().'/index.php';
232 232
     }
233 233
 
234 234
 
@@ -263,7 +263,7 @@  discard block
 block discarded – undo
263 263
      */
264 264
     public function display_maintenance_mode_notice()
265 265
     {
266
-        if (! did_action('AHEE__EE_System__load_core_configuration__complete')) {
266
+        if ( ! did_action('AHEE__EE_System__load_core_configuration__complete')) {
267 267
             return;
268 268
         }
269 269
         /** @var CurrentPage $current_page */
@@ -283,10 +283,10 @@  discard block
 block discarded – undo
283 283
                 ),
284 284
                 '<div id="ee-m-mode-admin-notice-dv" class="ee-really-important-notice-dv"><a class="close-espresso-notice" title="',
285 285
                 '"><span class="dashicons dashicons-no"></span></a><p>',
286
-                ' &raquo; <a href="' . add_query_arg(
286
+                ' &raquo; <a href="'.add_query_arg(
287 287
                     ['page' => 'espresso_maintenance_settings'],
288 288
                     admin_url('admin.php')
289
-                ) . '">',
289
+                ).'">',
290 290
                 '</a></p></div>'
291 291
             );
292 292
         }
@@ -300,7 +300,7 @@  discard block
 block discarded – undo
300 300
     {
301 301
         global $pagenow;
302 302
         $request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
303
-        $page   = $request->getRequestParam('page');
303
+        $page = $request->getRequestParam('page');
304 304
 
305 305
         if (
306 306
             $pagenow == 'admin.php'
Please login to merge, or discard this patch.