Completed
Branch add-cap-checks-to-routes (73eed8)
by
unknown
08:17 queued 10s
created
admin/extend/registration_form/Extend_Registration_Form_Admin_Page.core.php 1 patch
Indentation   +1440 added lines, -1440 removed lines patch added patch discarded remove patch
@@ -14,1444 +14,1444 @@
 block discarded – undo
14 14
  */
15 15
 class Extend_Registration_Form_Admin_Page extends Registration_Form_Admin_Page
16 16
 {
17
-    /**
18
-     * @param bool $routing indicate whether we want to just load the object and handle routing or just load the object.
19
-     */
20
-    public function __construct($routing = true)
21
-    {
22
-        define('REGISTRATION_FORM_CAF_ADMIN', EE_CORE_CAF_ADMIN_EXTEND . 'registration_form/');
23
-        define('REGISTRATION_FORM_CAF_ASSETS_PATH', REGISTRATION_FORM_CAF_ADMIN . 'assets/');
24
-        define('REGISTRATION_FORM_CAF_ASSETS_URL', EE_CORE_CAF_ADMIN_EXTEND_URL . 'registration_form/assets/');
25
-        define('REGISTRATION_FORM_CAF_TEMPLATE_PATH', REGISTRATION_FORM_CAF_ADMIN . 'templates/');
26
-        define('REGISTRATION_FORM_CAF_TEMPLATE_URL', EE_CORE_CAF_ADMIN_EXTEND_URL . 'registration_form/templates/');
27
-        parent::__construct($routing);
28
-    }
29
-
30
-
31
-    /**
32
-     * @return void
33
-     */
34
-    protected function _extend_page_config()
35
-    {
36
-        $this->_admin_base_path = REGISTRATION_FORM_CAF_ADMIN;
37
-        $qst_id = ! empty($this->_req_data['QST_ID']) && ! is_array($this->_req_data['QST_ID'])
38
-            ? $this->_req_data['QST_ID'] : 0;
39
-        $qsg_id = ! empty($this->_req_data['QSG_ID']) && ! is_array($this->_req_data['QSG_ID'])
40
-            ? $this->_req_data['QSG_ID'] : 0;
41
-
42
-        $new_page_routes = array(
43
-            'question_groups'    => array(
44
-                'func'       => '_question_groups_overview_list_table',
45
-                'capability' => 'ee_read_question_groups',
46
-            ),
47
-            'add_question'       => array(
48
-                'func'       => '_edit_question',
49
-                'capability' => 'ee_edit_questions',
50
-            ),
51
-            'insert_question'    => array(
52
-                'func'       => '_insert_or_update_question',
53
-                'args'       => array('new_question' => true),
54
-                'capability' => 'ee_edit_questions',
55
-                'noheader'   => true,
56
-            ),
57
-            'duplicate_question' => array(
58
-                'func'       => '_duplicate_question',
59
-                'capability' => 'ee_edit_questions',
60
-                'noheader'   => true,
61
-            ),
62
-            'trash_question'     => array(
63
-                'func'       => '_trash_question',
64
-                'capability' => 'ee_delete_question',
65
-                'obj_id'     => $qst_id,
66
-                'noheader'   => true,
67
-            ),
68
-
69
-            'restore_question' => array(
70
-                'func'       => '_trash_or_restore_questions',
71
-                'capability' => 'ee_delete_question',
72
-                'obj_id'     => $qst_id,
73
-                'args'       => array('trash' => false),
74
-                'noheader'   => true,
75
-            ),
76
-
77
-            'delete_question' => array(
78
-                'func'       => '_delete_question',
79
-                'capability' => 'ee_delete_question',
80
-                'obj_id'     => $qst_id,
81
-                'noheader'   => true,
82
-            ),
83
-
84
-            'trash_questions' => array(
85
-                'func'       => '_trash_or_restore_questions',
86
-                'capability' => 'ee_delete_questions',
87
-                'args'       => array('trash' => true),
88
-                'noheader'   => true,
89
-            ),
90
-
91
-            'restore_questions' => array(
92
-                'func'       => '_trash_or_restore_questions',
93
-                'capability' => 'ee_delete_questions',
94
-                'args'       => array('trash' => false),
95
-                'noheader'   => true,
96
-            ),
97
-
98
-            'delete_questions' => array(
99
-                'func'       => '_delete_questions',
100
-                'args'       => array(),
101
-                'capability' => 'ee_delete_questions',
102
-                'noheader'   => true,
103
-            ),
104
-
105
-            'add_question_group' => array(
106
-                'func'       => '_edit_question_group',
107
-                'capability' => 'ee_edit_question_groups',
108
-            ),
109
-
110
-            'edit_question_group' => array(
111
-                'func'       => '_edit_question_group',
112
-                'capability' => 'ee_edit_question_group',
113
-                'obj_id'     => $qsg_id,
114
-                'args'       => array('edit'),
115
-            ),
116
-
117
-            'delete_question_groups' => array(
118
-                'func'       => '_delete_question_groups',
119
-                'capability' => 'ee_delete_question_groups',
120
-                'noheader'   => true,
121
-            ),
122
-
123
-            'delete_question_group' => array(
124
-                'func'       => '_delete_question_groups',
125
-                'capability' => 'ee_delete_question_group',
126
-                'obj_id'     => $qsg_id,
127
-                'noheader'   => true,
128
-            ),
129
-
130
-            'trash_question_group' => array(
131
-                'func'       => '_trash_or_restore_question_groups',
132
-                'args'       => array('trash' => true),
133
-                'capability' => 'ee_delete_question_group',
134
-                'obj_id'     => $qsg_id,
135
-                'noheader'   => true,
136
-            ),
137
-
138
-            'restore_question_group' => array(
139
-                'func'       => '_trash_or_restore_question_groups',
140
-                'args'       => array('trash' => false),
141
-                'capability' => 'ee_delete_question_group',
142
-                'obj_id'     => $qsg_id,
143
-                'noheader'   => true,
144
-            ),
145
-
146
-            'insert_question_group' => array(
147
-                'func'       => '_insert_or_update_question_group',
148
-                'args'       => array('new_question_group' => true),
149
-                'capability' => 'ee_edit_question_groups',
150
-                'noheader'   => true,
151
-            ),
152
-
153
-            'update_question_group' => array(
154
-                'func'       => '_insert_or_update_question_group',
155
-                'args'       => array('new_question_group' => false),
156
-                'capability' => 'ee_edit_question_group',
157
-                'obj_id'     => $qsg_id,
158
-                'noheader'   => true,
159
-            ),
160
-
161
-            'trash_question_groups' => array(
162
-                'func'       => '_trash_or_restore_question_groups',
163
-                'args'       => array('trash' => true),
164
-                'capability' => 'ee_delete_question_groups',
165
-                'noheader'   => array('trash' => false),
166
-            ),
167
-
168
-            'restore_question_groups' => array(
169
-                'func'       => '_trash_or_restore_question_groups',
170
-                'args'       => array('trash' => false),
171
-                'capability' => 'ee_delete_question_groups',
172
-                'noheader'   => true,
173
-            ),
174
-
175
-
176
-            'espresso_update_question_group_order' => array(
177
-                'func'       => 'update_question_group_order',
178
-                'capability' => 'ee_edit_question_groups',
179
-                'noheader'   => true,
180
-            ),
181
-
182
-            'view_reg_form_settings' => array(
183
-                'func'       => '_reg_form_settings',
184
-                'capability' => 'manage_options',
185
-            ),
186
-
187
-            'update_reg_form_settings' => array(
188
-                'func'       => '_update_reg_form_settings',
189
-                'capability' => 'manage_options',
190
-                'noheader'   => true,
191
-            ),
192
-        );
193
-        $this->_page_routes = array_merge($this->_page_routes, $new_page_routes);
194
-
195
-        $new_page_config = array(
196
-
197
-            'question_groups' => array(
198
-                'nav'           => array(
199
-                    'label' => esc_html__('Question Groups', 'event_espresso'),
200
-                    'icon' => 'dashicons-forms',
201
-                    'order' => 20,
202
-                ),
203
-                'list_table'    => 'Registration_Form_Question_Groups_Admin_List_Table',
204
-                'help_tabs'     => array(
205
-                    'registration_form_question_groups_help_tab'                           => array(
206
-                        'title'    => esc_html__('Question Groups', 'event_espresso'),
207
-                        'filename' => 'registration_form_question_groups',
208
-                    ),
209
-                    'registration_form_question_groups_table_column_headings_help_tab'     => array(
210
-                        'title'    => esc_html__('Question Groups Table Column Headings', 'event_espresso'),
211
-                        'filename' => 'registration_form_question_groups_table_column_headings',
212
-                    ),
213
-                    'registration_form_question_groups_views_bulk_actions_search_help_tab' => array(
214
-                        'title'    => esc_html__('Question Groups Views & Bulk Actions & Search', 'event_espresso'),
215
-                        'filename' => 'registration_form_question_groups_views_bulk_actions_search',
216
-                    ),
217
-                ),
218
-                'metaboxes'     => $this->_default_espresso_metaboxes,
219
-                'require_nonce' => false,
220
-            ),
221
-
222
-            'add_question' => array(
223
-                'nav'           => array(
224
-                    'label'      => esc_html__('Add Question', 'event_espresso'),
225
-                    'icon' => 'dashicons-plus-alt',
226
-                    'order'      => 15,
227
-                    'persistent' => false,
228
-                ),
229
-                'metaboxes'     => array_merge($this->_default_espresso_metaboxes, array('_publish_post_box')),
230
-                'help_tabs'     => array(
231
-                    'registration_form_add_question_help_tab' => array(
232
-                        'title'    => esc_html__('Add Question', 'event_espresso'),
233
-                        'filename' => 'registration_form_add_question',
234
-                    ),
235
-                ),
236
-                'require_nonce' => false,
237
-            ),
238
-
239
-            'add_question_group' => array(
240
-                'nav'           => array(
241
-                    'label'      => esc_html__('Add Question Group', 'event_espresso'),
242
-                    'icon' => 'dashicons-plus-alt',
243
-                    'order'      => 25,
244
-                    'persistent' => false,
245
-                ),
246
-                'metaboxes'     => array_merge($this->_default_espresso_metaboxes, array('_publish_post_box')),
247
-                'help_tabs'     => array(
248
-                    'registration_form_add_question_group_help_tab' => array(
249
-                        'title'    => esc_html__('Add Question Group', 'event_espresso'),
250
-                        'filename' => 'registration_form_add_question_group',
251
-                    ),
252
-                ),
253
-                'require_nonce' => false,
254
-            ),
255
-
256
-            'edit_question_group' => array(
257
-                'nav'           => array(
258
-                    'label'      => esc_html__('Edit Question Group', 'event_espresso'),
259
-                    'icon' => 'dashicons-edit-large',
260
-                    'order'      => 25,
261
-                    'persistent' => false,
262
-                    'url'        => isset($this->_req_data['question_group_id']) ? add_query_arg(
263
-                        array('question_group_id' => $this->_req_data['question_group_id']),
264
-                        $this->_current_page_view_url
265
-                    ) : $this->_admin_base_url,
266
-                ),
267
-                'metaboxes'     => array_merge($this->_default_espresso_metaboxes, array('_publish_post_box')),
268
-                'help_tabs'     => array(
269
-                    'registration_form_edit_question_group_help_tab' => array(
270
-                        'title'    => esc_html__('Edit Question Group', 'event_espresso'),
271
-                        'filename' => 'registration_form_edit_question_group',
272
-                    ),
273
-                ),
274
-                'require_nonce' => false,
275
-            ),
276
-
277
-            'view_reg_form_settings' => array(
278
-                'nav'           => array(
279
-                    'label' => esc_html__('Reg Form Settings', 'event_espresso'),
280
-                    'icon' => 'dashicons-admin-generic',
281
-                    'order' => 40,
282
-                ),
283
-                'labels'        => array(
284
-                    'publishbox' => esc_html__('Update Settings', 'event_espresso'),
285
-                ),
286
-                'metaboxes'     => array_merge($this->_default_espresso_metaboxes, array('_publish_post_box')),
287
-                'help_tabs'     => array(
288
-                    'registration_form_reg_form_settings_help_tab' => array(
289
-                        'title'    => esc_html__('Registration Form Settings', 'event_espresso'),
290
-                        'filename' => 'registration_form_reg_form_settings',
291
-                    ),
292
-                ),
293
-                'require_nonce' => false,
294
-            ),
295
-
296
-        );
297
-        $this->_page_config = array_merge($this->_page_config, $new_page_config);
298
-
299
-        // change the list table we're going to use so it's the NEW list table!
300
-        $this->_page_config['default']['list_table'] = 'Extend_Registration_Form_Questions_Admin_List_Table';
301
-
302
-
303
-        // additional labels
304
-        $new_labels = array(
305
-            'add_question'          => esc_html__('Add New Question', 'event_espresso'),
306
-            'delete_question'       => esc_html__('Delete Question', 'event_espresso'),
307
-            'add_question_group'    => esc_html__('Add New Question Group', 'event_espresso'),
308
-            'edit_question_group'   => esc_html__('Edit Question Group', 'event_espresso'),
309
-            'delete_question_group' => esc_html__('Delete Question Group', 'event_espresso'),
310
-        );
311
-        $this->_labels['buttons'] = array_merge($this->_labels['buttons'], $new_labels);
312
-    }
313
-
314
-
315
-    /**
316
-     * @return void
317
-     */
318
-    protected function _ajax_hooks()
319
-    {
320
-        add_action('wp_ajax_espresso_update_question_group_order', array($this, 'update_question_group_order'));
321
-    }
322
-
323
-
324
-    /**
325
-     * @return void
326
-     */
327
-    public function load_scripts_styles_question_groups()
328
-    {
329
-        wp_enqueue_script('espresso_ajax_table_sorting');
330
-    }
331
-
332
-
333
-    /**
334
-     * @return void
335
-     */
336
-    public function load_scripts_styles_add_question_group()
337
-    {
338
-        $this->load_scripts_styles_forms();
339
-        $this->load_sortable_question_script();
340
-    }
341
-
342
-
343
-    /**
344
-     * @return void
345
-     */
346
-    public function load_scripts_styles_edit_question_group()
347
-    {
348
-        $this->load_scripts_styles_forms();
349
-        $this->load_sortable_question_script();
350
-    }
351
-
352
-
353
-    /**
354
-     * registers and enqueues script for questions
355
-     *
356
-     * @return void
357
-     */
358
-    public function load_sortable_question_script()
359
-    {
360
-        wp_register_script(
361
-            'ee-question-sortable',
362
-            REGISTRATION_FORM_CAF_ASSETS_URL . 'ee_question_order.js',
363
-            array('jquery-ui-sortable'),
364
-            EVENT_ESPRESSO_VERSION,
365
-            true
366
-        );
367
-        wp_enqueue_script('ee-question-sortable');
368
-    }
369
-
370
-
371
-    /**
372
-     * @return void
373
-     */
374
-    protected function _set_list_table_views_default()
375
-    {
376
-        $this->_views = array(
377
-            'all' => array(
378
-                'slug'        => 'all',
379
-                'label'       => esc_html__('View All Questions', 'event_espresso'),
380
-                'count'       => 0,
381
-                'bulk_action' => array(
382
-                    'trash_questions' => esc_html__('Trash', 'event_espresso'),
383
-                ),
384
-            ),
385
-        );
386
-
387
-        if (
388
-            EE_Registry::instance()->CAP->current_user_can(
389
-                'ee_delete_questions',
390
-                'espresso_registration_form_trash_questions'
391
-            )
392
-        ) {
393
-            $this->_views['trash'] = array(
394
-                'slug'        => 'trash',
395
-                'label'       => esc_html__('Trash', 'event_espresso'),
396
-                'count'       => 0,
397
-                'bulk_action' => array(
398
-                    'delete_questions'  => esc_html__('Delete Permanently', 'event_espresso'),
399
-                    'restore_questions' => esc_html__('Restore', 'event_espresso'),
400
-                ),
401
-            );
402
-        }
403
-    }
404
-
405
-
406
-    /**
407
-     * @return void
408
-     */
409
-    protected function _set_list_table_views_question_groups()
410
-    {
411
-        $this->_views = array(
412
-            'all' => array(
413
-                'slug'        => 'all',
414
-                'label'       => esc_html__('All', 'event_espresso'),
415
-                'count'       => 0,
416
-                'bulk_action' => array(
417
-                    'trash_question_groups' => esc_html__('Trash', 'event_espresso'),
418
-                ),
419
-            ),
420
-        );
421
-
422
-        if (
423
-            EE_Registry::instance()->CAP->current_user_can(
424
-                'ee_delete_question_groups',
425
-                'espresso_registration_form_trash_question_groups'
426
-            )
427
-        ) {
428
-            $this->_views['trash'] = array(
429
-                'slug'        => 'trash',
430
-                'label'       => esc_html__('Trash', 'event_espresso'),
431
-                'count'       => 0,
432
-                'bulk_action' => array(
433
-                    'delete_question_groups'  => esc_html__('Delete Permanently', 'event_espresso'),
434
-                    'restore_question_groups' => esc_html__('Restore', 'event_espresso'),
435
-                ),
436
-            );
437
-        }
438
-    }
439
-
440
-
441
-    /**
442
-     * @return void
443
-     * @throws EE_Error
444
-     * @throws InvalidArgumentException
445
-     * @throws InvalidDataTypeException
446
-     * @throws InvalidInterfaceException
447
-     */
448
-    protected function _questions_overview_list_table()
449
-    {
450
-        $this->_admin_page_title .= ' ' . $this->get_action_link_or_button(
451
-            'add_question',
452
-            'add_question',
453
-            array(),
454
-            'add-new-h2'
455
-        );
456
-        parent::_questions_overview_list_table();
457
-    }
458
-
459
-
460
-    /**
461
-     * @return void
462
-     * @throws DomainException
463
-     * @throws EE_Error
464
-     * @throws InvalidArgumentException
465
-     * @throws InvalidDataTypeException
466
-     * @throws InvalidInterfaceException
467
-     */
468
-    protected function _question_groups_overview_list_table()
469
-    {
470
-        $this->_search_btn_label = esc_html__('Question Groups', 'event_espresso');
471
-        $this->_admin_page_title .= ' ' . $this->get_action_link_or_button(
472
-            'add_question_group',
473
-            'add_question_group',
474
-            array(),
475
-            'add-new-h2'
476
-        );
477
-        $this->display_admin_list_table_page_with_sidebar();
478
-    }
479
-
480
-
481
-    /**
482
-     * @return void
483
-     * @throws EE_Error
484
-     * @throws InvalidArgumentException
485
-     * @throws InvalidDataTypeException
486
-     * @throws InvalidInterfaceException
487
-     */
488
-    protected function _delete_question()
489
-    {
490
-        $success = $this->_delete_items($this->_question_model);
491
-        $this->_redirect_after_action(
492
-            $success,
493
-            $this->_question_model->item_name($success),
494
-            'deleted',
495
-            array('action' => 'default', 'status' => 'all')
496
-        );
497
-    }
498
-
499
-
500
-    /**
501
-     * @return void
502
-     * @throws EE_Error
503
-     * @throws InvalidArgumentException
504
-     * @throws InvalidDataTypeException
505
-     * @throws InvalidInterfaceException
506
-     */
507
-    protected function _delete_questions()
508
-    {
509
-        $success = $this->_delete_items($this->_question_model);
510
-        $this->_redirect_after_action(
511
-            $success,
512
-            $this->_question_model->item_name($success),
513
-            'deleted permanently',
514
-            array('action' => 'default', 'status' => 'trash')
515
-        );
516
-    }
517
-
518
-
519
-    /**
520
-     * Performs the deletion of a single or multiple questions or question groups.
521
-     *
522
-     * @param EEM_Soft_Delete_Base $model
523
-     * @return int number of items deleted permanently
524
-     * @throws EE_Error
525
-     * @throws InvalidArgumentException
526
-     * @throws InvalidDataTypeException
527
-     * @throws InvalidInterfaceException
528
-     */
529
-    private function _delete_items(EEM_Soft_Delete_Base $model)
530
-    {
531
-        $success = 0;
532
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
533
-        if (! empty($this->_req_data['checkbox']) && is_array($this->_req_data['checkbox'])) {
534
-            // if array has more than one element than success message should be plural
535
-            $success = count($this->_req_data['checkbox']) > 1 ? 2 : 1;
536
-            // cycle thru bulk action checkboxes
537
-            while (list($ID, $value) = each($this->_req_data['checkbox'])) {
538
-                if (! $this->_delete_item($ID, $model)) {
539
-                    $success = 0;
540
-                }
541
-            }
542
-        } elseif (! empty($this->_req_data['QSG_ID'])) {
543
-            $success = $this->_delete_item($this->_req_data['QSG_ID'], $model);
544
-        } elseif (! empty($this->_req_data['QST_ID'])) {
545
-            $success = $this->_delete_item($this->_req_data['QST_ID'], $model);
546
-        } else {
547
-            EE_Error::add_error(
548
-                sprintf(
549
-                    esc_html__(
550
-                        "No Questions or Question Groups were selected for deleting. This error usually shows when you've attempted to delete via bulk action but there were no selections.",
551
-                        "event_espresso"
552
-                    )
553
-                ),
554
-                __FILE__,
555
-                __FUNCTION__,
556
-                __LINE__
557
-            );
558
-        }
559
-        return $success;
560
-    }
561
-
562
-
563
-    /**
564
-     * Deletes the specified question (and its associated question options) or question group
565
-     *
566
-     * @param int                  $id
567
-     * @param EEM_Soft_Delete_Base $model
568
-     * @return boolean
569
-     * @throws EE_Error
570
-     * @throws InvalidArgumentException
571
-     * @throws InvalidDataTypeException
572
-     * @throws InvalidInterfaceException
573
-     */
574
-    protected function _delete_item($id, $model)
575
-    {
576
-        if ($model instanceof EEM_Question) {
577
-            EEM_Question_Option::instance()->delete_permanently(array(array('QST_ID' => absint($id))));
578
-        }
579
-        return $model->delete_permanently_by_ID(absint($id));
580
-    }
581
-
582
-
583
-    /******************************    QUESTION GROUPS    ******************************/
584
-
585
-
586
-    /**
587
-     * @param string $type
588
-     * @return void
589
-     * @throws DomainException
590
-     * @throws EE_Error
591
-     * @throws InvalidArgumentException
592
-     * @throws InvalidDataTypeException
593
-     * @throws InvalidInterfaceException
594
-     */
595
-    protected function _edit_question_group($type = 'add')
596
-    {
597
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
598
-        $ID = isset($this->_req_data['QSG_ID']) && ! empty($this->_req_data['QSG_ID'])
599
-            ? absint($this->_req_data['QSG_ID'])
600
-            : false;
601
-
602
-        switch ($this->_req_action) {
603
-            case 'add_question_group':
604
-                $this->_admin_page_title = esc_html__('Add Question Group', 'event_espresso');
605
-                break;
606
-            case 'edit_question_group':
607
-                $this->_admin_page_title = esc_html__('Edit Question Group', 'event_espresso');
608
-                break;
609
-            default:
610
-                $this->_admin_page_title = ucwords(str_replace('_', ' ', $this->_req_action));
611
-        }
612
-        // add ID to title if editing
613
-        $this->_admin_page_title = $ID ? $this->_admin_page_title . ' # ' . $ID : $this->_admin_page_title;
614
-        if ($ID) {
615
-            /** @var EE_Question_Group $questionGroup */
616
-            $questionGroup = $this->_question_group_model->get_one_by_ID($ID);
617
-            $additional_hidden_fields = array('QSG_ID' => array('type' => 'hidden', 'value' => $ID));
618
-            $this->_set_add_edit_form_tags('update_question_group', $additional_hidden_fields);
619
-        } else {
620
-            /** @var EE_Question_Group $questionGroup */
621
-            $questionGroup = EEM_Question_Group::instance()->create_default_object();
622
-            $questionGroup->set_order_to_latest();
623
-            $this->_set_add_edit_form_tags('insert_question_group');
624
-        }
625
-        $this->_template_args['values'] = $this->_yes_no_values;
626
-        $this->_template_args['all_questions'] = $questionGroup->questions_in_and_not_in_group();
627
-        $this->_template_args['QSG_ID'] = $ID ? $ID : true;
628
-        $this->_template_args['question_group'] = $questionGroup;
629
-
630
-        $redirect_URL = add_query_arg(array('action' => 'question_groups'), $this->_admin_base_url);
631
-        $this->_set_publish_post_box_vars('id', $ID, false, $redirect_URL);
632
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
633
-            REGISTRATION_FORM_CAF_TEMPLATE_PATH . 'question_groups_main_meta_box.template.php',
634
-            $this->_template_args,
635
-            true
636
-        );
637
-
638
-        // the details template wrapper
639
-        $this->display_admin_page_with_sidebar();
640
-    }
641
-
642
-
643
-    /**
644
-     * @return void
645
-     * @throws EE_Error
646
-     * @throws InvalidArgumentException
647
-     * @throws InvalidDataTypeException
648
-     * @throws InvalidInterfaceException
649
-     */
650
-    protected function _delete_question_groups()
651
-    {
652
-        $success = $this->_delete_items($this->_question_group_model);
653
-        $this->_redirect_after_action(
654
-            $success,
655
-            $this->_question_group_model->item_name($success),
656
-            'deleted permanently',
657
-            array('action' => 'question_groups', 'status' => 'trash')
658
-        );
659
-    }
660
-
661
-
662
-    /**
663
-     * @param bool $new_question_group
664
-     * @throws EE_Error
665
-     * @throws InvalidArgumentException
666
-     * @throws InvalidDataTypeException
667
-     * @throws InvalidInterfaceException
668
-     */
669
-    protected function _insert_or_update_question_group($new_question_group = true)
670
-    {
671
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
672
-        $set_column_values = $this->_set_column_values_for($this->_question_group_model);
673
-
674
-        // make sure identifier is unique
675
-        $identifier_value = isset($set_column_values['QSG_identifier']) ? $set_column_values['QSG_identifier'] : '';
676
-        $where_values = ['QSG_identifier' => $set_column_values['QSG_identifier']];
677
-        if (! $new_question_group && isset($set_column_values['QSG_ID'])) {
678
-            $where_values['QSG_ID'] = ['!=', $set_column_values['QSG_ID']];
679
-        }
680
-        $identifier_exists = ! empty($identifier_value)
681
-            ? $this->_question_group_model->count([$where_values]) > 0
682
-            : false;
683
-        if ($identifier_exists) {
684
-            $set_column_values['QSG_identifier'] .= uniqid('id', true);
685
-        }
686
-
687
-        if ($new_question_group) {
688
-            $QSG_ID = $this->_question_group_model->insert($set_column_values);
689
-            $success = $QSG_ID ? 1 : 0;
690
-            if ($success === 0) {
691
-                EE_Error::add_error(
692
-                    esc_html__('Something went wrong saving the question group.', 'event_espresso'),
693
-                    __FILE__,
694
-                    __FUNCTION__,
695
-                    __LINE__
696
-                );
697
-                $this->_redirect_after_action(
698
-                    false,
699
-                    '',
700
-                    '',
701
-                    array('action' => 'edit_question_group', 'QSG_ID' => $QSG_ID),
702
-                    true
703
-                );
704
-            }
705
-        } else {
706
-            $QSG_ID = absint($this->_req_data['QSG_ID']);
707
-            unset($set_column_values['QSG_ID']);
708
-            $success = $this->_question_group_model->update($set_column_values, array(array('QSG_ID' => $QSG_ID)));
709
-        }
710
-
711
-        $phone_question_id = EEM_Question::instance()->get_Question_ID_from_system_string(
712
-            EEM_Attendee::system_question_phone
713
-        );
714
-        // update the existing related questions
715
-        // BUT FIRST...  delete the phone question from the Question_Group_Question
716
-        // if it is being added to this question group (therefore removed from the existing group)
717
-        if (isset($this->_req_data['questions'], $this->_req_data['questions'][ $phone_question_id ])) {
718
-            // delete where QST ID = system phone question ID and Question Group ID is NOT this group
719
-            EEM_Question_Group_Question::instance()->delete(
720
-                array(
721
-                    array(
722
-                        'QST_ID' => $phone_question_id,
723
-                        'QSG_ID' => array('!=', $QSG_ID),
724
-                    ),
725
-                )
726
-            );
727
-        }
728
-        /** @type EE_Question_Group $question_group */
729
-        $question_group = $this->_question_group_model->get_one_by_ID($QSG_ID);
730
-        $questions = $question_group->questions();
731
-        // make sure system phone question is added to list of questions for this group
732
-        if (! isset($questions[ $phone_question_id ])) {
733
-            $questions[ $phone_question_id ] = EEM_Question::instance()->get_one_by_ID($phone_question_id);
734
-        }
735
-
736
-        foreach ($questions as $question_ID => $question) {
737
-            // first we always check for order.
738
-            if (! empty($this->_req_data['question_orders'][ $question_ID ])) {
739
-                // update question order
740
-                $question_group->update_question_order(
741
-                    $question_ID,
742
-                    $this->_req_data['question_orders'][ $question_ID ]
743
-                );
744
-            }
745
-
746
-            // then we always check if adding or removing.
747
-            if (isset($this->_req_data['questions'], $this->_req_data['questions'][ $question_ID ])) {
748
-                $question_group->add_question($question_ID);
749
-            } else {
750
-                // not found, remove it (but only if not a system question for the personal group
751
-                // with the exception of lname system question - we allow removal of it)
752
-                if (
753
-                    in_array(
754
-                        $question->system_ID(),
755
-                        EEM_Question::instance()->required_system_questions_in_system_question_group(
756
-                            $question_group->system_group()
757
-                        )
758
-                    )
759
-                ) {
760
-                    continue;
761
-                } else {
762
-                    $question_group->remove_question($question_ID);
763
-                }
764
-            }
765
-        }
766
-        // save new related questions
767
-        if (isset($this->_req_data['questions'])) {
768
-            foreach ($this->_req_data['questions'] as $QST_ID) {
769
-                $question_group->add_question($QST_ID);
770
-                if (isset($this->_req_data['question_orders'][ $QST_ID ])) {
771
-                    $question_group->update_question_order($QST_ID, $this->_req_data['question_orders'][ $QST_ID ]);
772
-                }
773
-            }
774
-        }
775
-
776
-        if ($success !== false) {
777
-            $msg = $new_question_group
778
-                ? sprintf(
779
-                    esc_html__('The %s has been created', 'event_espresso'),
780
-                    $this->_question_group_model->item_name()
781
-                )
782
-                : sprintf(
783
-                    esc_html__(
784
-                        'The %s has been updated',
785
-                        'event_espresso'
786
-                    ),
787
-                    $this->_question_group_model->item_name()
788
-                );
789
-            EE_Error::add_success($msg);
790
-        }
791
-        $this->_redirect_after_action(
792
-            false,
793
-            '',
794
-            '',
795
-            array('action' => 'edit_question_group', 'QSG_ID' => $QSG_ID),
796
-            true
797
-        );
798
-    }
799
-
800
-
801
-    /**
802
-     * duplicates a question and all its question options and redirects to the new question.
803
-     *
804
-     * @return void
805
-     * @throws EE_Error
806
-     * @throws InvalidArgumentException
807
-     * @throws ReflectionException
808
-     * @throws InvalidDataTypeException
809
-     * @throws InvalidInterfaceException
810
-     */
811
-    public function _duplicate_question()
812
-    {
813
-        $question_ID = (int) $this->_req_data['QST_ID'];
814
-        $question = EEM_Question::instance()->get_one_by_ID($question_ID);
815
-        if ($question instanceof EE_Question) {
816
-            $new_question = $question->duplicate();
817
-            if ($new_question instanceof EE_Question) {
818
-                $this->_redirect_after_action(
819
-                    true,
820
-                    esc_html__('Question', 'event_espresso'),
821
-                    esc_html__('Duplicated', 'event_espresso'),
822
-                    array('action' => 'edit_question', 'QST_ID' => $new_question->ID()),
823
-                    true
824
-                );
825
-            } else {
826
-                global $wpdb;
827
-                EE_Error::add_error(
828
-                    sprintf(
829
-                        esc_html__(
830
-                            'Could not duplicate question with ID %1$d because: %2$s',
831
-                            'event_espresso'
832
-                        ),
833
-                        $question_ID,
834
-                        $wpdb->last_error
835
-                    ),
836
-                    __FILE__,
837
-                    __FUNCTION__,
838
-                    __LINE__
839
-                );
840
-                $this->_redirect_after_action(false, '', '', array('action' => 'default'), false);
841
-            }
842
-        } else {
843
-            EE_Error::add_error(
844
-                sprintf(
845
-                    esc_html__(
846
-                        'Could not duplicate question with ID %d because it didn\'t exist!',
847
-                        'event_espresso'
848
-                    ),
849
-                    $question_ID
850
-                ),
851
-                __FILE__,
852
-                __FUNCTION__,
853
-                __LINE__
854
-            );
855
-            $this->_redirect_after_action(false, '', '', array('action' => 'default'), false);
856
-        }
857
-    }
858
-
859
-
860
-    /**
861
-     * @param bool $trash
862
-     * @throws EE_Error
863
-     */
864
-    protected function _trash_or_restore_question_groups($trash = true)
865
-    {
866
-        $this->_trash_or_restore_items($this->_question_group_model, $trash);
867
-    }
868
-
869
-
870
-    /**
871
-     *_trash_question
872
-     *
873
-     * @return void
874
-     * @throws EE_Error
875
-     */
876
-    protected function _trash_question()
877
-    {
878
-        $success = $this->_question_model->delete_by_ID((int) $this->_req_data['QST_ID']);
879
-        $query_args = array('action' => 'default', 'status' => 'all');
880
-        $this->_redirect_after_action($success, $this->_question_model->item_name($success), 'trashed', $query_args);
881
-    }
882
-
883
-
884
-    /**
885
-     * @param bool $trash
886
-     * @throws EE_Error
887
-     */
888
-    protected function _trash_or_restore_questions($trash = true)
889
-    {
890
-        $this->_trash_or_restore_items($this->_question_model, $trash);
891
-    }
892
-
893
-
894
-    /**
895
-     * Internally used to delete or restore items, using the request data. Meant to be
896
-     * flexible between question or question groups
897
-     *
898
-     * @param EEM_Soft_Delete_Base $model
899
-     * @param boolean              $trash whether to trash or restore
900
-     * @throws EE_Error
901
-     */
902
-    private function _trash_or_restore_items(EEM_Soft_Delete_Base $model, $trash = true)
903
-    {
904
-
905
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
906
-
907
-        $success = 1;
908
-        // Checkboxes
909
-        // echo "trash $trash";
910
-        // var_dump($this->_req_data['checkbox']);die;
911
-        if (isset($this->_req_data['checkbox'])) {
912
-            if (! empty($this->_req_data['checkbox']) && is_array($this->_req_data['checkbox'])) {
913
-                // if array has more than one element than success message should be plural
914
-                $success = count($this->_req_data['checkbox']) > 1 ? 2 : 1;
915
-                // cycle thru bulk action checkboxes
916
-                while (list($ID, $value) = each($this->_req_data['checkbox'])) {
917
-                    if (! $model->delete_or_restore_by_ID($trash, absint($ID))) {
918
-                        $success = 0;
919
-                    }
920
-                }
921
-            } else {
922
-                // grab single id and delete
923
-                $ID = absint($this->_req_data['checkbox']);
924
-                if (! $model->delete_or_restore_by_ID($trash, $ID)) {
925
-                    $success = 0;
926
-                }
927
-            }
928
-        } else {
929
-            // delete via trash link
930
-            // grab single id and delete
931
-            $ID = absint($this->_req_data[ $model->primary_key_name() ]);
932
-            if (! $model->delete_or_restore_by_ID($trash, $ID)) {
933
-                $success = 0;
934
-            }
935
-        }
936
-
937
-
938
-        $action = $model instanceof EEM_Question ? 'default' : 'question_groups';// strtolower( $model->item_name(2) );
939
-        // echo "action :$action";
940
-        // $action = 'questions' ? 'default' : $action;
941
-        if ($trash) {
942
-            $action_desc = 'trashed';
943
-            $status = 'trash';
944
-        } else {
945
-            $action_desc = 'restored';
946
-            $status = 'all';
947
-        }
948
-        $this->_redirect_after_action(
949
-            $success,
950
-            $model->item_name($success),
951
-            $action_desc,
952
-            array('action' => $action, 'status' => $status)
953
-        );
954
-    }
955
-
956
-
957
-    /**
958
-     * @param            $per_page
959
-     * @param int        $current_page
960
-     * @param bool|false $count
961
-     * @return EE_Soft_Delete_Base_Class[]|int
962
-     * @throws EE_Error
963
-     * @throws InvalidArgumentException
964
-     * @throws InvalidDataTypeException
965
-     * @throws InvalidInterfaceException
966
-     */
967
-    public function get_trashed_questions($per_page, $current_page = 1, $count = false)
968
-    {
969
-        $query_params = $this->get_query_params(EEM_Question::instance(), $per_page, $current_page);
970
-
971
-        if ($count) {
972
-            // note: this a subclass of EEM_Soft_Delete_Base, so this is actually only getting non-trashed items
973
-            $where = isset($query_params[0]) ? array($query_params[0]) : array();
974
-            $results = $this->_question_model->count_deleted($where);
975
-        } else {
976
-            // note: this a subclass of EEM_Soft_Delete_Base, so this is actually only getting non-trashed items
977
-            $results = $this->_question_model->get_all_deleted($query_params);
978
-        }
979
-        return $results;
980
-    }
981
-
982
-
983
-    /**
984
-     * @param            $per_page
985
-     * @param int        $current_page
986
-     * @param bool|false $count
987
-     * @return EE_Soft_Delete_Base_Class[]|int
988
-     * @throws EE_Error
989
-     * @throws InvalidArgumentException
990
-     * @throws InvalidDataTypeException
991
-     * @throws InvalidInterfaceException
992
-     */
993
-    public function get_question_groups($per_page, $current_page = 1, $count = false)
994
-    {
995
-        $questionGroupModel = EEM_Question_Group::instance();
996
-        $query_params = $this->get_query_params($questionGroupModel, $per_page, $current_page);
997
-        if ($count) {
998
-            $where = isset($query_params[0]) ? array($query_params[0]) : array();
999
-            $results = $questionGroupModel->count($where);
1000
-        } else {
1001
-            $results = $questionGroupModel->get_all($query_params);
1002
-        }
1003
-        return $results;
1004
-    }
1005
-
1006
-
1007
-    /**
1008
-     * @param      $per_page
1009
-     * @param int  $current_page
1010
-     * @param bool $count
1011
-     * @return EE_Soft_Delete_Base_Class[]|int
1012
-     * @throws EE_Error
1013
-     * @throws InvalidArgumentException
1014
-     * @throws InvalidDataTypeException
1015
-     * @throws InvalidInterfaceException
1016
-     */
1017
-    public function get_trashed_question_groups($per_page, $current_page = 1, $count = false)
1018
-    {
1019
-        $questionGroupModel = EEM_Question_Group::instance();
1020
-        $query_params = $this->get_query_params($questionGroupModel, $per_page, $current_page);
1021
-        if ($count) {
1022
-            $where = isset($query_params[0]) ? array($query_params[0]) : array();
1023
-            $query_params['limit'] = null;
1024
-            $results = $questionGroupModel->count_deleted($where);
1025
-        } else {
1026
-            $results = $questionGroupModel->get_all_deleted($query_params);
1027
-        }
1028
-        return $results;
1029
-    }
1030
-
1031
-
1032
-    /**
1033
-     * method for performing updates to question order
1034
-     *
1035
-     * @return void results array
1036
-     * @throws EE_Error
1037
-     * @throws InvalidArgumentException
1038
-     * @throws InvalidDataTypeException
1039
-     * @throws InvalidInterfaceException
1040
-     */
1041
-    public function update_question_group_order()
1042
-    {
1043
-
1044
-        $success = esc_html__('Question group order was updated successfully.', 'event_espresso');
1045
-
1046
-        // grab our row IDs
1047
-        $row_ids = isset($this->_req_data['row_ids']) && ! empty($this->_req_data['row_ids'])
1048
-            ? explode(',', rtrim($this->_req_data['row_ids'], ','))
1049
-            : array();
1050
-
1051
-        $perpage = ! empty($this->_req_data['perpage'])
1052
-            ? (int) $this->_req_data['perpage']
1053
-            : null;
1054
-        $curpage = ! empty($this->_req_data['curpage'])
1055
-            ? (int) $this->_req_data['curpage']
1056
-            : null;
1057
-
1058
-        if (! empty($row_ids)) {
1059
-            // figure out where we start the row_id count at for the current page.
1060
-            $qsgcount = empty($curpage) ? 0 : ($curpage - 1) * $perpage;
1061
-
1062
-            $row_count = count($row_ids);
1063
-            for ($i = 0; $i < $row_count; $i++) {
1064
-                // Update the questions when re-ordering
1065
-                $updated = EEM_Question_Group::instance()->update(
1066
-                    array('QSG_order' => $qsgcount),
1067
-                    array(array('QSG_ID' => $row_ids[ $i ]))
1068
-                );
1069
-                if ($updated === false) {
1070
-                    $success = false;
1071
-                }
1072
-                $qsgcount++;
1073
-            }
1074
-        } else {
1075
-            $success = false;
1076
-        }
1077
-
1078
-        $errors = ! $success
1079
-            ? esc_html__('An error occurred. The question group order was not updated.', 'event_espresso')
1080
-            : false;
1081
-
1082
-        echo wp_json_encode(array('return_data' => false, 'success' => $success, 'errors' => $errors));
1083
-        die();
1084
-    }
1085
-
1086
-
1087
-
1088
-    /***************************************       REGISTRATION SETTINGS       ***************************************/
1089
-
1090
-
1091
-    /**
1092
-     * @throws DomainException
1093
-     * @throws EE_Error
1094
-     * @throws InvalidArgumentException
1095
-     * @throws InvalidDataTypeException
1096
-     * @throws InvalidInterfaceException
1097
-     */
1098
-    protected function _reg_form_settings()
1099
-    {
1100
-        $this->_template_args['values'] = $this->_yes_no_values;
1101
-        add_action(
1102
-            'AHEE__Extend_Registration_Form_Admin_Page___reg_form_settings_template',
1103
-            array($this, 'email_validation_settings_form'),
1104
-            2
1105
-        );
1106
-        add_action(
1107
-            'AHEE__Extend_Registration_Form_Admin_Page___reg_form_settings_template',
1108
-            array($this, 'copy_attendee_info_settings_form'),
1109
-            4
1110
-        );
1111
-        $this->_template_args = (array) apply_filters(
1112
-            'FHEE__Extend_Registration_Form_Admin_Page___reg_form_settings___template_args',
1113
-            $this->_template_args
1114
-        );
1115
-        $this->_set_add_edit_form_tags('update_reg_form_settings');
1116
-        $this->_set_publish_post_box_vars(null, false, false, null, false);
1117
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
1118
-            REGISTRATION_FORM_CAF_TEMPLATE_PATH . 'reg_form_settings.template.php',
1119
-            $this->_template_args,
1120
-            true
1121
-        );
1122
-        $this->display_admin_page_with_sidebar();
1123
-    }
1124
-
1125
-
1126
-    /**
1127
-     * @return void
1128
-     * @throws EE_Error
1129
-     * @throws InvalidArgumentException
1130
-     * @throws ReflectionException
1131
-     * @throws InvalidDataTypeException
1132
-     * @throws InvalidInterfaceException
1133
-     */
1134
-    protected function _update_reg_form_settings()
1135
-    {
1136
-        EE_Registry::instance()->CFG->registration = $this->update_email_validation_settings_form(
1137
-            EE_Registry::instance()->CFG->registration
1138
-        );
1139
-        EE_Registry::instance()->CFG->registration = $this->update_copy_attendee_info_settings_form(
1140
-            EE_Registry::instance()->CFG->registration
1141
-        );
1142
-        EE_Registry::instance()->CFG->registration = apply_filters(
1143
-            'FHEE__Extend_Registration_Form_Admin_Page___update_reg_form_settings__CFG_registration',
1144
-            EE_Registry::instance()->CFG->registration
1145
-        );
1146
-        $success = $this->_update_espresso_configuration(
1147
-            esc_html__('Registration Form Options', 'event_espresso'),
1148
-            EE_Registry::instance()->CFG,
1149
-            __FILE__,
1150
-            __FUNCTION__,
1151
-            __LINE__
1152
-        );
1153
-        $this->_redirect_after_action(
1154
-            $success,
1155
-            esc_html__('Registration Form Options', 'event_espresso'),
1156
-            'updated',
1157
-            array('action' => 'view_reg_form_settings')
1158
-        );
1159
-    }
1160
-
1161
-
1162
-    /**
1163
-     * @return void
1164
-     * @throws EE_Error
1165
-     * @throws InvalidArgumentException
1166
-     * @throws InvalidDataTypeException
1167
-     * @throws InvalidInterfaceException
1168
-     */
1169
-    public function copy_attendee_info_settings_form()
1170
-    {
1171
-        echo wp_kses($this->_copy_attendee_info_settings_form()->get_html(), AllowedTags::getWithFormTags());
1172
-    }
1173
-
1174
-    /**
1175
-     * _copy_attendee_info_settings_form
1176
-     *
1177
-     * @access protected
1178
-     * @return EE_Form_Section_Proper
1179
-     * @throws \EE_Error
1180
-     */
1181
-    protected function _copy_attendee_info_settings_form()
1182
-    {
1183
-        return new EE_Form_Section_Proper(
1184
-            array(
1185
-                'name'            => 'copy_attendee_info_settings',
1186
-                'html_id'         => 'copy_attendee_info_settings',
1187
-                'layout_strategy' => new EE_Admin_Two_Column_Layout(),
1188
-                'subsections'     => apply_filters(
1189
-                    'FHEE__Extend_Registration_Form_Admin_Page___copy_attendee_info_settings_form__form_subsections',
1190
-                    array(
1191
-                        'copy_attendee_info_hdr'   => new EE_Form_Section_HTML(
1192
-                            EEH_HTML::h2(esc_html__('Copy Attendee Info Settings', 'event_espresso'))
1193
-                        ),
1194
-                        'copy_attendee_info' => new EE_Yes_No_Input(
1195
-                            array(
1196
-                                'html_label_text' => esc_html__(
1197
-                                    'Allow copy #1 attendee info to extra attendees?',
1198
-                                    'event_espresso'
1199
-                                ),
1200
-                                'html_help_text'  => esc_html__(
1201
-                                    'Set to yes if you want to enable the copy of #1 attendee info to extra attendees at Registration Form.',
1202
-                                    'event_espresso'
1203
-                                ),
1204
-                                'default'         => EE_Registry::instance()->CFG->registration->copyAttendeeInfo(),
1205
-                                'required'        => false,
1206
-                                'display_html_label_text' => false,
1207
-                            )
1208
-                        ),
1209
-                    )
1210
-                ),
1211
-            )
1212
-        );
1213
-    }
1214
-
1215
-    /**
1216
-     * @param EE_Registration_Config $EE_Registration_Config
1217
-     * @return EE_Registration_Config
1218
-     * @throws EE_Error
1219
-     * @throws InvalidArgumentException
1220
-     * @throws ReflectionException
1221
-     * @throws InvalidDataTypeException
1222
-     * @throws InvalidInterfaceException
1223
-     */
1224
-    public function update_copy_attendee_info_settings_form(EE_Registration_Config $EE_Registration_Config)
1225
-    {
1226
-        $prev_copy_attendee_info = $EE_Registration_Config->copyAttendeeInfo();
1227
-        try {
1228
-            $copy_attendee_info_settings_form = $this->_copy_attendee_info_settings_form();
1229
-            // if not displaying a form, then check for form submission
1230
-            if ($copy_attendee_info_settings_form->was_submitted()) {
1231
-                // capture form data
1232
-                $copy_attendee_info_settings_form->receive_form_submission();
1233
-                // validate form data
1234
-                if ($copy_attendee_info_settings_form->is_valid()) {
1235
-                    // grab validated data from form
1236
-                    $valid_data = $copy_attendee_info_settings_form->valid_data();
1237
-                    if (isset($valid_data['copy_attendee_info'])) {
1238
-                        $EE_Registration_Config->setCopyAttendeeInfo($valid_data['copy_attendee_info']);
1239
-                    } else {
1240
-                        EE_Error::add_error(
1241
-                            esc_html__(
1242
-                                'Invalid or missing Copy Attendee Info settings. Please refresh the form and try again.',
1243
-                                'event_espresso'
1244
-                            ),
1245
-                            __FILE__,
1246
-                            __FUNCTION__,
1247
-                            __LINE__
1248
-                        );
1249
-                    }
1250
-                } else {
1251
-                    if ($copy_attendee_info_settings_form->submission_error_message() !== '') {
1252
-                        EE_Error::add_error(
1253
-                            $copy_attendee_info_settings_form->submission_error_message(),
1254
-                            __FILE__,
1255
-                            __FUNCTION__,
1256
-                            __LINE__
1257
-                        );
1258
-                    }
1259
-                }
1260
-            }
1261
-        } catch (EE_Error $e) {
1262
-            $e->get_error();
1263
-        }
1264
-        return $EE_Registration_Config;
1265
-    }
1266
-
1267
-
1268
-    /**
1269
-     * @return void
1270
-     * @throws EE_Error
1271
-     * @throws InvalidArgumentException
1272
-     * @throws InvalidDataTypeException
1273
-     * @throws InvalidInterfaceException
1274
-     */
1275
-    public function email_validation_settings_form()
1276
-    {
1277
-        echo wp_kses($this->_email_validation_settings_form()->get_html(), AllowedTags::getWithFormTags());
1278
-    }
1279
-
1280
-
1281
-    /**
1282
-     * _email_validation_settings_form
1283
-     *
1284
-     * @access protected
1285
-     * @return EE_Form_Section_Proper
1286
-     * @throws \EE_Error
1287
-     */
1288
-    protected function _email_validation_settings_form()
1289
-    {
1290
-        return new EE_Form_Section_Proper(
1291
-            array(
1292
-                'name'            => 'email_validation_settings',
1293
-                'html_id'         => 'email_validation_settings',
1294
-                'layout_strategy' => new EE_Admin_Two_Column_Layout(),
1295
-                'subsections'     => apply_filters(
1296
-                    'FHEE__Extend_Registration_Form_Admin_Page___email_validation_settings_form__form_subsections',
1297
-                    array(
1298
-                        'email_validation_hdr'   => new EE_Form_Section_HTML(
1299
-                            EEH_HTML::h2(esc_html__('Email Validation Settings', 'event_espresso'))
1300
-                        ),
1301
-                        'email_validation_level' => new EE_Select_Input(
1302
-                            array(
1303
-                                'basic'      => esc_html__('Basic', 'event_espresso'),
1304
-                                'wp_default' => esc_html__('WordPress Default', 'event_espresso'),
1305
-                                'i18n'       => esc_html__('International', 'event_espresso'),
1306
-                                'i18n_dns'   => esc_html__('International + DNS Check', 'event_espresso'),
1307
-                            ),
1308
-                            array(
1309
-                                'html_label_text' => esc_html__('Email Validation Level', 'event_espresso')
1310
-                                                     . EEH_Template::get_help_tab_link('email_validation_info'),
1311
-                                'html_help_text'  => esc_html__(
1312
-                                    'These levels range from basic validation ( ie: [email protected] ) to more advanced checks against international email addresses (ie: üñîçøðé@example.com ) with additional MX and A record checks to confirm the domain actually exists. More information on on each level can be found within the help section.',
1313
-                                    'event_espresso'
1314
-                                ),
1315
-                                'default'         => isset(
1316
-                                    EE_Registry::instance()->CFG->registration->email_validation_level
1317
-                                )
1318
-                                    ? EE_Registry::instance()->CFG->registration->email_validation_level
1319
-                                    : 'wp_default',
1320
-                                'required'        => false,
1321
-                            )
1322
-                        ),
1323
-                    )
1324
-                ),
1325
-            )
1326
-        );
1327
-    }
1328
-
1329
-
1330
-    /**
1331
-     * @param EE_Registration_Config $EE_Registration_Config
1332
-     * @return EE_Registration_Config
1333
-     * @throws EE_Error
1334
-     * @throws InvalidArgumentException
1335
-     * @throws ReflectionException
1336
-     * @throws InvalidDataTypeException
1337
-     * @throws InvalidInterfaceException
1338
-     */
1339
-    public function update_email_validation_settings_form(EE_Registration_Config $EE_Registration_Config)
1340
-    {
1341
-        $prev_email_validation_level = $EE_Registration_Config->email_validation_level;
1342
-        try {
1343
-            $email_validation_settings_form = $this->_email_validation_settings_form();
1344
-            // if not displaying a form, then check for form submission
1345
-            if ($email_validation_settings_form->was_submitted()) {
1346
-                // capture form data
1347
-                $email_validation_settings_form->receive_form_submission();
1348
-                // validate form data
1349
-                if ($email_validation_settings_form->is_valid()) {
1350
-                    // grab validated data from form
1351
-                    $valid_data = $email_validation_settings_form->valid_data();
1352
-                    if (isset($valid_data['email_validation_level'])) {
1353
-                        $email_validation_level = $valid_data['email_validation_level'];
1354
-                        // now if they want to use international email addresses
1355
-                        if ($email_validation_level === 'i18n' || $email_validation_level === 'i18n_dns') {
1356
-                            // in case we need to reset their email validation level,
1357
-                            // make sure that the previous value wasn't already set to one of the i18n options.
1358
-                            if ($prev_email_validation_level === 'i18n' || $prev_email_validation_level === 'i18n_dns') {
1359
-                                // if so, then reset it back to "basic" since that is the only other option that,
1360
-                                // despite offering poor validation, supports i18n email addresses
1361
-                                $prev_email_validation_level = 'basic';
1362
-                            }
1363
-                            // confirm our i18n email validation will work on the server
1364
-                            if (! $this->_verify_pcre_support($EE_Registration_Config, $email_validation_level)) {
1365
-                                // or reset email validation level to previous value
1366
-                                $email_validation_level = $prev_email_validation_level;
1367
-                            }
1368
-                        }
1369
-                        $EE_Registration_Config->email_validation_level = $email_validation_level;
1370
-                    } else {
1371
-                        EE_Error::add_error(
1372
-                            esc_html__(
1373
-                                'Invalid or missing Email Validation settings. Please refresh the form and try again.',
1374
-                                'event_espresso'
1375
-                            ),
1376
-                            __FILE__,
1377
-                            __FUNCTION__,
1378
-                            __LINE__
1379
-                        );
1380
-                    }
1381
-                } else {
1382
-                    if ($email_validation_settings_form->submission_error_message() !== '') {
1383
-                        EE_Error::add_error(
1384
-                            $email_validation_settings_form->submission_error_message(),
1385
-                            __FILE__,
1386
-                            __FUNCTION__,
1387
-                            __LINE__
1388
-                        );
1389
-                    }
1390
-                }
1391
-            }
1392
-        } catch (EE_Error $e) {
1393
-            $e->get_error();
1394
-        }
1395
-        return $EE_Registration_Config;
1396
-    }
1397
-
1398
-
1399
-    /**
1400
-     * confirms that the server's PHP version has the PCRE module enabled,
1401
-     * and that the PCRE version works with our i18n email validation
1402
-     *
1403
-     * @param EE_Registration_Config $EE_Registration_Config
1404
-     * @param string                 $email_validation_level
1405
-     * @return bool
1406
-     */
1407
-    private function _verify_pcre_support(EE_Registration_Config $EE_Registration_Config, $email_validation_level)
1408
-    {
1409
-        // first check that PCRE is enabled
1410
-        if (! defined('PREG_BAD_UTF8_ERROR')) {
1411
-            EE_Error::add_error(
1412
-                sprintf(
1413
-                    esc_html__(
1414
-                        'We\'re sorry, but it appears that your server\'s version of PHP was not compiled with PCRE unicode support.%1$sPlease contact your hosting company and ask them whether the PCRE compiled with your version of PHP on your server can be been built with the "--enable-unicode-properties" and "--enable-utf8" configuration switches to enable more complex regex expressions.%1$sIf they are unable, or unwilling to do so, then your server will not support international email addresses using UTF-8 unicode characters. This means you will either have to lower your email validation level to "Basic" or "WordPress Default", or switch to a hosting company that has/can enable PCRE unicode support on the server.',
1415
-                        'event_espresso'
1416
-                    ),
1417
-                    '<br />'
1418
-                ),
1419
-                __FILE__,
1420
-                __FUNCTION__,
1421
-                __LINE__
1422
-            );
1423
-            return false;
1424
-        } else {
1425
-            // PCRE support is enabled, but let's still
1426
-            // perform a test to see if the server will support it.
1427
-            // but first, save the updated validation level to the config,
1428
-            // so that the validation strategy picks it up.
1429
-            // this will get bumped back down if it doesn't work
1430
-            $EE_Registration_Config->email_validation_level = $email_validation_level;
1431
-            try {
1432
-                $email_validator = new EE_Email_Validation_Strategy();
1433
-                $i18n_email_address = apply_filters(
1434
-                    'FHEE__Extend_Registration_Form_Admin_Page__update_email_validation_settings_form__i18n_email_address',
1435
-                    'jägerjü[email protected]'
1436
-                );
1437
-                $email_validator->validate($i18n_email_address);
1438
-            } catch (Exception $e) {
1439
-                EE_Error::add_error(
1440
-                    sprintf(
1441
-                        esc_html__(
1442
-                            'We\'re sorry, but it appears that your server\'s configuration will not support the "International" or "International + DNS Check" email validation levels.%1$sTo correct this issue, please consult with your hosting company regarding your server\'s PCRE settings.%1$sIt is recommended that your PHP version be configured to use PCRE 8.10 or newer.%1$sMore information regarding PCRE versions and installation can be found here: %2$s',
1443
-                            'event_espresso'
1444
-                        ),
1445
-                        '<br />',
1446
-                        '<a href="http://php.net/manual/en/pcre.installation.php" target="_blank" rel="noopener noreferrer">http://php.net/manual/en/pcre.installation.php</a>'
1447
-                    ),
1448
-                    __FILE__,
1449
-                    __FUNCTION__,
1450
-                    __LINE__
1451
-                );
1452
-                return false;
1453
-            }
1454
-        }
1455
-        return true;
1456
-    }
17
+	/**
18
+	 * @param bool $routing indicate whether we want to just load the object and handle routing or just load the object.
19
+	 */
20
+	public function __construct($routing = true)
21
+	{
22
+		define('REGISTRATION_FORM_CAF_ADMIN', EE_CORE_CAF_ADMIN_EXTEND . 'registration_form/');
23
+		define('REGISTRATION_FORM_CAF_ASSETS_PATH', REGISTRATION_FORM_CAF_ADMIN . 'assets/');
24
+		define('REGISTRATION_FORM_CAF_ASSETS_URL', EE_CORE_CAF_ADMIN_EXTEND_URL . 'registration_form/assets/');
25
+		define('REGISTRATION_FORM_CAF_TEMPLATE_PATH', REGISTRATION_FORM_CAF_ADMIN . 'templates/');
26
+		define('REGISTRATION_FORM_CAF_TEMPLATE_URL', EE_CORE_CAF_ADMIN_EXTEND_URL . 'registration_form/templates/');
27
+		parent::__construct($routing);
28
+	}
29
+
30
+
31
+	/**
32
+	 * @return void
33
+	 */
34
+	protected function _extend_page_config()
35
+	{
36
+		$this->_admin_base_path = REGISTRATION_FORM_CAF_ADMIN;
37
+		$qst_id = ! empty($this->_req_data['QST_ID']) && ! is_array($this->_req_data['QST_ID'])
38
+			? $this->_req_data['QST_ID'] : 0;
39
+		$qsg_id = ! empty($this->_req_data['QSG_ID']) && ! is_array($this->_req_data['QSG_ID'])
40
+			? $this->_req_data['QSG_ID'] : 0;
41
+
42
+		$new_page_routes = array(
43
+			'question_groups'    => array(
44
+				'func'       => '_question_groups_overview_list_table',
45
+				'capability' => 'ee_read_question_groups',
46
+			),
47
+			'add_question'       => array(
48
+				'func'       => '_edit_question',
49
+				'capability' => 'ee_edit_questions',
50
+			),
51
+			'insert_question'    => array(
52
+				'func'       => '_insert_or_update_question',
53
+				'args'       => array('new_question' => true),
54
+				'capability' => 'ee_edit_questions',
55
+				'noheader'   => true,
56
+			),
57
+			'duplicate_question' => array(
58
+				'func'       => '_duplicate_question',
59
+				'capability' => 'ee_edit_questions',
60
+				'noheader'   => true,
61
+			),
62
+			'trash_question'     => array(
63
+				'func'       => '_trash_question',
64
+				'capability' => 'ee_delete_question',
65
+				'obj_id'     => $qst_id,
66
+				'noheader'   => true,
67
+			),
68
+
69
+			'restore_question' => array(
70
+				'func'       => '_trash_or_restore_questions',
71
+				'capability' => 'ee_delete_question',
72
+				'obj_id'     => $qst_id,
73
+				'args'       => array('trash' => false),
74
+				'noheader'   => true,
75
+			),
76
+
77
+			'delete_question' => array(
78
+				'func'       => '_delete_question',
79
+				'capability' => 'ee_delete_question',
80
+				'obj_id'     => $qst_id,
81
+				'noheader'   => true,
82
+			),
83
+
84
+			'trash_questions' => array(
85
+				'func'       => '_trash_or_restore_questions',
86
+				'capability' => 'ee_delete_questions',
87
+				'args'       => array('trash' => true),
88
+				'noheader'   => true,
89
+			),
90
+
91
+			'restore_questions' => array(
92
+				'func'       => '_trash_or_restore_questions',
93
+				'capability' => 'ee_delete_questions',
94
+				'args'       => array('trash' => false),
95
+				'noheader'   => true,
96
+			),
97
+
98
+			'delete_questions' => array(
99
+				'func'       => '_delete_questions',
100
+				'args'       => array(),
101
+				'capability' => 'ee_delete_questions',
102
+				'noheader'   => true,
103
+			),
104
+
105
+			'add_question_group' => array(
106
+				'func'       => '_edit_question_group',
107
+				'capability' => 'ee_edit_question_groups',
108
+			),
109
+
110
+			'edit_question_group' => array(
111
+				'func'       => '_edit_question_group',
112
+				'capability' => 'ee_edit_question_group',
113
+				'obj_id'     => $qsg_id,
114
+				'args'       => array('edit'),
115
+			),
116
+
117
+			'delete_question_groups' => array(
118
+				'func'       => '_delete_question_groups',
119
+				'capability' => 'ee_delete_question_groups',
120
+				'noheader'   => true,
121
+			),
122
+
123
+			'delete_question_group' => array(
124
+				'func'       => '_delete_question_groups',
125
+				'capability' => 'ee_delete_question_group',
126
+				'obj_id'     => $qsg_id,
127
+				'noheader'   => true,
128
+			),
129
+
130
+			'trash_question_group' => array(
131
+				'func'       => '_trash_or_restore_question_groups',
132
+				'args'       => array('trash' => true),
133
+				'capability' => 'ee_delete_question_group',
134
+				'obj_id'     => $qsg_id,
135
+				'noheader'   => true,
136
+			),
137
+
138
+			'restore_question_group' => array(
139
+				'func'       => '_trash_or_restore_question_groups',
140
+				'args'       => array('trash' => false),
141
+				'capability' => 'ee_delete_question_group',
142
+				'obj_id'     => $qsg_id,
143
+				'noheader'   => true,
144
+			),
145
+
146
+			'insert_question_group' => array(
147
+				'func'       => '_insert_or_update_question_group',
148
+				'args'       => array('new_question_group' => true),
149
+				'capability' => 'ee_edit_question_groups',
150
+				'noheader'   => true,
151
+			),
152
+
153
+			'update_question_group' => array(
154
+				'func'       => '_insert_or_update_question_group',
155
+				'args'       => array('new_question_group' => false),
156
+				'capability' => 'ee_edit_question_group',
157
+				'obj_id'     => $qsg_id,
158
+				'noheader'   => true,
159
+			),
160
+
161
+			'trash_question_groups' => array(
162
+				'func'       => '_trash_or_restore_question_groups',
163
+				'args'       => array('trash' => true),
164
+				'capability' => 'ee_delete_question_groups',
165
+				'noheader'   => array('trash' => false),
166
+			),
167
+
168
+			'restore_question_groups' => array(
169
+				'func'       => '_trash_or_restore_question_groups',
170
+				'args'       => array('trash' => false),
171
+				'capability' => 'ee_delete_question_groups',
172
+				'noheader'   => true,
173
+			),
174
+
175
+
176
+			'espresso_update_question_group_order' => array(
177
+				'func'       => 'update_question_group_order',
178
+				'capability' => 'ee_edit_question_groups',
179
+				'noheader'   => true,
180
+			),
181
+
182
+			'view_reg_form_settings' => array(
183
+				'func'       => '_reg_form_settings',
184
+				'capability' => 'manage_options',
185
+			),
186
+
187
+			'update_reg_form_settings' => array(
188
+				'func'       => '_update_reg_form_settings',
189
+				'capability' => 'manage_options',
190
+				'noheader'   => true,
191
+			),
192
+		);
193
+		$this->_page_routes = array_merge($this->_page_routes, $new_page_routes);
194
+
195
+		$new_page_config = array(
196
+
197
+			'question_groups' => array(
198
+				'nav'           => array(
199
+					'label' => esc_html__('Question Groups', 'event_espresso'),
200
+					'icon' => 'dashicons-forms',
201
+					'order' => 20,
202
+				),
203
+				'list_table'    => 'Registration_Form_Question_Groups_Admin_List_Table',
204
+				'help_tabs'     => array(
205
+					'registration_form_question_groups_help_tab'                           => array(
206
+						'title'    => esc_html__('Question Groups', 'event_espresso'),
207
+						'filename' => 'registration_form_question_groups',
208
+					),
209
+					'registration_form_question_groups_table_column_headings_help_tab'     => array(
210
+						'title'    => esc_html__('Question Groups Table Column Headings', 'event_espresso'),
211
+						'filename' => 'registration_form_question_groups_table_column_headings',
212
+					),
213
+					'registration_form_question_groups_views_bulk_actions_search_help_tab' => array(
214
+						'title'    => esc_html__('Question Groups Views & Bulk Actions & Search', 'event_espresso'),
215
+						'filename' => 'registration_form_question_groups_views_bulk_actions_search',
216
+					),
217
+				),
218
+				'metaboxes'     => $this->_default_espresso_metaboxes,
219
+				'require_nonce' => false,
220
+			),
221
+
222
+			'add_question' => array(
223
+				'nav'           => array(
224
+					'label'      => esc_html__('Add Question', 'event_espresso'),
225
+					'icon' => 'dashicons-plus-alt',
226
+					'order'      => 15,
227
+					'persistent' => false,
228
+				),
229
+				'metaboxes'     => array_merge($this->_default_espresso_metaboxes, array('_publish_post_box')),
230
+				'help_tabs'     => array(
231
+					'registration_form_add_question_help_tab' => array(
232
+						'title'    => esc_html__('Add Question', 'event_espresso'),
233
+						'filename' => 'registration_form_add_question',
234
+					),
235
+				),
236
+				'require_nonce' => false,
237
+			),
238
+
239
+			'add_question_group' => array(
240
+				'nav'           => array(
241
+					'label'      => esc_html__('Add Question Group', 'event_espresso'),
242
+					'icon' => 'dashicons-plus-alt',
243
+					'order'      => 25,
244
+					'persistent' => false,
245
+				),
246
+				'metaboxes'     => array_merge($this->_default_espresso_metaboxes, array('_publish_post_box')),
247
+				'help_tabs'     => array(
248
+					'registration_form_add_question_group_help_tab' => array(
249
+						'title'    => esc_html__('Add Question Group', 'event_espresso'),
250
+						'filename' => 'registration_form_add_question_group',
251
+					),
252
+				),
253
+				'require_nonce' => false,
254
+			),
255
+
256
+			'edit_question_group' => array(
257
+				'nav'           => array(
258
+					'label'      => esc_html__('Edit Question Group', 'event_espresso'),
259
+					'icon' => 'dashicons-edit-large',
260
+					'order'      => 25,
261
+					'persistent' => false,
262
+					'url'        => isset($this->_req_data['question_group_id']) ? add_query_arg(
263
+						array('question_group_id' => $this->_req_data['question_group_id']),
264
+						$this->_current_page_view_url
265
+					) : $this->_admin_base_url,
266
+				),
267
+				'metaboxes'     => array_merge($this->_default_espresso_metaboxes, array('_publish_post_box')),
268
+				'help_tabs'     => array(
269
+					'registration_form_edit_question_group_help_tab' => array(
270
+						'title'    => esc_html__('Edit Question Group', 'event_espresso'),
271
+						'filename' => 'registration_form_edit_question_group',
272
+					),
273
+				),
274
+				'require_nonce' => false,
275
+			),
276
+
277
+			'view_reg_form_settings' => array(
278
+				'nav'           => array(
279
+					'label' => esc_html__('Reg Form Settings', 'event_espresso'),
280
+					'icon' => 'dashicons-admin-generic',
281
+					'order' => 40,
282
+				),
283
+				'labels'        => array(
284
+					'publishbox' => esc_html__('Update Settings', 'event_espresso'),
285
+				),
286
+				'metaboxes'     => array_merge($this->_default_espresso_metaboxes, array('_publish_post_box')),
287
+				'help_tabs'     => array(
288
+					'registration_form_reg_form_settings_help_tab' => array(
289
+						'title'    => esc_html__('Registration Form Settings', 'event_espresso'),
290
+						'filename' => 'registration_form_reg_form_settings',
291
+					),
292
+				),
293
+				'require_nonce' => false,
294
+			),
295
+
296
+		);
297
+		$this->_page_config = array_merge($this->_page_config, $new_page_config);
298
+
299
+		// change the list table we're going to use so it's the NEW list table!
300
+		$this->_page_config['default']['list_table'] = 'Extend_Registration_Form_Questions_Admin_List_Table';
301
+
302
+
303
+		// additional labels
304
+		$new_labels = array(
305
+			'add_question'          => esc_html__('Add New Question', 'event_espresso'),
306
+			'delete_question'       => esc_html__('Delete Question', 'event_espresso'),
307
+			'add_question_group'    => esc_html__('Add New Question Group', 'event_espresso'),
308
+			'edit_question_group'   => esc_html__('Edit Question Group', 'event_espresso'),
309
+			'delete_question_group' => esc_html__('Delete Question Group', 'event_espresso'),
310
+		);
311
+		$this->_labels['buttons'] = array_merge($this->_labels['buttons'], $new_labels);
312
+	}
313
+
314
+
315
+	/**
316
+	 * @return void
317
+	 */
318
+	protected function _ajax_hooks()
319
+	{
320
+		add_action('wp_ajax_espresso_update_question_group_order', array($this, 'update_question_group_order'));
321
+	}
322
+
323
+
324
+	/**
325
+	 * @return void
326
+	 */
327
+	public function load_scripts_styles_question_groups()
328
+	{
329
+		wp_enqueue_script('espresso_ajax_table_sorting');
330
+	}
331
+
332
+
333
+	/**
334
+	 * @return void
335
+	 */
336
+	public function load_scripts_styles_add_question_group()
337
+	{
338
+		$this->load_scripts_styles_forms();
339
+		$this->load_sortable_question_script();
340
+	}
341
+
342
+
343
+	/**
344
+	 * @return void
345
+	 */
346
+	public function load_scripts_styles_edit_question_group()
347
+	{
348
+		$this->load_scripts_styles_forms();
349
+		$this->load_sortable_question_script();
350
+	}
351
+
352
+
353
+	/**
354
+	 * registers and enqueues script for questions
355
+	 *
356
+	 * @return void
357
+	 */
358
+	public function load_sortable_question_script()
359
+	{
360
+		wp_register_script(
361
+			'ee-question-sortable',
362
+			REGISTRATION_FORM_CAF_ASSETS_URL . 'ee_question_order.js',
363
+			array('jquery-ui-sortable'),
364
+			EVENT_ESPRESSO_VERSION,
365
+			true
366
+		);
367
+		wp_enqueue_script('ee-question-sortable');
368
+	}
369
+
370
+
371
+	/**
372
+	 * @return void
373
+	 */
374
+	protected function _set_list_table_views_default()
375
+	{
376
+		$this->_views = array(
377
+			'all' => array(
378
+				'slug'        => 'all',
379
+				'label'       => esc_html__('View All Questions', 'event_espresso'),
380
+				'count'       => 0,
381
+				'bulk_action' => array(
382
+					'trash_questions' => esc_html__('Trash', 'event_espresso'),
383
+				),
384
+			),
385
+		);
386
+
387
+		if (
388
+			EE_Registry::instance()->CAP->current_user_can(
389
+				'ee_delete_questions',
390
+				'espresso_registration_form_trash_questions'
391
+			)
392
+		) {
393
+			$this->_views['trash'] = array(
394
+				'slug'        => 'trash',
395
+				'label'       => esc_html__('Trash', 'event_espresso'),
396
+				'count'       => 0,
397
+				'bulk_action' => array(
398
+					'delete_questions'  => esc_html__('Delete Permanently', 'event_espresso'),
399
+					'restore_questions' => esc_html__('Restore', 'event_espresso'),
400
+				),
401
+			);
402
+		}
403
+	}
404
+
405
+
406
+	/**
407
+	 * @return void
408
+	 */
409
+	protected function _set_list_table_views_question_groups()
410
+	{
411
+		$this->_views = array(
412
+			'all' => array(
413
+				'slug'        => 'all',
414
+				'label'       => esc_html__('All', 'event_espresso'),
415
+				'count'       => 0,
416
+				'bulk_action' => array(
417
+					'trash_question_groups' => esc_html__('Trash', 'event_espresso'),
418
+				),
419
+			),
420
+		);
421
+
422
+		if (
423
+			EE_Registry::instance()->CAP->current_user_can(
424
+				'ee_delete_question_groups',
425
+				'espresso_registration_form_trash_question_groups'
426
+			)
427
+		) {
428
+			$this->_views['trash'] = array(
429
+				'slug'        => 'trash',
430
+				'label'       => esc_html__('Trash', 'event_espresso'),
431
+				'count'       => 0,
432
+				'bulk_action' => array(
433
+					'delete_question_groups'  => esc_html__('Delete Permanently', 'event_espresso'),
434
+					'restore_question_groups' => esc_html__('Restore', 'event_espresso'),
435
+				),
436
+			);
437
+		}
438
+	}
439
+
440
+
441
+	/**
442
+	 * @return void
443
+	 * @throws EE_Error
444
+	 * @throws InvalidArgumentException
445
+	 * @throws InvalidDataTypeException
446
+	 * @throws InvalidInterfaceException
447
+	 */
448
+	protected function _questions_overview_list_table()
449
+	{
450
+		$this->_admin_page_title .= ' ' . $this->get_action_link_or_button(
451
+			'add_question',
452
+			'add_question',
453
+			array(),
454
+			'add-new-h2'
455
+		);
456
+		parent::_questions_overview_list_table();
457
+	}
458
+
459
+
460
+	/**
461
+	 * @return void
462
+	 * @throws DomainException
463
+	 * @throws EE_Error
464
+	 * @throws InvalidArgumentException
465
+	 * @throws InvalidDataTypeException
466
+	 * @throws InvalidInterfaceException
467
+	 */
468
+	protected function _question_groups_overview_list_table()
469
+	{
470
+		$this->_search_btn_label = esc_html__('Question Groups', 'event_espresso');
471
+		$this->_admin_page_title .= ' ' . $this->get_action_link_or_button(
472
+			'add_question_group',
473
+			'add_question_group',
474
+			array(),
475
+			'add-new-h2'
476
+		);
477
+		$this->display_admin_list_table_page_with_sidebar();
478
+	}
479
+
480
+
481
+	/**
482
+	 * @return void
483
+	 * @throws EE_Error
484
+	 * @throws InvalidArgumentException
485
+	 * @throws InvalidDataTypeException
486
+	 * @throws InvalidInterfaceException
487
+	 */
488
+	protected function _delete_question()
489
+	{
490
+		$success = $this->_delete_items($this->_question_model);
491
+		$this->_redirect_after_action(
492
+			$success,
493
+			$this->_question_model->item_name($success),
494
+			'deleted',
495
+			array('action' => 'default', 'status' => 'all')
496
+		);
497
+	}
498
+
499
+
500
+	/**
501
+	 * @return void
502
+	 * @throws EE_Error
503
+	 * @throws InvalidArgumentException
504
+	 * @throws InvalidDataTypeException
505
+	 * @throws InvalidInterfaceException
506
+	 */
507
+	protected function _delete_questions()
508
+	{
509
+		$success = $this->_delete_items($this->_question_model);
510
+		$this->_redirect_after_action(
511
+			$success,
512
+			$this->_question_model->item_name($success),
513
+			'deleted permanently',
514
+			array('action' => 'default', 'status' => 'trash')
515
+		);
516
+	}
517
+
518
+
519
+	/**
520
+	 * Performs the deletion of a single or multiple questions or question groups.
521
+	 *
522
+	 * @param EEM_Soft_Delete_Base $model
523
+	 * @return int number of items deleted permanently
524
+	 * @throws EE_Error
525
+	 * @throws InvalidArgumentException
526
+	 * @throws InvalidDataTypeException
527
+	 * @throws InvalidInterfaceException
528
+	 */
529
+	private function _delete_items(EEM_Soft_Delete_Base $model)
530
+	{
531
+		$success = 0;
532
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
533
+		if (! empty($this->_req_data['checkbox']) && is_array($this->_req_data['checkbox'])) {
534
+			// if array has more than one element than success message should be plural
535
+			$success = count($this->_req_data['checkbox']) > 1 ? 2 : 1;
536
+			// cycle thru bulk action checkboxes
537
+			while (list($ID, $value) = each($this->_req_data['checkbox'])) {
538
+				if (! $this->_delete_item($ID, $model)) {
539
+					$success = 0;
540
+				}
541
+			}
542
+		} elseif (! empty($this->_req_data['QSG_ID'])) {
543
+			$success = $this->_delete_item($this->_req_data['QSG_ID'], $model);
544
+		} elseif (! empty($this->_req_data['QST_ID'])) {
545
+			$success = $this->_delete_item($this->_req_data['QST_ID'], $model);
546
+		} else {
547
+			EE_Error::add_error(
548
+				sprintf(
549
+					esc_html__(
550
+						"No Questions or Question Groups were selected for deleting. This error usually shows when you've attempted to delete via bulk action but there were no selections.",
551
+						"event_espresso"
552
+					)
553
+				),
554
+				__FILE__,
555
+				__FUNCTION__,
556
+				__LINE__
557
+			);
558
+		}
559
+		return $success;
560
+	}
561
+
562
+
563
+	/**
564
+	 * Deletes the specified question (and its associated question options) or question group
565
+	 *
566
+	 * @param int                  $id
567
+	 * @param EEM_Soft_Delete_Base $model
568
+	 * @return boolean
569
+	 * @throws EE_Error
570
+	 * @throws InvalidArgumentException
571
+	 * @throws InvalidDataTypeException
572
+	 * @throws InvalidInterfaceException
573
+	 */
574
+	protected function _delete_item($id, $model)
575
+	{
576
+		if ($model instanceof EEM_Question) {
577
+			EEM_Question_Option::instance()->delete_permanently(array(array('QST_ID' => absint($id))));
578
+		}
579
+		return $model->delete_permanently_by_ID(absint($id));
580
+	}
581
+
582
+
583
+	/******************************    QUESTION GROUPS    ******************************/
584
+
585
+
586
+	/**
587
+	 * @param string $type
588
+	 * @return void
589
+	 * @throws DomainException
590
+	 * @throws EE_Error
591
+	 * @throws InvalidArgumentException
592
+	 * @throws InvalidDataTypeException
593
+	 * @throws InvalidInterfaceException
594
+	 */
595
+	protected function _edit_question_group($type = 'add')
596
+	{
597
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
598
+		$ID = isset($this->_req_data['QSG_ID']) && ! empty($this->_req_data['QSG_ID'])
599
+			? absint($this->_req_data['QSG_ID'])
600
+			: false;
601
+
602
+		switch ($this->_req_action) {
603
+			case 'add_question_group':
604
+				$this->_admin_page_title = esc_html__('Add Question Group', 'event_espresso');
605
+				break;
606
+			case 'edit_question_group':
607
+				$this->_admin_page_title = esc_html__('Edit Question Group', 'event_espresso');
608
+				break;
609
+			default:
610
+				$this->_admin_page_title = ucwords(str_replace('_', ' ', $this->_req_action));
611
+		}
612
+		// add ID to title if editing
613
+		$this->_admin_page_title = $ID ? $this->_admin_page_title . ' # ' . $ID : $this->_admin_page_title;
614
+		if ($ID) {
615
+			/** @var EE_Question_Group $questionGroup */
616
+			$questionGroup = $this->_question_group_model->get_one_by_ID($ID);
617
+			$additional_hidden_fields = array('QSG_ID' => array('type' => 'hidden', 'value' => $ID));
618
+			$this->_set_add_edit_form_tags('update_question_group', $additional_hidden_fields);
619
+		} else {
620
+			/** @var EE_Question_Group $questionGroup */
621
+			$questionGroup = EEM_Question_Group::instance()->create_default_object();
622
+			$questionGroup->set_order_to_latest();
623
+			$this->_set_add_edit_form_tags('insert_question_group');
624
+		}
625
+		$this->_template_args['values'] = $this->_yes_no_values;
626
+		$this->_template_args['all_questions'] = $questionGroup->questions_in_and_not_in_group();
627
+		$this->_template_args['QSG_ID'] = $ID ? $ID : true;
628
+		$this->_template_args['question_group'] = $questionGroup;
629
+
630
+		$redirect_URL = add_query_arg(array('action' => 'question_groups'), $this->_admin_base_url);
631
+		$this->_set_publish_post_box_vars('id', $ID, false, $redirect_URL);
632
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
633
+			REGISTRATION_FORM_CAF_TEMPLATE_PATH . 'question_groups_main_meta_box.template.php',
634
+			$this->_template_args,
635
+			true
636
+		);
637
+
638
+		// the details template wrapper
639
+		$this->display_admin_page_with_sidebar();
640
+	}
641
+
642
+
643
+	/**
644
+	 * @return void
645
+	 * @throws EE_Error
646
+	 * @throws InvalidArgumentException
647
+	 * @throws InvalidDataTypeException
648
+	 * @throws InvalidInterfaceException
649
+	 */
650
+	protected function _delete_question_groups()
651
+	{
652
+		$success = $this->_delete_items($this->_question_group_model);
653
+		$this->_redirect_after_action(
654
+			$success,
655
+			$this->_question_group_model->item_name($success),
656
+			'deleted permanently',
657
+			array('action' => 'question_groups', 'status' => 'trash')
658
+		);
659
+	}
660
+
661
+
662
+	/**
663
+	 * @param bool $new_question_group
664
+	 * @throws EE_Error
665
+	 * @throws InvalidArgumentException
666
+	 * @throws InvalidDataTypeException
667
+	 * @throws InvalidInterfaceException
668
+	 */
669
+	protected function _insert_or_update_question_group($new_question_group = true)
670
+	{
671
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
672
+		$set_column_values = $this->_set_column_values_for($this->_question_group_model);
673
+
674
+		// make sure identifier is unique
675
+		$identifier_value = isset($set_column_values['QSG_identifier']) ? $set_column_values['QSG_identifier'] : '';
676
+		$where_values = ['QSG_identifier' => $set_column_values['QSG_identifier']];
677
+		if (! $new_question_group && isset($set_column_values['QSG_ID'])) {
678
+			$where_values['QSG_ID'] = ['!=', $set_column_values['QSG_ID']];
679
+		}
680
+		$identifier_exists = ! empty($identifier_value)
681
+			? $this->_question_group_model->count([$where_values]) > 0
682
+			: false;
683
+		if ($identifier_exists) {
684
+			$set_column_values['QSG_identifier'] .= uniqid('id', true);
685
+		}
686
+
687
+		if ($new_question_group) {
688
+			$QSG_ID = $this->_question_group_model->insert($set_column_values);
689
+			$success = $QSG_ID ? 1 : 0;
690
+			if ($success === 0) {
691
+				EE_Error::add_error(
692
+					esc_html__('Something went wrong saving the question group.', 'event_espresso'),
693
+					__FILE__,
694
+					__FUNCTION__,
695
+					__LINE__
696
+				);
697
+				$this->_redirect_after_action(
698
+					false,
699
+					'',
700
+					'',
701
+					array('action' => 'edit_question_group', 'QSG_ID' => $QSG_ID),
702
+					true
703
+				);
704
+			}
705
+		} else {
706
+			$QSG_ID = absint($this->_req_data['QSG_ID']);
707
+			unset($set_column_values['QSG_ID']);
708
+			$success = $this->_question_group_model->update($set_column_values, array(array('QSG_ID' => $QSG_ID)));
709
+		}
710
+
711
+		$phone_question_id = EEM_Question::instance()->get_Question_ID_from_system_string(
712
+			EEM_Attendee::system_question_phone
713
+		);
714
+		// update the existing related questions
715
+		// BUT FIRST...  delete the phone question from the Question_Group_Question
716
+		// if it is being added to this question group (therefore removed from the existing group)
717
+		if (isset($this->_req_data['questions'], $this->_req_data['questions'][ $phone_question_id ])) {
718
+			// delete where QST ID = system phone question ID and Question Group ID is NOT this group
719
+			EEM_Question_Group_Question::instance()->delete(
720
+				array(
721
+					array(
722
+						'QST_ID' => $phone_question_id,
723
+						'QSG_ID' => array('!=', $QSG_ID),
724
+					),
725
+				)
726
+			);
727
+		}
728
+		/** @type EE_Question_Group $question_group */
729
+		$question_group = $this->_question_group_model->get_one_by_ID($QSG_ID);
730
+		$questions = $question_group->questions();
731
+		// make sure system phone question is added to list of questions for this group
732
+		if (! isset($questions[ $phone_question_id ])) {
733
+			$questions[ $phone_question_id ] = EEM_Question::instance()->get_one_by_ID($phone_question_id);
734
+		}
735
+
736
+		foreach ($questions as $question_ID => $question) {
737
+			// first we always check for order.
738
+			if (! empty($this->_req_data['question_orders'][ $question_ID ])) {
739
+				// update question order
740
+				$question_group->update_question_order(
741
+					$question_ID,
742
+					$this->_req_data['question_orders'][ $question_ID ]
743
+				);
744
+			}
745
+
746
+			// then we always check if adding or removing.
747
+			if (isset($this->_req_data['questions'], $this->_req_data['questions'][ $question_ID ])) {
748
+				$question_group->add_question($question_ID);
749
+			} else {
750
+				// not found, remove it (but only if not a system question for the personal group
751
+				// with the exception of lname system question - we allow removal of it)
752
+				if (
753
+					in_array(
754
+						$question->system_ID(),
755
+						EEM_Question::instance()->required_system_questions_in_system_question_group(
756
+							$question_group->system_group()
757
+						)
758
+					)
759
+				) {
760
+					continue;
761
+				} else {
762
+					$question_group->remove_question($question_ID);
763
+				}
764
+			}
765
+		}
766
+		// save new related questions
767
+		if (isset($this->_req_data['questions'])) {
768
+			foreach ($this->_req_data['questions'] as $QST_ID) {
769
+				$question_group->add_question($QST_ID);
770
+				if (isset($this->_req_data['question_orders'][ $QST_ID ])) {
771
+					$question_group->update_question_order($QST_ID, $this->_req_data['question_orders'][ $QST_ID ]);
772
+				}
773
+			}
774
+		}
775
+
776
+		if ($success !== false) {
777
+			$msg = $new_question_group
778
+				? sprintf(
779
+					esc_html__('The %s has been created', 'event_espresso'),
780
+					$this->_question_group_model->item_name()
781
+				)
782
+				: sprintf(
783
+					esc_html__(
784
+						'The %s has been updated',
785
+						'event_espresso'
786
+					),
787
+					$this->_question_group_model->item_name()
788
+				);
789
+			EE_Error::add_success($msg);
790
+		}
791
+		$this->_redirect_after_action(
792
+			false,
793
+			'',
794
+			'',
795
+			array('action' => 'edit_question_group', 'QSG_ID' => $QSG_ID),
796
+			true
797
+		);
798
+	}
799
+
800
+
801
+	/**
802
+	 * duplicates a question and all its question options and redirects to the new question.
803
+	 *
804
+	 * @return void
805
+	 * @throws EE_Error
806
+	 * @throws InvalidArgumentException
807
+	 * @throws ReflectionException
808
+	 * @throws InvalidDataTypeException
809
+	 * @throws InvalidInterfaceException
810
+	 */
811
+	public function _duplicate_question()
812
+	{
813
+		$question_ID = (int) $this->_req_data['QST_ID'];
814
+		$question = EEM_Question::instance()->get_one_by_ID($question_ID);
815
+		if ($question instanceof EE_Question) {
816
+			$new_question = $question->duplicate();
817
+			if ($new_question instanceof EE_Question) {
818
+				$this->_redirect_after_action(
819
+					true,
820
+					esc_html__('Question', 'event_espresso'),
821
+					esc_html__('Duplicated', 'event_espresso'),
822
+					array('action' => 'edit_question', 'QST_ID' => $new_question->ID()),
823
+					true
824
+				);
825
+			} else {
826
+				global $wpdb;
827
+				EE_Error::add_error(
828
+					sprintf(
829
+						esc_html__(
830
+							'Could not duplicate question with ID %1$d because: %2$s',
831
+							'event_espresso'
832
+						),
833
+						$question_ID,
834
+						$wpdb->last_error
835
+					),
836
+					__FILE__,
837
+					__FUNCTION__,
838
+					__LINE__
839
+				);
840
+				$this->_redirect_after_action(false, '', '', array('action' => 'default'), false);
841
+			}
842
+		} else {
843
+			EE_Error::add_error(
844
+				sprintf(
845
+					esc_html__(
846
+						'Could not duplicate question with ID %d because it didn\'t exist!',
847
+						'event_espresso'
848
+					),
849
+					$question_ID
850
+				),
851
+				__FILE__,
852
+				__FUNCTION__,
853
+				__LINE__
854
+			);
855
+			$this->_redirect_after_action(false, '', '', array('action' => 'default'), false);
856
+		}
857
+	}
858
+
859
+
860
+	/**
861
+	 * @param bool $trash
862
+	 * @throws EE_Error
863
+	 */
864
+	protected function _trash_or_restore_question_groups($trash = true)
865
+	{
866
+		$this->_trash_or_restore_items($this->_question_group_model, $trash);
867
+	}
868
+
869
+
870
+	/**
871
+	 *_trash_question
872
+	 *
873
+	 * @return void
874
+	 * @throws EE_Error
875
+	 */
876
+	protected function _trash_question()
877
+	{
878
+		$success = $this->_question_model->delete_by_ID((int) $this->_req_data['QST_ID']);
879
+		$query_args = array('action' => 'default', 'status' => 'all');
880
+		$this->_redirect_after_action($success, $this->_question_model->item_name($success), 'trashed', $query_args);
881
+	}
882
+
883
+
884
+	/**
885
+	 * @param bool $trash
886
+	 * @throws EE_Error
887
+	 */
888
+	protected function _trash_or_restore_questions($trash = true)
889
+	{
890
+		$this->_trash_or_restore_items($this->_question_model, $trash);
891
+	}
892
+
893
+
894
+	/**
895
+	 * Internally used to delete or restore items, using the request data. Meant to be
896
+	 * flexible between question or question groups
897
+	 *
898
+	 * @param EEM_Soft_Delete_Base $model
899
+	 * @param boolean              $trash whether to trash or restore
900
+	 * @throws EE_Error
901
+	 */
902
+	private function _trash_or_restore_items(EEM_Soft_Delete_Base $model, $trash = true)
903
+	{
904
+
905
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
906
+
907
+		$success = 1;
908
+		// Checkboxes
909
+		// echo "trash $trash";
910
+		// var_dump($this->_req_data['checkbox']);die;
911
+		if (isset($this->_req_data['checkbox'])) {
912
+			if (! empty($this->_req_data['checkbox']) && is_array($this->_req_data['checkbox'])) {
913
+				// if array has more than one element than success message should be plural
914
+				$success = count($this->_req_data['checkbox']) > 1 ? 2 : 1;
915
+				// cycle thru bulk action checkboxes
916
+				while (list($ID, $value) = each($this->_req_data['checkbox'])) {
917
+					if (! $model->delete_or_restore_by_ID($trash, absint($ID))) {
918
+						$success = 0;
919
+					}
920
+				}
921
+			} else {
922
+				// grab single id and delete
923
+				$ID = absint($this->_req_data['checkbox']);
924
+				if (! $model->delete_or_restore_by_ID($trash, $ID)) {
925
+					$success = 0;
926
+				}
927
+			}
928
+		} else {
929
+			// delete via trash link
930
+			// grab single id and delete
931
+			$ID = absint($this->_req_data[ $model->primary_key_name() ]);
932
+			if (! $model->delete_or_restore_by_ID($trash, $ID)) {
933
+				$success = 0;
934
+			}
935
+		}
936
+
937
+
938
+		$action = $model instanceof EEM_Question ? 'default' : 'question_groups';// strtolower( $model->item_name(2) );
939
+		// echo "action :$action";
940
+		// $action = 'questions' ? 'default' : $action;
941
+		if ($trash) {
942
+			$action_desc = 'trashed';
943
+			$status = 'trash';
944
+		} else {
945
+			$action_desc = 'restored';
946
+			$status = 'all';
947
+		}
948
+		$this->_redirect_after_action(
949
+			$success,
950
+			$model->item_name($success),
951
+			$action_desc,
952
+			array('action' => $action, 'status' => $status)
953
+		);
954
+	}
955
+
956
+
957
+	/**
958
+	 * @param            $per_page
959
+	 * @param int        $current_page
960
+	 * @param bool|false $count
961
+	 * @return EE_Soft_Delete_Base_Class[]|int
962
+	 * @throws EE_Error
963
+	 * @throws InvalidArgumentException
964
+	 * @throws InvalidDataTypeException
965
+	 * @throws InvalidInterfaceException
966
+	 */
967
+	public function get_trashed_questions($per_page, $current_page = 1, $count = false)
968
+	{
969
+		$query_params = $this->get_query_params(EEM_Question::instance(), $per_page, $current_page);
970
+
971
+		if ($count) {
972
+			// note: this a subclass of EEM_Soft_Delete_Base, so this is actually only getting non-trashed items
973
+			$where = isset($query_params[0]) ? array($query_params[0]) : array();
974
+			$results = $this->_question_model->count_deleted($where);
975
+		} else {
976
+			// note: this a subclass of EEM_Soft_Delete_Base, so this is actually only getting non-trashed items
977
+			$results = $this->_question_model->get_all_deleted($query_params);
978
+		}
979
+		return $results;
980
+	}
981
+
982
+
983
+	/**
984
+	 * @param            $per_page
985
+	 * @param int        $current_page
986
+	 * @param bool|false $count
987
+	 * @return EE_Soft_Delete_Base_Class[]|int
988
+	 * @throws EE_Error
989
+	 * @throws InvalidArgumentException
990
+	 * @throws InvalidDataTypeException
991
+	 * @throws InvalidInterfaceException
992
+	 */
993
+	public function get_question_groups($per_page, $current_page = 1, $count = false)
994
+	{
995
+		$questionGroupModel = EEM_Question_Group::instance();
996
+		$query_params = $this->get_query_params($questionGroupModel, $per_page, $current_page);
997
+		if ($count) {
998
+			$where = isset($query_params[0]) ? array($query_params[0]) : array();
999
+			$results = $questionGroupModel->count($where);
1000
+		} else {
1001
+			$results = $questionGroupModel->get_all($query_params);
1002
+		}
1003
+		return $results;
1004
+	}
1005
+
1006
+
1007
+	/**
1008
+	 * @param      $per_page
1009
+	 * @param int  $current_page
1010
+	 * @param bool $count
1011
+	 * @return EE_Soft_Delete_Base_Class[]|int
1012
+	 * @throws EE_Error
1013
+	 * @throws InvalidArgumentException
1014
+	 * @throws InvalidDataTypeException
1015
+	 * @throws InvalidInterfaceException
1016
+	 */
1017
+	public function get_trashed_question_groups($per_page, $current_page = 1, $count = false)
1018
+	{
1019
+		$questionGroupModel = EEM_Question_Group::instance();
1020
+		$query_params = $this->get_query_params($questionGroupModel, $per_page, $current_page);
1021
+		if ($count) {
1022
+			$where = isset($query_params[0]) ? array($query_params[0]) : array();
1023
+			$query_params['limit'] = null;
1024
+			$results = $questionGroupModel->count_deleted($where);
1025
+		} else {
1026
+			$results = $questionGroupModel->get_all_deleted($query_params);
1027
+		}
1028
+		return $results;
1029
+	}
1030
+
1031
+
1032
+	/**
1033
+	 * method for performing updates to question order
1034
+	 *
1035
+	 * @return void results array
1036
+	 * @throws EE_Error
1037
+	 * @throws InvalidArgumentException
1038
+	 * @throws InvalidDataTypeException
1039
+	 * @throws InvalidInterfaceException
1040
+	 */
1041
+	public function update_question_group_order()
1042
+	{
1043
+
1044
+		$success = esc_html__('Question group order was updated successfully.', 'event_espresso');
1045
+
1046
+		// grab our row IDs
1047
+		$row_ids = isset($this->_req_data['row_ids']) && ! empty($this->_req_data['row_ids'])
1048
+			? explode(',', rtrim($this->_req_data['row_ids'], ','))
1049
+			: array();
1050
+
1051
+		$perpage = ! empty($this->_req_data['perpage'])
1052
+			? (int) $this->_req_data['perpage']
1053
+			: null;
1054
+		$curpage = ! empty($this->_req_data['curpage'])
1055
+			? (int) $this->_req_data['curpage']
1056
+			: null;
1057
+
1058
+		if (! empty($row_ids)) {
1059
+			// figure out where we start the row_id count at for the current page.
1060
+			$qsgcount = empty($curpage) ? 0 : ($curpage - 1) * $perpage;
1061
+
1062
+			$row_count = count($row_ids);
1063
+			for ($i = 0; $i < $row_count; $i++) {
1064
+				// Update the questions when re-ordering
1065
+				$updated = EEM_Question_Group::instance()->update(
1066
+					array('QSG_order' => $qsgcount),
1067
+					array(array('QSG_ID' => $row_ids[ $i ]))
1068
+				);
1069
+				if ($updated === false) {
1070
+					$success = false;
1071
+				}
1072
+				$qsgcount++;
1073
+			}
1074
+		} else {
1075
+			$success = false;
1076
+		}
1077
+
1078
+		$errors = ! $success
1079
+			? esc_html__('An error occurred. The question group order was not updated.', 'event_espresso')
1080
+			: false;
1081
+
1082
+		echo wp_json_encode(array('return_data' => false, 'success' => $success, 'errors' => $errors));
1083
+		die();
1084
+	}
1085
+
1086
+
1087
+
1088
+	/***************************************       REGISTRATION SETTINGS       ***************************************/
1089
+
1090
+
1091
+	/**
1092
+	 * @throws DomainException
1093
+	 * @throws EE_Error
1094
+	 * @throws InvalidArgumentException
1095
+	 * @throws InvalidDataTypeException
1096
+	 * @throws InvalidInterfaceException
1097
+	 */
1098
+	protected function _reg_form_settings()
1099
+	{
1100
+		$this->_template_args['values'] = $this->_yes_no_values;
1101
+		add_action(
1102
+			'AHEE__Extend_Registration_Form_Admin_Page___reg_form_settings_template',
1103
+			array($this, 'email_validation_settings_form'),
1104
+			2
1105
+		);
1106
+		add_action(
1107
+			'AHEE__Extend_Registration_Form_Admin_Page___reg_form_settings_template',
1108
+			array($this, 'copy_attendee_info_settings_form'),
1109
+			4
1110
+		);
1111
+		$this->_template_args = (array) apply_filters(
1112
+			'FHEE__Extend_Registration_Form_Admin_Page___reg_form_settings___template_args',
1113
+			$this->_template_args
1114
+		);
1115
+		$this->_set_add_edit_form_tags('update_reg_form_settings');
1116
+		$this->_set_publish_post_box_vars(null, false, false, null, false);
1117
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
1118
+			REGISTRATION_FORM_CAF_TEMPLATE_PATH . 'reg_form_settings.template.php',
1119
+			$this->_template_args,
1120
+			true
1121
+		);
1122
+		$this->display_admin_page_with_sidebar();
1123
+	}
1124
+
1125
+
1126
+	/**
1127
+	 * @return void
1128
+	 * @throws EE_Error
1129
+	 * @throws InvalidArgumentException
1130
+	 * @throws ReflectionException
1131
+	 * @throws InvalidDataTypeException
1132
+	 * @throws InvalidInterfaceException
1133
+	 */
1134
+	protected function _update_reg_form_settings()
1135
+	{
1136
+		EE_Registry::instance()->CFG->registration = $this->update_email_validation_settings_form(
1137
+			EE_Registry::instance()->CFG->registration
1138
+		);
1139
+		EE_Registry::instance()->CFG->registration = $this->update_copy_attendee_info_settings_form(
1140
+			EE_Registry::instance()->CFG->registration
1141
+		);
1142
+		EE_Registry::instance()->CFG->registration = apply_filters(
1143
+			'FHEE__Extend_Registration_Form_Admin_Page___update_reg_form_settings__CFG_registration',
1144
+			EE_Registry::instance()->CFG->registration
1145
+		);
1146
+		$success = $this->_update_espresso_configuration(
1147
+			esc_html__('Registration Form Options', 'event_espresso'),
1148
+			EE_Registry::instance()->CFG,
1149
+			__FILE__,
1150
+			__FUNCTION__,
1151
+			__LINE__
1152
+		);
1153
+		$this->_redirect_after_action(
1154
+			$success,
1155
+			esc_html__('Registration Form Options', 'event_espresso'),
1156
+			'updated',
1157
+			array('action' => 'view_reg_form_settings')
1158
+		);
1159
+	}
1160
+
1161
+
1162
+	/**
1163
+	 * @return void
1164
+	 * @throws EE_Error
1165
+	 * @throws InvalidArgumentException
1166
+	 * @throws InvalidDataTypeException
1167
+	 * @throws InvalidInterfaceException
1168
+	 */
1169
+	public function copy_attendee_info_settings_form()
1170
+	{
1171
+		echo wp_kses($this->_copy_attendee_info_settings_form()->get_html(), AllowedTags::getWithFormTags());
1172
+	}
1173
+
1174
+	/**
1175
+	 * _copy_attendee_info_settings_form
1176
+	 *
1177
+	 * @access protected
1178
+	 * @return EE_Form_Section_Proper
1179
+	 * @throws \EE_Error
1180
+	 */
1181
+	protected function _copy_attendee_info_settings_form()
1182
+	{
1183
+		return new EE_Form_Section_Proper(
1184
+			array(
1185
+				'name'            => 'copy_attendee_info_settings',
1186
+				'html_id'         => 'copy_attendee_info_settings',
1187
+				'layout_strategy' => new EE_Admin_Two_Column_Layout(),
1188
+				'subsections'     => apply_filters(
1189
+					'FHEE__Extend_Registration_Form_Admin_Page___copy_attendee_info_settings_form__form_subsections',
1190
+					array(
1191
+						'copy_attendee_info_hdr'   => new EE_Form_Section_HTML(
1192
+							EEH_HTML::h2(esc_html__('Copy Attendee Info Settings', 'event_espresso'))
1193
+						),
1194
+						'copy_attendee_info' => new EE_Yes_No_Input(
1195
+							array(
1196
+								'html_label_text' => esc_html__(
1197
+									'Allow copy #1 attendee info to extra attendees?',
1198
+									'event_espresso'
1199
+								),
1200
+								'html_help_text'  => esc_html__(
1201
+									'Set to yes if you want to enable the copy of #1 attendee info to extra attendees at Registration Form.',
1202
+									'event_espresso'
1203
+								),
1204
+								'default'         => EE_Registry::instance()->CFG->registration->copyAttendeeInfo(),
1205
+								'required'        => false,
1206
+								'display_html_label_text' => false,
1207
+							)
1208
+						),
1209
+					)
1210
+				),
1211
+			)
1212
+		);
1213
+	}
1214
+
1215
+	/**
1216
+	 * @param EE_Registration_Config $EE_Registration_Config
1217
+	 * @return EE_Registration_Config
1218
+	 * @throws EE_Error
1219
+	 * @throws InvalidArgumentException
1220
+	 * @throws ReflectionException
1221
+	 * @throws InvalidDataTypeException
1222
+	 * @throws InvalidInterfaceException
1223
+	 */
1224
+	public function update_copy_attendee_info_settings_form(EE_Registration_Config $EE_Registration_Config)
1225
+	{
1226
+		$prev_copy_attendee_info = $EE_Registration_Config->copyAttendeeInfo();
1227
+		try {
1228
+			$copy_attendee_info_settings_form = $this->_copy_attendee_info_settings_form();
1229
+			// if not displaying a form, then check for form submission
1230
+			if ($copy_attendee_info_settings_form->was_submitted()) {
1231
+				// capture form data
1232
+				$copy_attendee_info_settings_form->receive_form_submission();
1233
+				// validate form data
1234
+				if ($copy_attendee_info_settings_form->is_valid()) {
1235
+					// grab validated data from form
1236
+					$valid_data = $copy_attendee_info_settings_form->valid_data();
1237
+					if (isset($valid_data['copy_attendee_info'])) {
1238
+						$EE_Registration_Config->setCopyAttendeeInfo($valid_data['copy_attendee_info']);
1239
+					} else {
1240
+						EE_Error::add_error(
1241
+							esc_html__(
1242
+								'Invalid or missing Copy Attendee Info settings. Please refresh the form and try again.',
1243
+								'event_espresso'
1244
+							),
1245
+							__FILE__,
1246
+							__FUNCTION__,
1247
+							__LINE__
1248
+						);
1249
+					}
1250
+				} else {
1251
+					if ($copy_attendee_info_settings_form->submission_error_message() !== '') {
1252
+						EE_Error::add_error(
1253
+							$copy_attendee_info_settings_form->submission_error_message(),
1254
+							__FILE__,
1255
+							__FUNCTION__,
1256
+							__LINE__
1257
+						);
1258
+					}
1259
+				}
1260
+			}
1261
+		} catch (EE_Error $e) {
1262
+			$e->get_error();
1263
+		}
1264
+		return $EE_Registration_Config;
1265
+	}
1266
+
1267
+
1268
+	/**
1269
+	 * @return void
1270
+	 * @throws EE_Error
1271
+	 * @throws InvalidArgumentException
1272
+	 * @throws InvalidDataTypeException
1273
+	 * @throws InvalidInterfaceException
1274
+	 */
1275
+	public function email_validation_settings_form()
1276
+	{
1277
+		echo wp_kses($this->_email_validation_settings_form()->get_html(), AllowedTags::getWithFormTags());
1278
+	}
1279
+
1280
+
1281
+	/**
1282
+	 * _email_validation_settings_form
1283
+	 *
1284
+	 * @access protected
1285
+	 * @return EE_Form_Section_Proper
1286
+	 * @throws \EE_Error
1287
+	 */
1288
+	protected function _email_validation_settings_form()
1289
+	{
1290
+		return new EE_Form_Section_Proper(
1291
+			array(
1292
+				'name'            => 'email_validation_settings',
1293
+				'html_id'         => 'email_validation_settings',
1294
+				'layout_strategy' => new EE_Admin_Two_Column_Layout(),
1295
+				'subsections'     => apply_filters(
1296
+					'FHEE__Extend_Registration_Form_Admin_Page___email_validation_settings_form__form_subsections',
1297
+					array(
1298
+						'email_validation_hdr'   => new EE_Form_Section_HTML(
1299
+							EEH_HTML::h2(esc_html__('Email Validation Settings', 'event_espresso'))
1300
+						),
1301
+						'email_validation_level' => new EE_Select_Input(
1302
+							array(
1303
+								'basic'      => esc_html__('Basic', 'event_espresso'),
1304
+								'wp_default' => esc_html__('WordPress Default', 'event_espresso'),
1305
+								'i18n'       => esc_html__('International', 'event_espresso'),
1306
+								'i18n_dns'   => esc_html__('International + DNS Check', 'event_espresso'),
1307
+							),
1308
+							array(
1309
+								'html_label_text' => esc_html__('Email Validation Level', 'event_espresso')
1310
+													 . EEH_Template::get_help_tab_link('email_validation_info'),
1311
+								'html_help_text'  => esc_html__(
1312
+									'These levels range from basic validation ( ie: [email protected] ) to more advanced checks against international email addresses (ie: üñîçøðé@example.com ) with additional MX and A record checks to confirm the domain actually exists. More information on on each level can be found within the help section.',
1313
+									'event_espresso'
1314
+								),
1315
+								'default'         => isset(
1316
+									EE_Registry::instance()->CFG->registration->email_validation_level
1317
+								)
1318
+									? EE_Registry::instance()->CFG->registration->email_validation_level
1319
+									: 'wp_default',
1320
+								'required'        => false,
1321
+							)
1322
+						),
1323
+					)
1324
+				),
1325
+			)
1326
+		);
1327
+	}
1328
+
1329
+
1330
+	/**
1331
+	 * @param EE_Registration_Config $EE_Registration_Config
1332
+	 * @return EE_Registration_Config
1333
+	 * @throws EE_Error
1334
+	 * @throws InvalidArgumentException
1335
+	 * @throws ReflectionException
1336
+	 * @throws InvalidDataTypeException
1337
+	 * @throws InvalidInterfaceException
1338
+	 */
1339
+	public function update_email_validation_settings_form(EE_Registration_Config $EE_Registration_Config)
1340
+	{
1341
+		$prev_email_validation_level = $EE_Registration_Config->email_validation_level;
1342
+		try {
1343
+			$email_validation_settings_form = $this->_email_validation_settings_form();
1344
+			// if not displaying a form, then check for form submission
1345
+			if ($email_validation_settings_form->was_submitted()) {
1346
+				// capture form data
1347
+				$email_validation_settings_form->receive_form_submission();
1348
+				// validate form data
1349
+				if ($email_validation_settings_form->is_valid()) {
1350
+					// grab validated data from form
1351
+					$valid_data = $email_validation_settings_form->valid_data();
1352
+					if (isset($valid_data['email_validation_level'])) {
1353
+						$email_validation_level = $valid_data['email_validation_level'];
1354
+						// now if they want to use international email addresses
1355
+						if ($email_validation_level === 'i18n' || $email_validation_level === 'i18n_dns') {
1356
+							// in case we need to reset their email validation level,
1357
+							// make sure that the previous value wasn't already set to one of the i18n options.
1358
+							if ($prev_email_validation_level === 'i18n' || $prev_email_validation_level === 'i18n_dns') {
1359
+								// if so, then reset it back to "basic" since that is the only other option that,
1360
+								// despite offering poor validation, supports i18n email addresses
1361
+								$prev_email_validation_level = 'basic';
1362
+							}
1363
+							// confirm our i18n email validation will work on the server
1364
+							if (! $this->_verify_pcre_support($EE_Registration_Config, $email_validation_level)) {
1365
+								// or reset email validation level to previous value
1366
+								$email_validation_level = $prev_email_validation_level;
1367
+							}
1368
+						}
1369
+						$EE_Registration_Config->email_validation_level = $email_validation_level;
1370
+					} else {
1371
+						EE_Error::add_error(
1372
+							esc_html__(
1373
+								'Invalid or missing Email Validation settings. Please refresh the form and try again.',
1374
+								'event_espresso'
1375
+							),
1376
+							__FILE__,
1377
+							__FUNCTION__,
1378
+							__LINE__
1379
+						);
1380
+					}
1381
+				} else {
1382
+					if ($email_validation_settings_form->submission_error_message() !== '') {
1383
+						EE_Error::add_error(
1384
+							$email_validation_settings_form->submission_error_message(),
1385
+							__FILE__,
1386
+							__FUNCTION__,
1387
+							__LINE__
1388
+						);
1389
+					}
1390
+				}
1391
+			}
1392
+		} catch (EE_Error $e) {
1393
+			$e->get_error();
1394
+		}
1395
+		return $EE_Registration_Config;
1396
+	}
1397
+
1398
+
1399
+	/**
1400
+	 * confirms that the server's PHP version has the PCRE module enabled,
1401
+	 * and that the PCRE version works with our i18n email validation
1402
+	 *
1403
+	 * @param EE_Registration_Config $EE_Registration_Config
1404
+	 * @param string                 $email_validation_level
1405
+	 * @return bool
1406
+	 */
1407
+	private function _verify_pcre_support(EE_Registration_Config $EE_Registration_Config, $email_validation_level)
1408
+	{
1409
+		// first check that PCRE is enabled
1410
+		if (! defined('PREG_BAD_UTF8_ERROR')) {
1411
+			EE_Error::add_error(
1412
+				sprintf(
1413
+					esc_html__(
1414
+						'We\'re sorry, but it appears that your server\'s version of PHP was not compiled with PCRE unicode support.%1$sPlease contact your hosting company and ask them whether the PCRE compiled with your version of PHP on your server can be been built with the "--enable-unicode-properties" and "--enable-utf8" configuration switches to enable more complex regex expressions.%1$sIf they are unable, or unwilling to do so, then your server will not support international email addresses using UTF-8 unicode characters. This means you will either have to lower your email validation level to "Basic" or "WordPress Default", or switch to a hosting company that has/can enable PCRE unicode support on the server.',
1415
+						'event_espresso'
1416
+					),
1417
+					'<br />'
1418
+				),
1419
+				__FILE__,
1420
+				__FUNCTION__,
1421
+				__LINE__
1422
+			);
1423
+			return false;
1424
+		} else {
1425
+			// PCRE support is enabled, but let's still
1426
+			// perform a test to see if the server will support it.
1427
+			// but first, save the updated validation level to the config,
1428
+			// so that the validation strategy picks it up.
1429
+			// this will get bumped back down if it doesn't work
1430
+			$EE_Registration_Config->email_validation_level = $email_validation_level;
1431
+			try {
1432
+				$email_validator = new EE_Email_Validation_Strategy();
1433
+				$i18n_email_address = apply_filters(
1434
+					'FHEE__Extend_Registration_Form_Admin_Page__update_email_validation_settings_form__i18n_email_address',
1435
+					'jägerjü[email protected]'
1436
+				);
1437
+				$email_validator->validate($i18n_email_address);
1438
+			} catch (Exception $e) {
1439
+				EE_Error::add_error(
1440
+					sprintf(
1441
+						esc_html__(
1442
+							'We\'re sorry, but it appears that your server\'s configuration will not support the "International" or "International + DNS Check" email validation levels.%1$sTo correct this issue, please consult with your hosting company regarding your server\'s PCRE settings.%1$sIt is recommended that your PHP version be configured to use PCRE 8.10 or newer.%1$sMore information regarding PCRE versions and installation can be found here: %2$s',
1443
+							'event_espresso'
1444
+						),
1445
+						'<br />',
1446
+						'<a href="http://php.net/manual/en/pcre.installation.php" target="_blank" rel="noopener noreferrer">http://php.net/manual/en/pcre.installation.php</a>'
1447
+					),
1448
+					__FILE__,
1449
+					__FUNCTION__,
1450
+					__LINE__
1451
+				);
1452
+				return false;
1453
+			}
1454
+		}
1455
+		return true;
1456
+	}
1457 1457
 }
Please login to merge, or discard this patch.
admin_pages/events/Events_Admin_Page.core.php 1 patch
Indentation   +2916 added lines, -2916 removed lines patch added patch discarded remove patch
@@ -16,2923 +16,2923 @@
 block discarded – undo
16 16
  */
17 17
 class Events_Admin_Page extends EE_Admin_Page_CPT
18 18
 {
19
-    /**
20
-     * This will hold the event object for event_details screen.
19
+	/**
20
+	 * This will hold the event object for event_details screen.
21
+	 *
22
+	 * @var EE_Event $_event
23
+	 */
24
+	protected $_event;
25
+
26
+
27
+	/**
28
+	 * This will hold the category object for category_details screen.
29
+	 *
30
+	 * @var stdClass $_category
31
+	 */
32
+	protected $_category;
33
+
34
+
35
+	/**
36
+	 * This will hold the event model instance
37
+	 *
38
+	 * @var EEM_Event $_event_model
39
+	 */
40
+	protected $_event_model;
41
+
42
+
43
+	/**
44
+	 * @var EE_Event
45
+	 */
46
+	protected $_cpt_model_obj = false;
47
+
48
+
49
+	/**
50
+	 * @var NodeGroupDao
51
+	 */
52
+	protected $model_obj_node_group_persister;
53
+
54
+	/**
55
+	 * @var AdvancedEditorAdminFormSection
56
+	 */
57
+	protected $advanced_editor_admin_form;
58
+
59
+
60
+	/**
61
+	 * Initialize page props for this admin page group.
62
+	 */
63
+	protected function _init_page_props()
64
+	{
65
+		$this->page_slug        = EVENTS_PG_SLUG;
66
+		$this->page_label       = EVENTS_LABEL;
67
+		$this->_admin_base_url  = EVENTS_ADMIN_URL;
68
+		$this->_admin_base_path = EVENTS_ADMIN;
69
+		$this->_cpt_model_names = [
70
+			'create_new' => 'EEM_Event',
71
+			'edit'       => 'EEM_Event',
72
+		];
73
+		$this->_cpt_edit_routes = [
74
+			'espresso_events' => 'edit',
75
+		];
76
+		add_action(
77
+			'AHEE__EE_Admin_Page_CPT__set_model_object__after_set_object',
78
+			[$this, 'verify_event_edit'],
79
+			10,
80
+			2
81
+		);
82
+	}
83
+
84
+
85
+	/**
86
+	 * Sets the ajax hooks used for this admin page group.
87
+	 */
88
+	protected function _ajax_hooks()
89
+	{
90
+		add_action('wp_ajax_ee_save_timezone_setting', [$this, 'saveTimezoneString']);
91
+	}
92
+
93
+
94
+	/**
95
+	 * Sets the page properties for this admin page group.
96
+	 */
97
+	protected function _define_page_props()
98
+	{
99
+		$this->_admin_page_title = EVENTS_LABEL;
100
+		$this->_labels           = [
101
+			'buttons'      => [
102
+				'add'             => esc_html__('Add New Event', 'event_espresso'),
103
+				'edit'            => esc_html__('Edit Event', 'event_espresso'),
104
+				'delete'          => esc_html__('Delete Event', 'event_espresso'),
105
+				'add_category'    => esc_html__('Add New Category', 'event_espresso'),
106
+				'edit_category'   => esc_html__('Edit Category', 'event_espresso'),
107
+				'delete_category' => esc_html__('Delete Category', 'event_espresso'),
108
+			],
109
+			'editor_title' => [
110
+				'espresso_events' => esc_html__('Enter event title here', 'event_espresso'),
111
+			],
112
+			'publishbox'   => [
113
+				'create_new'        => esc_html__('Save New Event', 'event_espresso'),
114
+				'edit'              => esc_html__('Update Event', 'event_espresso'),
115
+				'add_category'      => esc_html__('Save New Category', 'event_espresso'),
116
+				'edit_category'     => esc_html__('Update Category', 'event_espresso'),
117
+				'template_settings' => esc_html__('Update Settings', 'event_espresso'),
118
+			],
119
+		];
120
+	}
121
+
122
+
123
+	/**
124
+	 * Sets the page routes property for this admin page group.
125
+	 */
126
+	protected function _set_page_routes()
127
+	{
128
+		// load formatter helper
129
+		// load field generator helper
130
+		// is there a evt_id in the request?
131
+		$EVT_ID = $this->request->getRequestParam('EVT_ID', 0, 'int');
132
+		$EVT_ID = $this->request->getRequestParam('post', $EVT_ID, 'int');
133
+
134
+		$this->_page_routes = [
135
+			'default'                       => [
136
+				'func'       => '_events_overview_list_table',
137
+				'capability' => 'ee_read_events',
138
+			],
139
+			'create_new'                    => [
140
+				'func'       => '_create_new_cpt_item',
141
+				'capability' => 'ee_edit_events',
142
+			],
143
+			'edit'                          => [
144
+				'func'       => '_edit_cpt_item',
145
+				'capability' => 'ee_edit_event',
146
+				'obj_id'     => $EVT_ID,
147
+			],
148
+			'copy_event'                    => [
149
+				'func'       => '_copy_events',
150
+				'capability' => 'ee_edit_event',
151
+				'obj_id'     => $EVT_ID,
152
+				'noheader'   => true,
153
+			],
154
+			'trash_event'                   => [
155
+				'func'       => '_trash_or_restore_event',
156
+				'args'       => ['event_status' => 'trash'],
157
+				'capability' => 'ee_delete_event',
158
+				'obj_id'     => $EVT_ID,
159
+				'noheader'   => true,
160
+			],
161
+			'trash_events'                  => [
162
+				'func'       => '_trash_or_restore_events',
163
+				'args'       => ['event_status' => 'trash'],
164
+				'capability' => 'ee_delete_events',
165
+				'noheader'   => true,
166
+			],
167
+			'restore_event'                 => [
168
+				'func'       => '_trash_or_restore_event',
169
+				'args'       => ['event_status' => 'draft'],
170
+				'capability' => 'ee_delete_event',
171
+				'obj_id'     => $EVT_ID,
172
+				'noheader'   => true,
173
+			],
174
+			'restore_events'                => [
175
+				'func'       => '_trash_or_restore_events',
176
+				'args'       => ['event_status' => 'draft'],
177
+				'capability' => 'ee_delete_events',
178
+				'noheader'   => true,
179
+			],
180
+			'delete_event'                  => [
181
+				'func'       => '_delete_event',
182
+				'capability' => 'ee_delete_event',
183
+				'obj_id'     => $EVT_ID,
184
+				'noheader'   => true,
185
+			],
186
+			'delete_events'                 => [
187
+				'func'       => '_delete_events',
188
+				'capability' => 'ee_delete_events',
189
+				'noheader'   => true,
190
+			],
191
+			'view_report'                   => [
192
+				'func'       => '_view_report',
193
+				'capability' => 'ee_edit_events',
194
+			],
195
+			'default_event_settings'        => [
196
+				'func'       => '_default_event_settings',
197
+				'capability' => 'manage_options',
198
+			],
199
+			'update_default_event_settings' => [
200
+				'func'       => '_update_default_event_settings',
201
+				'capability' => 'manage_options',
202
+				'noheader'   => true,
203
+			],
204
+			'template_settings'             => [
205
+				'func'       => '_template_settings',
206
+				'capability' => 'manage_options',
207
+			],
208
+			// event category tab related
209
+			'add_category'                  => [
210
+				'func'       => '_category_details',
211
+				'capability' => 'ee_edit_event_category',
212
+				'args'       => ['add'],
213
+			],
214
+			'edit_category'                 => [
215
+				'func'       => '_category_details',
216
+				'capability' => 'ee_edit_event_category',
217
+				'args'       => ['edit'],
218
+			],
219
+			'delete_categories'             => [
220
+				'func'       => '_delete_categories',
221
+				'capability' => 'ee_delete_event_category',
222
+				'noheader'   => true,
223
+			],
224
+			'delete_category'               => [
225
+				'func'       => '_delete_categories',
226
+				'capability' => 'ee_delete_event_category',
227
+				'noheader'   => true,
228
+			],
229
+			'insert_category'               => [
230
+				'func'       => '_insert_or_update_category',
231
+				'args'       => ['new_category' => true],
232
+				'capability' => 'ee_edit_event_category',
233
+				'noheader'   => true,
234
+			],
235
+			'update_category'               => [
236
+				'func'       => '_insert_or_update_category',
237
+				'args'       => ['new_category' => false],
238
+				'capability' => 'ee_edit_event_category',
239
+				'noheader'   => true,
240
+			],
241
+			'category_list'                 => [
242
+				'func'       => '_category_list_table',
243
+				'capability' => 'ee_manage_event_categories',
244
+			],
245
+			'preview_deletion'              => [
246
+				'func'       => 'previewDeletion',
247
+				'capability' => 'ee_delete_events',
248
+			],
249
+			'confirm_deletion'              => [
250
+				'func'       => 'confirmDeletion',
251
+				'capability' => 'ee_delete_events',
252
+				'noheader'   => true,
253
+			],
254
+		];
255
+	}
256
+
257
+
258
+	/**
259
+	 * Set the _page_config property for this admin page group.
260
+	 */
261
+	protected function _set_page_config()
262
+	{
263
+		$post_id            = $this->request->getRequestParam('post', 0, 'int');
264
+		$EVT_CAT_ID         = $this->request->getRequestParam('EVT_CAT_ID', 0, 'int');
265
+		$this->_page_config = [
266
+			'default'                => [
267
+				'nav'           => [
268
+					'label' => esc_html__('Overview', 'event_espresso'),
269
+					'icon' => 'dashicons-list-view',
270
+					'order' => 10,
271
+				],
272
+				'list_table'    => 'Events_Admin_List_Table',
273
+				'help_tabs'     => [
274
+					'events_overview_help_tab'                       => [
275
+						'title'    => esc_html__('Events Overview', 'event_espresso'),
276
+						'filename' => 'events_overview',
277
+					],
278
+					'events_overview_table_column_headings_help_tab' => [
279
+						'title'    => esc_html__('Events Overview Table Column Headings', 'event_espresso'),
280
+						'filename' => 'events_overview_table_column_headings',
281
+					],
282
+					'events_overview_filters_help_tab'               => [
283
+						'title'    => esc_html__('Events Overview Filters', 'event_espresso'),
284
+						'filename' => 'events_overview_filters',
285
+					],
286
+					'events_overview_view_help_tab'                  => [
287
+						'title'    => esc_html__('Events Overview Views', 'event_espresso'),
288
+						'filename' => 'events_overview_views',
289
+					],
290
+					'events_overview_other_help_tab'                 => [
291
+						'title'    => esc_html__('Events Overview Other', 'event_espresso'),
292
+						'filename' => 'events_overview_other',
293
+					],
294
+				],
295
+				'require_nonce' => false,
296
+			],
297
+			'create_new'             => [
298
+				'nav'           => [
299
+					'label'      => esc_html__('Add New Event', 'event_espresso'),
300
+					'icon' => 'dashicons-plus-alt',
301
+					'order'      => 15,
302
+					'persistent' => false,
303
+				],
304
+				'metaboxes'     => ['_register_event_editor_meta_boxes'],
305
+				'help_tabs'     => [
306
+					'event_editor_help_tab'                            => [
307
+						'title'    => esc_html__('Event Editor', 'event_espresso'),
308
+						'filename' => 'event_editor',
309
+					],
310
+					'event_editor_title_richtexteditor_help_tab'       => [
311
+						'title'    => esc_html__('Event Title & Rich Text Editor', 'event_espresso'),
312
+						'filename' => 'event_editor_title_richtexteditor',
313
+					],
314
+					'event_editor_venue_details_help_tab'              => [
315
+						'title'    => esc_html__('Event Venue Details', 'event_espresso'),
316
+						'filename' => 'event_editor_venue_details',
317
+					],
318
+					'event_editor_event_datetimes_help_tab'            => [
319
+						'title'    => esc_html__('Event Datetimes', 'event_espresso'),
320
+						'filename' => 'event_editor_event_datetimes',
321
+					],
322
+					'event_editor_event_tickets_help_tab'              => [
323
+						'title'    => esc_html__('Event Tickets', 'event_espresso'),
324
+						'filename' => 'event_editor_event_tickets',
325
+					],
326
+					'event_editor_event_registration_options_help_tab' => [
327
+						'title'    => esc_html__('Event Registration Options', 'event_espresso'),
328
+						'filename' => 'event_editor_event_registration_options',
329
+					],
330
+					'event_editor_tags_categories_help_tab'            => [
331
+						'title'    => esc_html__('Event Tags & Categories', 'event_espresso'),
332
+						'filename' => 'event_editor_tags_categories',
333
+					],
334
+					'event_editor_questions_registrants_help_tab'      => [
335
+						'title'    => esc_html__('Questions for Registrants', 'event_espresso'),
336
+						'filename' => 'event_editor_questions_registrants',
337
+					],
338
+					'event_editor_save_new_event_help_tab'             => [
339
+						'title'    => esc_html__('Save New Event', 'event_espresso'),
340
+						'filename' => 'event_editor_save_new_event',
341
+					],
342
+					'event_editor_other_help_tab'                      => [
343
+						'title'    => esc_html__('Event Other', 'event_espresso'),
344
+						'filename' => 'event_editor_other',
345
+					],
346
+				],
347
+				'qtips'         => ['EE_Event_Editor_Decaf_Tips'],
348
+				'require_nonce' => false,
349
+			],
350
+			'edit'                   => [
351
+				'nav'           => [
352
+					'label'      => esc_html__('Edit Event', 'event_espresso'),
353
+					'icon' => 'dashicons-edit',
354
+					'order'      => 15,
355
+					'persistent' => false,
356
+					'url'        => $post_id
357
+						? EE_Admin_Page::add_query_args_and_nonce(
358
+							['post' => $post_id, 'action' => 'edit'],
359
+							$this->_current_page_view_url
360
+						)
361
+						: $this->_admin_base_url,
362
+				],
363
+				'metaboxes'     => ['_register_event_editor_meta_boxes'],
364
+				'help_tabs'     => [
365
+					'event_editor_help_tab'                            => [
366
+						'title'    => esc_html__('Event Editor', 'event_espresso'),
367
+						'filename' => 'event_editor',
368
+					],
369
+					'event_editor_title_richtexteditor_help_tab'       => [
370
+						'title'    => esc_html__('Event Title & Rich Text Editor', 'event_espresso'),
371
+						'filename' => 'event_editor_title_richtexteditor',
372
+					],
373
+					'event_editor_venue_details_help_tab'              => [
374
+						'title'    => esc_html__('Event Venue Details', 'event_espresso'),
375
+						'filename' => 'event_editor_venue_details',
376
+					],
377
+					'event_editor_event_datetimes_help_tab'            => [
378
+						'title'    => esc_html__('Event Datetimes', 'event_espresso'),
379
+						'filename' => 'event_editor_event_datetimes',
380
+					],
381
+					'event_editor_event_tickets_help_tab'              => [
382
+						'title'    => esc_html__('Event Tickets', 'event_espresso'),
383
+						'filename' => 'event_editor_event_tickets',
384
+					],
385
+					'event_editor_event_registration_options_help_tab' => [
386
+						'title'    => esc_html__('Event Registration Options', 'event_espresso'),
387
+						'filename' => 'event_editor_event_registration_options',
388
+					],
389
+					'event_editor_tags_categories_help_tab'            => [
390
+						'title'    => esc_html__('Event Tags & Categories', 'event_espresso'),
391
+						'filename' => 'event_editor_tags_categories',
392
+					],
393
+					'event_editor_questions_registrants_help_tab'      => [
394
+						'title'    => esc_html__('Questions for Registrants', 'event_espresso'),
395
+						'filename' => 'event_editor_questions_registrants',
396
+					],
397
+					'event_editor_save_new_event_help_tab'             => [
398
+						'title'    => esc_html__('Save New Event', 'event_espresso'),
399
+						'filename' => 'event_editor_save_new_event',
400
+					],
401
+					'event_editor_other_help_tab'                      => [
402
+						'title'    => esc_html__('Event Other', 'event_espresso'),
403
+						'filename' => 'event_editor_other',
404
+					],
405
+				],
406
+				'require_nonce' => false,
407
+			],
408
+			'default_event_settings' => [
409
+				'nav'           => [
410
+					'label' => esc_html__('Default Settings', 'event_espresso'),
411
+					'icon' => 'dashicons-admin-generic',
412
+					'order' => 40,
413
+				],
414
+				'metaboxes'     => array_merge(['_publish_post_box'], $this->_default_espresso_metaboxes),
415
+				'labels'        => [
416
+					'publishbox' => esc_html__('Update Settings', 'event_espresso'),
417
+				],
418
+				'help_tabs'     => [
419
+					'default_settings_help_tab'        => [
420
+						'title'    => esc_html__('Default Event Settings', 'event_espresso'),
421
+						'filename' => 'events_default_settings',
422
+					],
423
+					'default_settings_status_help_tab' => [
424
+						'title'    => esc_html__('Default Registration Status', 'event_espresso'),
425
+						'filename' => 'events_default_settings_status',
426
+					],
427
+					'default_maximum_tickets_help_tab' => [
428
+						'title'    => esc_html__('Default Maximum Tickets Per Order', 'event_espresso'),
429
+						'filename' => 'events_default_settings_max_tickets',
430
+					],
431
+				],
432
+				'require_nonce' => false,
433
+			],
434
+			// template settings
435
+			'template_settings'      => [
436
+				'nav'           => [
437
+					'label' => esc_html__('Templates', 'event_espresso'),
438
+					'icon' => 'dashicons-layout',
439
+					'order' => 30,
440
+				],
441
+				'metaboxes'     => $this->_default_espresso_metaboxes,
442
+				'help_tabs'     => [
443
+					'general_settings_templates_help_tab' => [
444
+						'title'    => esc_html__('Templates', 'event_espresso'),
445
+						'filename' => 'general_settings_templates',
446
+					],
447
+				],
448
+				'require_nonce' => false,
449
+			],
450
+			// event category stuff
451
+			'add_category'           => [
452
+				'nav'           => [
453
+					'label'      => esc_html__('Add Category', 'event_espresso'),
454
+					'icon' => 'dashicons-plus-alt',
455
+					'order'      => 25,
456
+					'persistent' => false,
457
+				],
458
+				'help_tabs'     => [
459
+					'add_category_help_tab' => [
460
+						'title'    => esc_html__('Add New Event Category', 'event_espresso'),
461
+						'filename' => 'events_add_category',
462
+					],
463
+				],
464
+				'metaboxes'     => ['_publish_post_box'],
465
+				'require_nonce' => false,
466
+			],
467
+			'edit_category'          => [
468
+				'nav'           => [
469
+					'label'      => esc_html__('Edit Category', 'event_espresso'),
470
+					'icon' => 'dashicons-edit',
471
+					'order'      => 25,
472
+					'persistent' => false,
473
+					'url'        => $EVT_CAT_ID
474
+						? add_query_arg(
475
+							['EVT_CAT_ID' => $EVT_CAT_ID],
476
+							$this->_current_page_view_url
477
+						)
478
+						: $this->_admin_base_url,
479
+				],
480
+				'help_tabs'     => [
481
+					'edit_category_help_tab' => [
482
+						'title'    => esc_html__('Edit Event Category', 'event_espresso'),
483
+						'filename' => 'events_edit_category',
484
+					],
485
+				],
486
+				'metaboxes'     => ['_publish_post_box'],
487
+				'require_nonce' => false,
488
+			],
489
+			'category_list'          => [
490
+				'nav'           => [
491
+					'label' => esc_html__('Categories', 'event_espresso'),
492
+					'icon' => 'dashicons-networking',
493
+					'order' => 20,
494
+				],
495
+				'list_table'    => 'Event_Categories_Admin_List_Table',
496
+				'help_tabs'     => [
497
+					'events_categories_help_tab'                       => [
498
+						'title'    => esc_html__('Event Categories', 'event_espresso'),
499
+						'filename' => 'events_categories',
500
+					],
501
+					'events_categories_table_column_headings_help_tab' => [
502
+						'title'    => esc_html__('Event Categories Table Column Headings', 'event_espresso'),
503
+						'filename' => 'events_categories_table_column_headings',
504
+					],
505
+					'events_categories_view_help_tab'                  => [
506
+						'title'    => esc_html__('Event Categories Views', 'event_espresso'),
507
+						'filename' => 'events_categories_views',
508
+					],
509
+					'events_categories_other_help_tab'                 => [
510
+						'title'    => esc_html__('Event Categories Other', 'event_espresso'),
511
+						'filename' => 'events_categories_other',
512
+					],
513
+				],
514
+				'metaboxes'     => $this->_default_espresso_metaboxes,
515
+				'require_nonce' => false,
516
+			],
517
+			'preview_deletion'       => [
518
+				'nav'           => [
519
+					'label'      => esc_html__('Preview Deletion', 'event_espresso'),
520
+					'icon' => 'dashicons-remove',
521
+					'order'      => 15,
522
+					'persistent' => false,
523
+					'url'        => '',
524
+				],
525
+				'require_nonce' => false,
526
+			],
527
+		];
528
+	}
529
+
530
+
531
+	/**
532
+	 * Used to register any global screen options if necessary for every route in this admin page group.
533
+	 */
534
+	protected function _add_screen_options()
535
+	{
536
+	}
537
+
538
+
539
+	/**
540
+	 * Implementing the screen options for the 'default' route.
541
+	 *
542
+	 * @throws InvalidArgumentException
543
+	 * @throws InvalidDataTypeException
544
+	 * @throws InvalidInterfaceException
545
+	 */
546
+	protected function _add_screen_options_default()
547
+	{
548
+		$this->_per_page_screen_option();
549
+	}
550
+
551
+
552
+	/**
553
+	 * Implementing screen options for the category list route.
554
+	 *
555
+	 * @throws InvalidArgumentException
556
+	 * @throws InvalidDataTypeException
557
+	 * @throws InvalidInterfaceException
558
+	 */
559
+	protected function _add_screen_options_category_list()
560
+	{
561
+		$page_title              = $this->_admin_page_title;
562
+		$this->_admin_page_title = esc_html__('Categories', 'event_espresso');
563
+		$this->_per_page_screen_option();
564
+		$this->_admin_page_title = $page_title;
565
+	}
566
+
567
+
568
+	/**
569
+	 * Used to register any global feature pointers for the admin page group.
570
+	 */
571
+	protected function _add_feature_pointers()
572
+	{
573
+	}
574
+
575
+
576
+	/**
577
+	 * Registers and enqueues any global scripts and styles for the entire admin page group.
578
+	 */
579
+	public function load_scripts_styles()
580
+	{
581
+		wp_register_style(
582
+			'events-admin-css',
583
+			EVENTS_ASSETS_URL . 'events-admin-page.css',
584
+			[],
585
+			EVENT_ESPRESSO_VERSION
586
+		);
587
+		wp_register_style(
588
+			'ee-cat-admin',
589
+			EVENTS_ASSETS_URL . 'ee-cat-admin.css',
590
+			[],
591
+			EVENT_ESPRESSO_VERSION
592
+		);
593
+		wp_enqueue_style('events-admin-css');
594
+		wp_enqueue_style('ee-cat-admin');
595
+		// scripts
596
+		wp_register_script(
597
+			'event_editor_js',
598
+			EVENTS_ASSETS_URL . 'event_editor.js',
599
+			['ee_admin_js', 'jquery-ui-slider', 'jquery-ui-timepicker-addon'],
600
+			EVENT_ESPRESSO_VERSION,
601
+			true
602
+		);
603
+	}
604
+
605
+
606
+	/**
607
+	 * Enqueuing scripts and styles specific to this view
608
+	 */
609
+	public function load_scripts_styles_create_new()
610
+	{
611
+		$this->load_scripts_styles_edit();
612
+	}
613
+
614
+
615
+	/**
616
+	 * Enqueuing scripts and styles specific to this view
617
+	 */
618
+	public function load_scripts_styles_edit()
619
+	{
620
+		// styles
621
+		wp_enqueue_style('espresso-ui-theme');
622
+		wp_register_style(
623
+			'event-editor-css',
624
+			EVENTS_ASSETS_URL . 'event-editor.css',
625
+			['ee-admin-css'],
626
+			EVENT_ESPRESSO_VERSION
627
+		);
628
+		wp_enqueue_style('event-editor-css');
629
+		// scripts
630
+		if (! $this->admin_config->useAdvancedEditor()) {
631
+			wp_register_script(
632
+				'event-datetime-metabox',
633
+				EVENTS_ASSETS_URL . 'event-datetime-metabox.js',
634
+				['event_editor_js', 'ee-datepicker'],
635
+				EVENT_ESPRESSO_VERSION
636
+			);
637
+			wp_enqueue_script('event-datetime-metabox');
638
+		}
639
+	}
640
+
641
+
642
+	/**
643
+	 * Populating the _views property for the category list table view.
644
+	 */
645
+	protected function _set_list_table_views_category_list()
646
+	{
647
+		$this->_views = [
648
+			'all' => [
649
+				'slug'        => 'all',
650
+				'label'       => esc_html__('All', 'event_espresso'),
651
+				'count'       => 0,
652
+				'bulk_action' => [
653
+					'delete_categories' => esc_html__('Delete Permanently', 'event_espresso'),
654
+				],
655
+			],
656
+		];
657
+	}
658
+
659
+
660
+	/**
661
+	 * For adding anything that fires on the admin_init hook for any route within this admin page group.
662
+	 */
663
+	public function admin_init()
664
+	{
665
+		EE_Registry::$i18n_js_strings['image_confirm'] = esc_html__(
666
+			'Do you really want to delete this image? Please remember to update your event to complete the removal.',
667
+			'event_espresso'
668
+		);
669
+	}
670
+
671
+
672
+	/**
673
+	 * For adding anything that should be triggered on the admin_notices hook for any route within this admin page
674
+	 * group.
675
+	 */
676
+	public function admin_notices()
677
+	{
678
+	}
679
+
680
+
681
+	/**
682
+	 * For adding anything that should be triggered on the `admin_print_footer_scripts` hook for any route within
683
+	 * this admin page group.
684
+	 */
685
+	public function admin_footer_scripts()
686
+	{
687
+	}
688
+
689
+
690
+	/**
691
+	 * Call this function to verify if an event is public and has tickets for sale.  If it does, then we need to show a
692
+	 * warning (via EE_Error::add_error());
693
+	 *
694
+	 * @param EE_Event $event Event object
695
+	 * @param string   $req_type
696
+	 * @return void
697
+	 * @throws EE_Error
698
+	 * @throws ReflectionException
699
+	 */
700
+	public function verify_event_edit($event = null, $req_type = '')
701
+	{
702
+		// don't need to do this when processing
703
+		if (! empty($req_type)) {
704
+			return;
705
+		}
706
+		// no event?
707
+		if (! $event instanceof EE_Event) {
708
+			$event = $this->_cpt_model_obj;
709
+		}
710
+		// STILL no event?
711
+		if (! $event instanceof EE_Event) {
712
+			return;
713
+		}
714
+		$orig_status = $event->status();
715
+		// first check if event is active.
716
+		if (
717
+			$orig_status === EEM_Event::cancelled
718
+			|| $orig_status === EEM_Event::postponed
719
+			|| $event->is_expired()
720
+			|| $event->is_inactive()
721
+		) {
722
+			return;
723
+		}
724
+		// made it here so it IS active... next check that any of the tickets are sold.
725
+		if ($event->is_sold_out(true)) {
726
+			if ($orig_status !== EEM_Event::sold_out && $event->status() !== $orig_status) {
727
+				EE_Error::add_attention(
728
+					sprintf(
729
+						esc_html__(
730
+							'Please note that the Event Status has automatically been changed to %s because there are no more spaces available for this event.  However, this change is not permanent until you update the event.  You can change the status back to something else before updating if you wish.',
731
+							'event_espresso'
732
+						),
733
+						EEH_Template::pretty_status(EEM_Event::sold_out, false, 'sentence')
734
+					)
735
+				);
736
+			}
737
+			return;
738
+		}
739
+		if ($orig_status === EEM_Event::sold_out) {
740
+			EE_Error::add_attention(
741
+				sprintf(
742
+					esc_html__(
743
+						'Please note that the Event Status has automatically been changed to %s because more spaces have become available for this event, most likely due to abandoned transactions freeing up reserved tickets.  However, this change is not permanent until you update the event. If you wish, you can change the status back to something else before updating.',
744
+						'event_espresso'
745
+					),
746
+					EEH_Template::pretty_status($event->status(), false, 'sentence')
747
+				)
748
+			);
749
+		}
750
+		// now we need to determine if the event has any tickets on sale.  If not then we dont' show the error
751
+		if (! $event->tickets_on_sale()) {
752
+			return;
753
+		}
754
+		// made it here so show warning
755
+		$this->_edit_event_warning();
756
+	}
757
+
758
+
759
+	/**
760
+	 * This is the text used for when an event is being edited that is public and has tickets for sale.
761
+	 * When needed, hook this into a EE_Error::add_error() notice.
762
+	 *
763
+	 * @access protected
764
+	 * @return void
765
+	 */
766
+	protected function _edit_event_warning()
767
+	{
768
+		// we don't want to add warnings during these requests
769
+		if ($this->request->getRequestParam('action') === 'editpost') {
770
+			return;
771
+		}
772
+		EE_Error::add_attention(
773
+			sprintf(
774
+				esc_html__(
775
+					'Your event is open for registration. Making changes may disrupt any transactions in progress. %sLearn more%s',
776
+					'event_espresso'
777
+				),
778
+				'<a class="espresso-help-tab-lnk ee-help-tab-link">',
779
+				'</a>'
780
+			)
781
+		);
782
+	}
783
+
784
+
785
+	/**
786
+	 * When a user is creating a new event, notify them if they haven't set their timezone.
787
+	 * Otherwise, do the normal logic
788
+	 *
789
+	 * @return void
790
+	 * @throws EE_Error
791
+	 * @throws InvalidArgumentException
792
+	 * @throws InvalidDataTypeException
793
+	 * @throws InvalidInterfaceException
794
+	 */
795
+	protected function _create_new_cpt_item()
796
+	{
797
+		$has_timezone_string = get_option('timezone_string');
798
+		// only nag them about setting their timezone if it's their first event, and they haven't already done it
799
+		if (! $has_timezone_string && ! EEM_Event::instance()->exists([])) {
800
+			EE_Error::add_attention(
801
+				sprintf(
802
+					esc_html__(
803
+						'Your website\'s timezone is currently set to a UTC offset. We recommend updating your timezone to a city or region near you before you create an event. Change your timezone now:%1$s%2$s%3$sChange Timezone%4$s',
804
+						'event_espresso'
805
+					),
806
+					'<br>',
807
+					'<select id="timezone_string" name="timezone_string" aria-describedby="timezone-description">'
808
+					. EEH_DTT_Helper::wp_timezone_choice('', EEH_DTT_Helper::get_user_locale())
809
+					. '</select>',
810
+					'<button class="button button--secondary timezone-submit">',
811
+					'</button><span class="spinner"></span>'
812
+				),
813
+				__FILE__,
814
+				__FUNCTION__,
815
+				__LINE__
816
+			);
817
+		}
818
+		parent::_create_new_cpt_item();
819
+	}
820
+
821
+
822
+	/**
823
+	 * Sets the _views property for the default route in this admin page group.
824
+	 */
825
+	protected function _set_list_table_views_default()
826
+	{
827
+		$this->_views = [
828
+			'all'   => [
829
+				'slug'        => 'all',
830
+				'label'       => esc_html__('View All Events', 'event_espresso'),
831
+				'count'       => 0,
832
+				'bulk_action' => [
833
+					'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
834
+				],
835
+			],
836
+			'draft' => [
837
+				'slug'        => 'draft',
838
+				'label'       => esc_html__('Draft', 'event_espresso'),
839
+				'count'       => 0,
840
+				'bulk_action' => [
841
+					'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
842
+				],
843
+			],
844
+		];
845
+		if (EE_Registry::instance()->CAP->current_user_can('ee_delete_events', 'espresso_events_trash_events')) {
846
+			$this->_views['trash'] = [
847
+				'slug'        => 'trash',
848
+				'label'       => esc_html__('Trash', 'event_espresso'),
849
+				'count'       => 0,
850
+				'bulk_action' => [
851
+					'restore_events' => esc_html__('Restore From Trash', 'event_espresso'),
852
+					'delete_events'  => esc_html__('Delete Permanently', 'event_espresso'),
853
+				],
854
+			];
855
+		}
856
+	}
857
+
858
+
859
+	/**
860
+	 * Provides the legend item array for the default list table view.
861
+	 *
862
+	 * @return array
863
+	 * @throws EE_Error
864
+	 * @throws EE_Error
865
+	 */
866
+	protected function _event_legend_items()
867
+	{
868
+		$items    = [
869
+			'view_details'   => [
870
+				'class' => 'dashicons dashicons-visibility',
871
+				'desc'  => esc_html__('View Event', 'event_espresso'),
872
+			],
873
+			'edit_event'     => [
874
+				'class' => 'dashicons dashicons-calendar-alt',
875
+				'desc'  => esc_html__('Edit Event Details', 'event_espresso'),
876
+			],
877
+			'view_attendees' => [
878
+				'class' => 'dashicons dashicons-groups',
879
+				'desc'  => esc_html__('View Registrations for Event', 'event_espresso'),
880
+			],
881
+		];
882
+		$items    = apply_filters('FHEE__Events_Admin_Page___event_legend_items__items', $items);
883
+		$statuses = [
884
+			'sold_out_status'  => [
885
+				'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::sold_out,
886
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::sold_out, false, 'sentence'),
887
+			],
888
+			'active_status'    => [
889
+				'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::active,
890
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::active, false, 'sentence'),
891
+			],
892
+			'upcoming_status'  => [
893
+				'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::upcoming,
894
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::upcoming, false, 'sentence'),
895
+			],
896
+			'postponed_status' => [
897
+				'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::postponed,
898
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::postponed, false, 'sentence'),
899
+			],
900
+			'cancelled_status' => [
901
+				'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::cancelled,
902
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::cancelled, false, 'sentence'),
903
+			],
904
+			'expired_status'   => [
905
+				'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::expired,
906
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::expired, false, 'sentence'),
907
+			],
908
+			'inactive_status'  => [
909
+				'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::inactive,
910
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::inactive, false, 'sentence'),
911
+			],
912
+		];
913
+		$statuses = apply_filters('FHEE__Events_Admin_Page__event_legend_items__statuses', $statuses);
914
+		return array_merge($items, $statuses);
915
+	}
916
+
917
+
918
+	/**
919
+	 * @return EEM_Event
920
+	 * @throws EE_Error
921
+	 * @throws InvalidArgumentException
922
+	 * @throws InvalidDataTypeException
923
+	 * @throws InvalidInterfaceException
924
+	 * @throws ReflectionException
925
+	 */
926
+	private function _event_model()
927
+	{
928
+		if (! $this->_event_model instanceof EEM_Event) {
929
+			$this->_event_model = EE_Registry::instance()->load_model('Event');
930
+		}
931
+		return $this->_event_model;
932
+	}
933
+
934
+
935
+	/**
936
+	 * Adds extra buttons to the WP CPT permalink field row.
937
+	 * Method is called from parent and is hooked into the wp 'get_sample_permalink_html' filter.
938
+	 *
939
+	 * @param string $return    the current html
940
+	 * @param int    $id        the post id for the page
941
+	 * @param string $new_title What the title is
942
+	 * @param string $new_slug  what the slug is
943
+	 * @return string            The new html string for the permalink area
944
+	 */
945
+	public function extra_permalink_field_buttons($return, $id, $new_title, $new_slug)
946
+	{
947
+		// make sure this is only when editing
948
+		if (! empty($id)) {
949
+			$post = get_post($id);
950
+			$return .= '<a class="button button--small button--secondary" onclick="prompt(\'Shortcode:\', jQuery(\'#shortcode\').val()); return false;" href="#"  tabindex="-1">'
951
+					   . esc_html__('Shortcode', 'event_espresso')
952
+					   . '</a> ';
953
+			$return .= '<input id="shortcode" type="hidden" value="[ESPRESSO_TICKET_SELECTOR event_id='
954
+					   . $post->ID
955
+					   . ']">';
956
+		}
957
+		return $return;
958
+	}
959
+
960
+
961
+	/**
962
+	 * _events_overview_list_table
963
+	 * This contains the logic for showing the events_overview list
964
+	 *
965
+	 * @access protected
966
+	 * @return void
967
+	 * @throws DomainException
968
+	 * @throws EE_Error
969
+	 * @throws InvalidArgumentException
970
+	 * @throws InvalidDataTypeException
971
+	 * @throws InvalidInterfaceException
972
+	 */
973
+	protected function _events_overview_list_table()
974
+	{
975
+		$after_list_table                           = [];
976
+		$links_html = EEH_HTML::div('', '', 'ee-admin-section ee-layout-stack');
977
+		$links_html .= EEH_HTML::h3(esc_html__('Links', 'event_espresso'));
978
+		$links_html .= EEH_HTML::div(
979
+			EEH_Template::get_button_or_link(
980
+				get_post_type_archive_link('espresso_events'),
981
+				esc_html__('View Event Archive Page', 'event_espresso'),
982
+				'button button--small button--secondary'
983
+			),
984
+			'',
985
+			'ee-admin-button-row ee-admin-button-row--align-start'
986
+		);
987
+		$links_html .= EEH_HTML::divx();
988
+
989
+		$after_list_table['view_event_list_button'] = $links_html;
990
+
991
+		$after_list_table['legend'] = $this->_display_legend($this->_event_legend_items());
992
+		$this->_admin_page_title                    .= ' ' . $this->get_action_link_or_button(
993
+			'create_new',
994
+			'add',
995
+			[],
996
+			'add-new-h2'
997
+		);
998
+
999
+		$this->_template_args['after_list_table']   = array_merge(
1000
+			(array) $this->_template_args['after_list_table'],
1001
+			$after_list_table
1002
+		);
1003
+		$this->display_admin_list_table_page_with_no_sidebar();
1004
+	}
1005
+
1006
+
1007
+	/**
1008
+	 * this allows for extra misc actions in the default WP publish box
1009
+	 *
1010
+	 * @return void
1011
+	 * @throws DomainException
1012
+	 * @throws EE_Error
1013
+	 * @throws InvalidArgumentException
1014
+	 * @throws InvalidDataTypeException
1015
+	 * @throws InvalidInterfaceException
1016
+	 * @throws ReflectionException
1017
+	 */
1018
+	public function extra_misc_actions_publish_box()
1019
+	{
1020
+		$this->_generate_publish_box_extra_content();
1021
+	}
1022
+
1023
+
1024
+	/**
1025
+	 * This is hooked into the WordPress do_action('save_post') hook and runs after the custom post type has been
1026
+	 * saved.
1027
+	 * Typically you would use this to save any additional data.
1028
+	 * Keep in mind also that "save_post" runs on EVERY post update to the database.
1029
+	 * ALSO very important.  When a post transitions from scheduled to published,
1030
+	 * the save_post action is fired but you will NOT have any _POST data containing any extra info you may have from
1031
+	 * other meta saves. So MAKE sure that you handle this accordingly.
1032
+	 *
1033
+	 * @access protected
1034
+	 * @abstract
1035
+	 * @param string $post_id The ID of the cpt that was saved (so you can link relationally)
1036
+	 * @param WP_Post $post    The post object of the cpt that was saved.
1037
+	 * @return void
1038
+	 * @throws EE_Error
1039
+	 * @throws InvalidArgumentException
1040
+	 * @throws InvalidDataTypeException
1041
+	 * @throws InvalidInterfaceException
1042
+	 * @throws ReflectionException
1043
+	 */
1044
+	protected function _insert_update_cpt_item($post_id, $post)
1045
+	{
1046
+		if ($post instanceof WP_Post && $post->post_type !== 'espresso_events') {
1047
+			// get out we're not processing an event save.
1048
+			return;
1049
+		}
1050
+		$event_values = [
1051
+			'EVT_member_only'     => $this->request->getRequestParam('member_only', false, 'bool'),
1052
+			'EVT_allow_overflow'  => $this->request->getRequestParam('EVT_allow_overflow', false, 'bool'),
1053
+			'EVT_timezone_string' => $this->request->getRequestParam('timezone_string'),
1054
+		];
1055
+		// check if the new EDTR reg options meta box is being used, and if so, don't run updates for legacy version
1056
+		if (! $this->admin_config->useAdvancedEditor() || ! $this->feature->allowed('use_reg_options_meta_box')) {
1057
+			$event_values['EVT_display_ticket_selector']     = $this->request->getRequestParam(
1058
+				'display_ticket_selector',
1059
+				false,
1060
+				'bool'
1061
+			);
1062
+			$event_values['EVT_additional_limit']            = min(
1063
+				apply_filters('FHEE__EE_Events_Admin__insert_update_cpt_item__EVT_additional_limit_max', 255),
1064
+				$this->request->getRequestParam('additional_limit', null, 'int')
1065
+			);
1066
+			$event_values['EVT_default_registration_status'] = $this->request->getRequestParam(
1067
+				'EVT_default_registration_status',
1068
+				EE_Registry::instance()->CFG->registration->default_STS_ID
1069
+			);
1070
+
1071
+			$event_values['EVT_external_URL'] = $this->request->getRequestParam('externalURL');
1072
+			$event_values['EVT_phone']        = $this->request->getRequestParam('event_phone');
1073
+			$event_values['EVT_display_desc'] = $this->request->getRequestParam('display_desc', false, 'bool');
1074
+		}
1075
+		// update event
1076
+		$success = $this->_event_model()->update_by_ID($event_values, $post_id);
1077
+		// get event_object for other metaboxes...
1078
+		// though it would seem to make sense to just use $this->_event_model()->get_one_by_ID( $post_id )..
1079
+		// i have to setup where conditions to override the filters in the model
1080
+		// that filter out autodraft and inherit statuses so we GET the inherit id!
1081
+		$event = $this->_event_model()->get_one(
1082
+			[
1083
+				[
1084
+					$this->_event_model()->primary_key_name() => $post_id,
1085
+					'OR'                                      => [
1086
+						'status'   => $post->post_status,
1087
+						// if trying to "Publish" a sold out event, it's status will get switched back to "sold_out" in the db,
1088
+						// but the returned object here has a status of "publish", so use the original post status as well
1089
+						'status*1' => $this->request->getRequestParam('original_post_status'),
1090
+					],
1091
+				],
1092
+			]
1093
+		);
1094
+
1095
+		// the following are default callbacks for event attachment updates
1096
+		// that can be overridden by caffeinated functionality and/or addons.
1097
+		$event_update_callbacks = [];
1098
+		if (! $this->admin_config->useAdvancedEditor()) {
1099
+			$event_update_callbacks['_default_venue_update']   = [$this, '_default_venue_update'];
1100
+			$event_update_callbacks['_default_tickets_update'] = [$this, '_default_tickets_update'];
1101
+		}
1102
+		$event_update_callbacks = apply_filters(
1103
+			'FHEE__Events_Admin_Page___insert_update_cpt_item__event_update_callbacks',
1104
+			$event_update_callbacks
1105
+		);
1106
+
1107
+		$att_success = true;
1108
+		foreach ($event_update_callbacks as $e_callback) {
1109
+			$_success = is_callable($e_callback)
1110
+				? $e_callback($event, $this->request->requestParams())
1111
+				: false;
1112
+			// if ANY of these updates fail then we want the appropriate global error message
1113
+			$att_success = $_success !== false ? $att_success : false;
1114
+		}
1115
+		// any errors?
1116
+		if ($success && $att_success === false) {
1117
+			EE_Error::add_error(
1118
+				esc_html__(
1119
+					'Event Details saved successfully but something went wrong with saving attachments.',
1120
+					'event_espresso'
1121
+				),
1122
+				__FILE__,
1123
+				__FUNCTION__,
1124
+				__LINE__
1125
+			);
1126
+		} elseif ($success === false) {
1127
+			EE_Error::add_error(
1128
+				esc_html__('Event Details did not save successfully.', 'event_espresso'),
1129
+				__FILE__,
1130
+				__FUNCTION__,
1131
+				__LINE__
1132
+			);
1133
+		}
1134
+	}
1135
+
1136
+
1137
+	/**
1138
+	 * @param int $post_id
1139
+	 * @param int $revision_id
1140
+	 * @throws EE_Error
1141
+	 * @throws EE_Error
1142
+	 * @throws ReflectionException
1143
+	 * @see parent::restore_item()
1144
+	 */
1145
+	protected function _restore_cpt_item($post_id, $revision_id)
1146
+	{
1147
+		// copy existing event meta to new post
1148
+		$post_evt = $this->_event_model()->get_one_by_ID($post_id);
1149
+		if ($post_evt instanceof EE_Event) {
1150
+			// meta revision restore
1151
+			$post_evt->restore_revision($revision_id);
1152
+			// related objs restore
1153
+			$post_evt->restore_revision($revision_id, ['Venue', 'Datetime', 'Price']);
1154
+		}
1155
+	}
1156
+
1157
+
1158
+	/**
1159
+	 * Attach the venue to the Event
1160
+	 *
1161
+	 * @param EE_Event $event Event Object to add the venue to
1162
+	 * @param array    $data  The request data from the form
1163
+	 * @return bool           Success or fail.
1164
+	 * @throws EE_Error
1165
+	 * @throws ReflectionException
1166
+	 */
1167
+	protected function _default_venue_update(EE_Event $event, $data)
1168
+	{
1169
+		require_once(EE_MODELS . 'EEM_Venue.model.php');
1170
+		$venue_model = EE_Registry::instance()->load_model('Venue');
1171
+		$venue_id    = ! empty($data['venue_id']) ? $data['venue_id'] : null;
1172
+		// very important.  If we don't have a venue name...
1173
+		// then we'll get out because not necessary to create empty venue
1174
+		if (empty($data['venue_title'])) {
1175
+			return false;
1176
+		}
1177
+		$venue_array = [
1178
+			'VNU_wp_user'         => $event->get('EVT_wp_user'),
1179
+			'VNU_name'            => ! empty($data['venue_title']) ? $data['venue_title'] : null,
1180
+			'VNU_desc'            => ! empty($data['venue_description']) ? $data['venue_description'] : null,
1181
+			'VNU_identifier'      => ! empty($data['venue_identifier']) ? $data['venue_identifier'] : null,
1182
+			'VNU_short_desc'      => ! empty($data['venue_short_description'])
1183
+				? $data['venue_short_description']
1184
+				: null,
1185
+			'VNU_address'         => ! empty($data['address']) ? $data['address'] : null,
1186
+			'VNU_address2'        => ! empty($data['address2']) ? $data['address2'] : null,
1187
+			'VNU_city'            => ! empty($data['city']) ? $data['city'] : null,
1188
+			'STA_ID'              => ! empty($data['state']) ? $data['state'] : null,
1189
+			'CNT_ISO'             => ! empty($data['countries']) ? $data['countries'] : null,
1190
+			'VNU_zip'             => ! empty($data['zip']) ? $data['zip'] : null,
1191
+			'VNU_phone'           => ! empty($data['venue_phone']) ? $data['venue_phone'] : null,
1192
+			'VNU_capacity'        => ! empty($data['venue_capacity']) ? $data['venue_capacity'] : null,
1193
+			'VNU_url'             => ! empty($data['venue_url']) ? $data['venue_url'] : null,
1194
+			'VNU_virtual_phone'   => ! empty($data['virtual_phone']) ? $data['virtual_phone'] : null,
1195
+			'VNU_virtual_url'     => ! empty($data['virtual_url']) ? $data['virtual_url'] : null,
1196
+			'VNU_enable_for_gmap' => isset($data['enable_for_gmap']) ? 1 : 0,
1197
+			'status'              => 'publish',
1198
+		];
1199
+		// if we've got the venue_id then we're just updating the existing venue so let's do that and then get out.
1200
+		if (! empty($venue_id)) {
1201
+			$update_where  = [$venue_model->primary_key_name() => $venue_id];
1202
+			$rows_affected = $venue_model->update($venue_array, [$update_where]);
1203
+			// we've gotta make sure that the venue is always attached to a revision..
1204
+			// add_relation_to should take care of making sure that the relation is already present.
1205
+			$event->_add_relation_to($venue_id, 'Venue');
1206
+			return $rows_affected > 0;
1207
+		}
1208
+		// we insert the venue
1209
+		$venue_id = $venue_model->insert($venue_array);
1210
+		$event->_add_relation_to($venue_id, 'Venue');
1211
+		return ! empty($venue_id);
1212
+		// when we have the ancestor come in it's already been handled by the revision save.
1213
+	}
1214
+
1215
+
1216
+	/**
1217
+	 * Handles saving everything related to Tickets (datetimes, tickets, prices)
1218
+	 *
1219
+	 * @param EE_Event $event The Event object we're attaching data to
1220
+	 * @param array    $data  The request data from the form
1221
+	 * @return array
1222
+	 * @throws EE_Error
1223
+	 * @throws ReflectionException
1224
+	 * @throws Exception
1225
+	 */
1226
+	protected function _default_tickets_update(EE_Event $event, $data)
1227
+	{
1228
+		if ($this->admin_config->useAdvancedEditor()) {
1229
+			return [];
1230
+		}
1231
+		$datetime       = null;
1232
+		$saved_tickets  = [];
1233
+		$event_timezone = $event->get_timezone();
1234
+		$date_formats   = ['Y-m-d', 'h:i a'];
1235
+		foreach ($data['edit_event_datetimes'] as $row => $datetime_data) {
1236
+			// trim all values to ensure any excess whitespace is removed.
1237
+			$datetime_data                = array_map('trim', $datetime_data);
1238
+			$datetime_data['DTT_EVT_end'] =
1239
+				isset($datetime_data['DTT_EVT_end']) && ! empty($datetime_data['DTT_EVT_end'])
1240
+					? $datetime_data['DTT_EVT_end']
1241
+					: $datetime_data['DTT_EVT_start'];
1242
+			$datetime_values              = [
1243
+				'DTT_ID'        => ! empty($datetime_data['DTT_ID']) ? $datetime_data['DTT_ID'] : null,
1244
+				'DTT_EVT_start' => $datetime_data['DTT_EVT_start'],
1245
+				'DTT_EVT_end'   => $datetime_data['DTT_EVT_end'],
1246
+				'DTT_reg_limit' => empty($datetime_data['DTT_reg_limit']) ? EE_INF : $datetime_data['DTT_reg_limit'],
1247
+				'DTT_order'     => $row,
1248
+			];
1249
+			// if we have an id then let's get existing object first and then set the new values.
1250
+			//  Otherwise we instantiate a new object for save.
1251
+			if (! empty($datetime_data['DTT_ID'])) {
1252
+				$datetime = EEM_Datetime::instance($event_timezone)->get_one_by_ID($datetime_data['DTT_ID']);
1253
+				if (! $datetime instanceof EE_Datetime) {
1254
+					throw new RuntimeException(
1255
+						sprintf(
1256
+							esc_html__(
1257
+								'Something went wrong! A valid Datetime could not be retrieved from the database using the supplied ID: %1$d',
1258
+								'event_espresso'
1259
+							),
1260
+							$datetime_data['DTT_ID']
1261
+						)
1262
+					);
1263
+				}
1264
+				$datetime->set_date_format($date_formats[0]);
1265
+				$datetime->set_time_format($date_formats[1]);
1266
+				foreach ($datetime_values as $field => $value) {
1267
+					$datetime->set($field, $value);
1268
+				}
1269
+			} else {
1270
+				$datetime = EE_Datetime::new_instance($datetime_values, $event_timezone, $date_formats);
1271
+			}
1272
+			if (! $datetime instanceof EE_Datetime) {
1273
+				throw new RuntimeException(
1274
+					sprintf(
1275
+						esc_html__(
1276
+							'Something went wrong! A valid Datetime could not be generated or retrieved using the supplied data: %1$s',
1277
+							'event_espresso'
1278
+						),
1279
+						print_r($datetime_values, true)
1280
+					)
1281
+				);
1282
+			}
1283
+			// before going any further make sure our dates are setup correctly
1284
+			// so that the end date is always equal or greater than the start date.
1285
+			if ($datetime->get_raw('DTT_EVT_start') > $datetime->get_raw('DTT_EVT_end')) {
1286
+				$datetime->set('DTT_EVT_end', $datetime->get('DTT_EVT_start'));
1287
+				$datetime = EEH_DTT_Helper::date_time_add($datetime, 'DTT_EVT_end', 'days');
1288
+			}
1289
+			$datetime->save();
1290
+			$event->_add_relation_to($datetime, 'Datetime');
1291
+		}
1292
+		// no datetimes get deleted so we don't do any of that logic here.
1293
+		// update tickets next
1294
+		$old_tickets = isset($data['ticket_IDs']) ? explode(',', $data['ticket_IDs']) : [];
1295
+
1296
+		// set up some default start and end dates in case those are not present in the incoming data
1297
+		$default_start_date = new DateTime('now', new DateTimeZone($event->get_timezone()));
1298
+		$default_start_date = $default_start_date->format($date_formats[0] . ' ' . $date_formats[1]);
1299
+		// use the start date of the first datetime for the end date
1300
+		$first_datetime   = $event->first_datetime();
1301
+		$default_end_date = $first_datetime->start_date_and_time($date_formats[0], $date_formats[1]);
1302
+
1303
+		// now process the incoming data
1304
+		foreach ($data['edit_tickets'] as $row => $ticket_data) {
1305
+			$update_prices = false;
1306
+			$ticket_price  = isset($data['edit_prices'][ $row ][1]['PRC_amount'])
1307
+				? $data['edit_prices'][ $row ][1]['PRC_amount']
1308
+				: 0;
1309
+			// trim inputs to ensure any excess whitespace is removed.
1310
+			$ticket_data   = array_map('trim', $ticket_data);
1311
+			$ticket_values = [
1312
+				'TKT_ID'          => ! empty($ticket_data['TKT_ID']) ? $ticket_data['TKT_ID'] : null,
1313
+				'TTM_ID'          => ! empty($ticket_data['TTM_ID']) ? $ticket_data['TTM_ID'] : 0,
1314
+				'TKT_name'        => ! empty($ticket_data['TKT_name']) ? $ticket_data['TKT_name'] : '',
1315
+				'TKT_description' => ! empty($ticket_data['TKT_description']) ? $ticket_data['TKT_description'] : '',
1316
+				'TKT_start_date'  => ! empty($ticket_data['TKT_start_date'])
1317
+					? $ticket_data['TKT_start_date']
1318
+					: $default_start_date,
1319
+				'TKT_end_date'    => ! empty($ticket_data['TKT_end_date'])
1320
+					? $ticket_data['TKT_end_date']
1321
+					: $default_end_date,
1322
+				'TKT_qty'         => ! empty($ticket_data['TKT_qty'])
1323
+									 || (isset($ticket_data['TKT_qty']) && (int) $ticket_data['TKT_qty'] === 0)
1324
+					? $ticket_data['TKT_qty']
1325
+					: EE_INF,
1326
+				'TKT_uses'        => ! empty($ticket_data['TKT_uses'])
1327
+									 || (isset($ticket_data['TKT_uses']) && (int) $ticket_data['TKT_uses'] === 0)
1328
+					? $ticket_data['TKT_uses']
1329
+					: EE_INF,
1330
+				'TKT_min'         => ! empty($ticket_data['TKT_min']) ? $ticket_data['TKT_min'] : 0,
1331
+				'TKT_max'         => ! empty($ticket_data['TKT_max']) ? $ticket_data['TKT_max'] : EE_INF,
1332
+				'TKT_order'       => isset($ticket_data['TKT_order']) ? $ticket_data['TKT_order'] : $row,
1333
+				'TKT_price'       => $ticket_price,
1334
+				'TKT_row'         => $row,
1335
+			];
1336
+			// if this is a default ticket, then we need to set the TKT_ID to 0 and update accordingly,
1337
+			// which means in turn that the prices will become new prices as well.
1338
+			if (isset($ticket_data['TKT_is_default']) && $ticket_data['TKT_is_default']) {
1339
+				$ticket_values['TKT_ID']         = 0;
1340
+				$ticket_values['TKT_is_default'] = 0;
1341
+				$update_prices                   = true;
1342
+			}
1343
+			// if we have a TKT_ID then we need to get that existing TKT_obj and update it
1344
+			// we actually do our saves ahead of adding any relations because its entirely possible that this
1345
+			// ticket didn't get removed or added to any datetime in the session but DID have it's items modified.
1346
+			// keep in mind that if the ticket has been sold (and we have changed pricing information),
1347
+			// then we won't be updating the tkt but instead a new tkt will be created and the old one archived.
1348
+			if (! empty($ticket_data['TKT_ID'])) {
1349
+				$existing_ticket = EEM_Ticket::instance($event_timezone)->get_one_by_ID($ticket_data['TKT_ID']);
1350
+				if (! $existing_ticket instanceof EE_Ticket) {
1351
+					throw new RuntimeException(
1352
+						sprintf(
1353
+							esc_html__(
1354
+								'Something went wrong! A valid Ticket could not be retrieved from the database using the supplied ID: %1$d',
1355
+								'event_espresso'
1356
+							),
1357
+							$ticket_data['TKT_ID']
1358
+						)
1359
+					);
1360
+				}
1361
+				$ticket_sold = $existing_ticket->count_related(
1362
+					'Registration',
1363
+					[
1364
+							[
1365
+								'STS_ID' => [
1366
+									'NOT IN',
1367
+									[EEM_Registration::status_id_incomplete],
1368
+								],
1369
+							],
1370
+						]
1371
+				) > 0;
1372
+				// let's just check the total price for the existing ticket and determine if it matches the new total price.
1373
+				// if they are different then we create a new ticket (if $ticket_sold)
1374
+				// if they aren't different then we go ahead and modify existing ticket.
1375
+				$create_new_ticket = $ticket_sold
1376
+									 && $ticket_price !== $existing_ticket->price()
1377
+									 && ! $existing_ticket->deleted();
1378
+				$existing_ticket->set_date_format($date_formats[0]);
1379
+				$existing_ticket->set_time_format($date_formats[1]);
1380
+				// set new values
1381
+				foreach ($ticket_values as $field => $value) {
1382
+					if ($field == 'TKT_qty') {
1383
+						$existing_ticket->set_qty($value);
1384
+					} elseif ($field == 'TKT_price') {
1385
+						$existing_ticket->set('TKT_price', $ticket_price);
1386
+					} else {
1387
+						$existing_ticket->set($field, $value);
1388
+					}
1389
+				}
1390
+				$ticket = $existing_ticket;
1391
+				// if $create_new_ticket is false then we can safely update the existing ticket.
1392
+				//  Otherwise we have to create a new ticket.
1393
+				if ($create_new_ticket) {
1394
+					// archive the old ticket first
1395
+					$existing_ticket->set('TKT_deleted', 1);
1396
+					$existing_ticket->save();
1397
+					// make sure this ticket is still recorded in our $saved_tickets
1398
+					// so we don't run it through the regular trash routine.
1399
+					$saved_tickets[ $existing_ticket->ID() ] = $existing_ticket;
1400
+					// create new ticket that's a copy of the existing except,
1401
+					// (a new id of course and not archived) AND has the new TKT_price associated with it.
1402
+					$new_ticket = clone $existing_ticket;
1403
+					$new_ticket->set('TKT_ID', 0);
1404
+					$new_ticket->set('TKT_deleted', 0);
1405
+					$new_ticket->set('TKT_sold', 0);
1406
+					// now we need to make sure that $new prices are created as well and attached to new ticket.
1407
+					$update_prices = true;
1408
+					$ticket        = $new_ticket;
1409
+				}
1410
+			} else {
1411
+				// no TKT_id so a new ticket
1412
+				$ticket_values['TKT_price'] = $ticket_price;
1413
+				$ticket                     = EE_Ticket::new_instance($ticket_values, $event_timezone, $date_formats);
1414
+				$update_prices              = true;
1415
+			}
1416
+			if (! $ticket instanceof EE_Ticket) {
1417
+				throw new RuntimeException(
1418
+					sprintf(
1419
+						esc_html__(
1420
+							'Something went wrong! A valid Ticket could not be generated or retrieved using the supplied data: %1$s',
1421
+							'event_espresso'
1422
+						),
1423
+						print_r($ticket_values, true)
1424
+					)
1425
+				);
1426
+			}
1427
+			// cap ticket qty by datetime reg limits
1428
+			$ticket->set_qty(min($ticket->qty(), $ticket->qty('reg_limit')));
1429
+			// update ticket.
1430
+			$ticket->save();
1431
+			// before going any further make sure our dates are setup correctly
1432
+			// so that the end date is always equal or greater than the start date.
1433
+			if ($ticket->get_raw('TKT_start_date') > $ticket->get_raw('TKT_end_date')) {
1434
+				$ticket->set('TKT_end_date', $ticket->get('TKT_start_date'));
1435
+				$ticket = EEH_DTT_Helper::date_time_add($ticket, 'TKT_end_date', 'days');
1436
+				$ticket->save();
1437
+			}
1438
+			// initially let's add the ticket to the datetime
1439
+			$datetime->_add_relation_to($ticket, 'Ticket');
1440
+			$saved_tickets[ $ticket->ID() ] = $ticket;
1441
+			// add prices to ticket
1442
+			$prices_data = isset($data['edit_prices'][ $row ]) && is_array($data['edit_prices'][ $row ])
1443
+				? $data['edit_prices'][ $row ]
1444
+				: [];
1445
+			$this->_add_prices_to_ticket($prices_data, $ticket, $update_prices);
1446
+		}
1447
+		// however now we need to handle permanently deleting tickets via the ui.
1448
+		// Keep in mind that the ui does not allow deleting/archiving tickets that have ticket sold.
1449
+		// However, it does allow for deleting tickets that have no tickets sold,
1450
+		// in which case we want to get rid of permanently because there is no need to save in db.
1451
+		$old_tickets     = isset($old_tickets[0]) && $old_tickets[0] === '' ? [] : $old_tickets;
1452
+		$tickets_removed = array_diff($old_tickets, array_keys($saved_tickets));
1453
+		foreach ($tickets_removed as $id) {
1454
+			$id = absint($id);
1455
+			// get the ticket for this id
1456
+			$ticket_to_remove = EEM_Ticket::instance()->get_one_by_ID($id);
1457
+			if (! $ticket_to_remove instanceof EE_Ticket) {
1458
+				continue;
1459
+			}
1460
+			// need to get all the related datetimes on this ticket and remove from every single one of them
1461
+			// (remember this process can ONLY kick off if there are NO tickets sold)
1462
+			$related_datetimes = $ticket_to_remove->get_many_related('Datetime');
1463
+			foreach ($related_datetimes as $related_datetime) {
1464
+				$ticket_to_remove->_remove_relation_to($related_datetime, 'Datetime');
1465
+			}
1466
+			// need to do the same for prices (except these prices can also be deleted because again,
1467
+			// tickets can only be trashed if they don't have any TKTs sold (otherwise they are just archived))
1468
+			$ticket_to_remove->delete_related_permanently('Price');
1469
+			// finally let's delete this ticket
1470
+			// (which should not be blocked at this point b/c we've removed all our relationships)
1471
+			$ticket_to_remove->delete_permanently();
1472
+		}
1473
+		return [$datetime, $saved_tickets];
1474
+	}
1475
+
1476
+
1477
+	/**
1478
+	 * This attaches a list of given prices to a ticket.
1479
+	 * Note we dont' have to worry about ever removing relationships (or archiving prices)
1480
+	 * because if there is a change in price information on a ticket, a new ticket is created anyways
1481
+	 * so the archived ticket will retain the old price info and prices are automatically "archived" via the ticket.
1482
+	 *
1483
+	 * @access  private
1484
+	 * @param array     $prices_data Array of prices from the form.
1485
+	 * @param EE_Ticket $ticket      EE_Ticket object that prices are being attached to.
1486
+	 * @param bool      $new_prices  Whether attach existing incoming prices or create new ones.
1487
+	 * @return  void
1488
+	 * @throws EE_Error
1489
+	 * @throws ReflectionException
1490
+	 */
1491
+	private function _add_prices_to_ticket($prices_data, EE_Ticket $ticket, $new_prices = false)
1492
+	{
1493
+		$timezone = $ticket->get_timezone();
1494
+		foreach ($prices_data as $row => $price_data) {
1495
+			$price_values = [
1496
+				'PRC_ID'         => ! empty($price_data['PRC_ID']) ? $price_data['PRC_ID'] : null,
1497
+				'PRT_ID'         => ! empty($price_data['PRT_ID']) ? $price_data['PRT_ID'] : null,
1498
+				'PRC_amount'     => ! empty($price_data['PRC_amount']) ? $price_data['PRC_amount'] : 0,
1499
+				'PRC_name'       => ! empty($price_data['PRC_name']) ? $price_data['PRC_name'] : '',
1500
+				'PRC_desc'       => ! empty($price_data['PRC_desc']) ? $price_data['PRC_desc'] : '',
1501
+				'PRC_is_default' => 0, // make sure prices are NOT set as default from this context
1502
+				'PRC_order'      => $row,
1503
+			];
1504
+			if ($new_prices || empty($price_values['PRC_ID'])) {
1505
+				$price_values['PRC_ID'] = 0;
1506
+				$price                  = EE_Price::new_instance($price_values, $timezone);
1507
+			} else {
1508
+				$price = EEM_Price::instance($timezone)->get_one_by_ID($price_data['PRC_ID']);
1509
+				// update this price with new values
1510
+				foreach ($price_values as $field => $new_price) {
1511
+					$price->set($field, $new_price);
1512
+				}
1513
+			}
1514
+			if (! $price instanceof EE_Price) {
1515
+				throw new RuntimeException(
1516
+					sprintf(
1517
+						esc_html__(
1518
+							'Something went wrong! A valid Price could not be generated or retrieved using the supplied data: %1$s',
1519
+							'event_espresso'
1520
+						),
1521
+						print_r($price_values, true)
1522
+					)
1523
+				);
1524
+			}
1525
+			$price->save();
1526
+			$ticket->_add_relation_to($price, 'Price');
1527
+		}
1528
+	}
1529
+
1530
+
1531
+	/**
1532
+	 * Add in our autosave ajax handlers
1533
+	 *
1534
+	 */
1535
+	protected function _ee_autosave_create_new()
1536
+	{
1537
+	}
1538
+
1539
+
1540
+	/**
1541
+	 * More autosave handlers.
1542
+	 */
1543
+	protected function _ee_autosave_edit()
1544
+	{
1545
+	}
1546
+
1547
+
1548
+	/**
1549
+	 * @throws EE_Error
1550
+	 * @throws ReflectionException
1551
+	 */
1552
+	private function _generate_publish_box_extra_content()
1553
+	{
1554
+		// load formatter helper
1555
+		// args for getting related registrations
1556
+		$approved_query_args        = [
1557
+			[
1558
+				'REG_deleted' => 0,
1559
+				'STS_ID'      => EEM_Registration::status_id_approved,
1560
+			],
1561
+		];
1562
+		$not_approved_query_args    = [
1563
+			[
1564
+				'REG_deleted' => 0,
1565
+				'STS_ID'      => EEM_Registration::status_id_not_approved,
1566
+			],
1567
+		];
1568
+		$pending_payment_query_args = [
1569
+			[
1570
+				'REG_deleted' => 0,
1571
+				'STS_ID'      => EEM_Registration::status_id_pending_payment,
1572
+			],
1573
+		];
1574
+		// publish box
1575
+		$publish_box_extra_args = [
1576
+			'view_approved_reg_url'        => add_query_arg(
1577
+				[
1578
+					'action'      => 'default',
1579
+					'event_id'    => $this->_cpt_model_obj->ID(),
1580
+					'_reg_status' => EEM_Registration::status_id_approved,
1581
+				],
1582
+				REG_ADMIN_URL
1583
+			),
1584
+			'view_not_approved_reg_url'    => add_query_arg(
1585
+				[
1586
+					'action'      => 'default',
1587
+					'event_id'    => $this->_cpt_model_obj->ID(),
1588
+					'_reg_status' => EEM_Registration::status_id_not_approved,
1589
+				],
1590
+				REG_ADMIN_URL
1591
+			),
1592
+			'view_pending_payment_reg_url' => add_query_arg(
1593
+				[
1594
+					'action'      => 'default',
1595
+					'event_id'    => $this->_cpt_model_obj->ID(),
1596
+					'_reg_status' => EEM_Registration::status_id_pending_payment,
1597
+				],
1598
+				REG_ADMIN_URL
1599
+			),
1600
+			'approved_regs'                => $this->_cpt_model_obj->count_related(
1601
+				'Registration',
1602
+				$approved_query_args
1603
+			),
1604
+			'not_approved_regs'            => $this->_cpt_model_obj->count_related(
1605
+				'Registration',
1606
+				$not_approved_query_args
1607
+			),
1608
+			'pending_payment_regs'         => $this->_cpt_model_obj->count_related(
1609
+				'Registration',
1610
+				$pending_payment_query_args
1611
+			),
1612
+			'misc_pub_section_class'       => apply_filters(
1613
+				'FHEE_Events_Admin_Page___generate_publish_box_extra_content__misc_pub_section_class',
1614
+				'misc-pub-section'
1615
+			),
1616
+		];
1617
+		ob_start();
1618
+		do_action(
1619
+			'AHEE__Events_Admin_Page___generate_publish_box_extra_content__event_editor_overview_add',
1620
+			$this->_cpt_model_obj
1621
+		);
1622
+		$publish_box_extra_args['event_editor_overview_add'] = ob_get_clean();
1623
+		// load template
1624
+		EEH_Template::display_template(
1625
+			EVENTS_TEMPLATE_PATH . 'event_publish_box_extras.template.php',
1626
+			$publish_box_extra_args
1627
+		);
1628
+	}
1629
+
1630
+
1631
+	/**
1632
+	 * @return EE_Event
1633
+	 */
1634
+	public function get_event_object()
1635
+	{
1636
+		return $this->_cpt_model_obj;
1637
+	}
1638
+
1639
+
1640
+
1641
+
1642
+	/** METABOXES * */
1643
+	/**
1644
+	 * _register_event_editor_meta_boxes
1645
+	 * add all metaboxes related to the event_editor
1646
+	 *
1647
+	 * @return void
1648
+	 * @throws EE_Error
1649
+	 * @throws ReflectionException
1650
+	 */
1651
+	protected function _register_event_editor_meta_boxes()
1652
+	{
1653
+		$this->verify_cpt_object();
1654
+		$use_advanced_editor = $this->admin_config->useAdvancedEditor();
1655
+		// check if the new EDTR reg options meta box is being used, and if so, don't load the legacy version
1656
+		if (! $use_advanced_editor || ! $this->feature->allowed('use_reg_options_meta_box')) {
1657
+			$this->addMetaBox(
1658
+				'espresso_event_editor_event_options',
1659
+				esc_html__('Event Registration Options', 'event_espresso'),
1660
+				[$this, 'registration_options_meta_box'],
1661
+				$this->page_slug,
1662
+				'side'
1663
+			);
1664
+		}
1665
+		if (! $use_advanced_editor) {
1666
+			$this->addMetaBox(
1667
+				'espresso_event_editor_tickets',
1668
+				esc_html__('Event Datetime & Ticket', 'event_espresso'),
1669
+				[$this, 'ticket_metabox'],
1670
+				$this->page_slug,
1671
+				'normal',
1672
+				'high'
1673
+			);
1674
+		} elseif ($this->feature->allowed('use_reg_options_meta_box')) {
1675
+			add_action(
1676
+				'add_meta_boxes_espresso_events',
1677
+				function () {
1678
+					global $current_screen;
1679
+					remove_meta_box('authordiv', $current_screen, 'normal');
1680
+				},
1681
+				99
1682
+			);
1683
+		}
1684
+		// NOTE: if you're looking for other metaboxes in here,
1685
+		// where a metabox has a related management page in the admin
1686
+		// you will find it setup in the related management page's "_Hooks" file.
1687
+		// i.e. messages metabox is found in "espresso_events_Messages_Hooks.class.php".
1688
+	}
1689
+
1690
+
1691
+	/**
1692
+	 * @throws DomainException
1693
+	 * @throws EE_Error
1694
+	 * @throws ReflectionException
1695
+	 */
1696
+	public function ticket_metabox()
1697
+	{
1698
+		$existing_datetime_ids = $existing_ticket_ids = [];
1699
+		// defaults for template args
1700
+		$template_args = [
1701
+			'existing_datetime_ids'    => '',
1702
+			'event_datetime_help_link' => '',
1703
+			'ticket_options_help_link' => '',
1704
+			'time'                     => null,
1705
+			'ticket_rows'              => '',
1706
+			'existing_ticket_ids'      => '',
1707
+			'total_ticket_rows'        => 1,
1708
+			'ticket_js_structure'      => '',
1709
+			'trash_icon'               => 'dashicons dashicons-lock',
1710
+			'disabled'                 => '',
1711
+		];
1712
+		$event_id      = is_object($this->_cpt_model_obj) ? $this->_cpt_model_obj->ID() : null;
1713
+		/**
1714
+		 * 1. Start with retrieving Datetimes
1715
+		 * 2. Fore each datetime get related tickets
1716
+		 * 3. For each ticket get related prices
1717
+		 */
1718
+		/** @var EEM_Datetime $datetime_model */
1719
+		$datetime_model = EE_Registry::instance()->load_model('Datetime');
1720
+		/** @var EEM_Ticket $datetime_model */
1721
+		$ticket_model = EE_Registry::instance()->load_model('Ticket');
1722
+		$times        = $datetime_model->get_all_event_dates($event_id);
1723
+		/** @type EE_Datetime $first_datetime */
1724
+		$first_datetime = reset($times);
1725
+		// do we get related tickets?
1726
+		if (
1727
+			$first_datetime instanceof EE_Datetime
1728
+			&& $first_datetime->ID() !== 0
1729
+		) {
1730
+			$existing_datetime_ids[] = $first_datetime->get('DTT_ID');
1731
+			$template_args['time']   = $first_datetime;
1732
+			$related_tickets         = $first_datetime->tickets(
1733
+				[
1734
+					['OR' => ['TKT_deleted' => 1, 'TKT_deleted*' => 0]],
1735
+					'default_where_conditions' => 'none',
1736
+				]
1737
+			);
1738
+			if (! empty($related_tickets)) {
1739
+				$template_args['total_ticket_rows'] = count($related_tickets);
1740
+				$row                                = 0;
1741
+				foreach ($related_tickets as $ticket) {
1742
+					$existing_ticket_ids[]        = $ticket->get('TKT_ID');
1743
+					$template_args['ticket_rows'] .= $this->_get_ticket_row($ticket, false, $row);
1744
+					$row++;
1745
+				}
1746
+			} else {
1747
+				$template_args['total_ticket_rows'] = 1;
1748
+				/** @type EE_Ticket $ticket */
1749
+				$ticket                       = $ticket_model->create_default_object();
1750
+				$template_args['ticket_rows'] .= $this->_get_ticket_row($ticket);
1751
+			}
1752
+		} else {
1753
+			$template_args['time'] = $times[0];
1754
+			/** @type EE_Ticket[] $tickets */
1755
+			$tickets                      = $ticket_model->get_all_default_tickets();
1756
+			$template_args['ticket_rows'] .= $this->_get_ticket_row($tickets[1]);
1757
+			// NOTE: we're just sending the first default row
1758
+			// (decaf can't manage default tickets so this should be sufficient);
1759
+		}
1760
+		$template_args['event_datetime_help_link'] = $this->_get_help_tab_link(
1761
+			'event_editor_event_datetimes_help_tab'
1762
+		);
1763
+		$template_args['ticket_options_help_link'] = $this->_get_help_tab_link('ticket_options_info');
1764
+		$template_args['existing_datetime_ids']    = implode(',', $existing_datetime_ids);
1765
+		$template_args['existing_ticket_ids']      = implode(',', $existing_ticket_ids);
1766
+		$template_args['ticket_js_structure']      = $this->_get_ticket_row(
1767
+			$ticket_model->create_default_object(),
1768
+			true
1769
+		);
1770
+		$template                                  = apply_filters(
1771
+			'FHEE__Events_Admin_Page__ticket_metabox__template',
1772
+			EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_main.template.php'
1773
+		);
1774
+		EEH_Template::display_template($template, $template_args);
1775
+	}
1776
+
1777
+
1778
+	/**
1779
+	 * Setup an individual ticket form for the decaf event editor page
1780
+	 *
1781
+	 * @access private
1782
+	 * @param EE_Ticket $ticket   the ticket object
1783
+	 * @param boolean   $skeleton whether we're generating a skeleton for js manipulation
1784
+	 * @param int       $row
1785
+	 * @return string generated html for the ticket row.
1786
+	 * @throws EE_Error
1787
+	 * @throws ReflectionException
1788
+	 */
1789
+	private function _get_ticket_row($ticket, $skeleton = false, $row = 0)
1790
+	{
1791
+		$template_args = [
1792
+			'tkt_status_class'    => ' tkt-status-' . $ticket->ticket_status(),
1793
+			'tkt_archive_class'   => $ticket->ticket_status() === EE_Ticket::archived && ! $skeleton ? ' tkt-archived'
1794
+				: '',
1795
+			'ticketrow'           => $skeleton ? 'TICKETNUM' : $row,
1796
+			'TKT_ID'              => $ticket->get('TKT_ID'),
1797
+			'TKT_name'            => $ticket->get('TKT_name'),
1798
+			'TKT_start_date'      => $skeleton ? '' : $ticket->get_date('TKT_start_date', 'Y-m-d h:i a'),
1799
+			'TKT_end_date'        => $skeleton ? '' : $ticket->get_date('TKT_end_date', 'Y-m-d h:i a'),
1800
+			'TKT_is_default'      => $ticket->get('TKT_is_default'),
1801
+			'TKT_qty'             => $ticket->get_pretty('TKT_qty', 'input'),
1802
+			'edit_ticketrow_name' => $skeleton ? 'TICKETNAMEATTR' : 'edit_tickets',
1803
+			'TKT_sold'            => $skeleton ? 0 : $ticket->get('TKT_sold'),
1804
+			'trash_icon'          => ($skeleton || (! empty($ticket) && ! $ticket->get('TKT_deleted')))
1805
+									 && (! empty($ticket) && $ticket->get('TKT_sold') === 0)
1806
+				? 'trash-icon dashicons dashicons-post-trash clickable' : 'dashicons dashicons-lock',
1807
+			'disabled'            => $skeleton || (! empty($ticket) && ! $ticket->get('TKT_deleted')) ? ''
1808
+				: ' disabled=disabled',
1809
+		];
1810
+		$price         = $ticket->ID() !== 0
1811
+			? $ticket->get_first_related('Price', ['default_where_conditions' => 'none'])
1812
+			: null;
1813
+		$price         = $price instanceof EE_Price
1814
+			? $price
1815
+			: EEM_Price::instance()->create_default_object();
1816
+		$price_args    = [
1817
+			'price_currency_symbol' => EE_Registry::instance()->CFG->currency->sign,
1818
+			'PRC_amount'            => $price->get('PRC_amount'),
1819
+			'PRT_ID'                => $price->get('PRT_ID'),
1820
+			'PRC_ID'                => $price->get('PRC_ID'),
1821
+			'PRC_is_default'        => $price->get('PRC_is_default'),
1822
+		];
1823
+		// make sure we have default start and end dates if skeleton
1824
+		// handle rows that should NOT be empty
1825
+		if (empty($template_args['TKT_start_date'])) {
1826
+			// if empty then the start date will be now.
1827
+			$template_args['TKT_start_date'] = date('Y-m-d h:i a', current_time('timestamp'));
1828
+		}
1829
+		if (empty($template_args['TKT_end_date'])) {
1830
+			// get the earliest datetime (if present);
1831
+			$earliest_datetime             = $this->_cpt_model_obj->ID() > 0
1832
+				? $this->_cpt_model_obj->get_first_related(
1833
+					'Datetime',
1834
+					['order_by' => ['DTT_EVT_start' => 'ASC']]
1835
+				)
1836
+				: null;
1837
+			$template_args['TKT_end_date'] = $earliest_datetime instanceof EE_Datetime
1838
+				? $earliest_datetime->get_datetime('DTT_EVT_start', 'Y-m-d', 'h:i a')
1839
+				: date('Y-m-d h:i a', mktime(0, 0, 0, date('m'), date('d') + 7, date('Y')));
1840
+		}
1841
+		$template_args = array_merge($template_args, $price_args);
1842
+		$template      = apply_filters(
1843
+			'FHEE__Events_Admin_Page__get_ticket_row__template',
1844
+			EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_ticket_row.template.php',
1845
+			$ticket
1846
+		);
1847
+		return EEH_Template::display_template($template, $template_args, true);
1848
+	}
1849
+
1850
+
1851
+	/**
1852
+	 * @throws EE_Error
1853
+	 * @throws ReflectionException
1854
+	 */
1855
+	public function registration_options_meta_box()
1856
+	{
1857
+		$yes_no_values             = [
1858
+			['id' => true, 'text' => esc_html__('Yes', 'event_espresso')],
1859
+			['id' => false, 'text' => esc_html__('No', 'event_espresso')],
1860
+		];
1861
+		$default_reg_status_values = EEM_Registration::reg_status_array(
1862
+			[
1863
+				EEM_Registration::status_id_cancelled,
1864
+				EEM_Registration::status_id_declined,
1865
+				EEM_Registration::status_id_incomplete,
1866
+			],
1867
+			true
1868
+		);
1869
+		// $template_args['is_active_select'] = EEH_Form_Fields::select_input('is_active', $yes_no_values, $this->_cpt_model_obj->is_active());
1870
+		$template_args['_event']                          = $this->_cpt_model_obj;
1871
+		$template_args['event']                           = $this->_cpt_model_obj;
1872
+		$template_args['active_status']                   = $this->_cpt_model_obj->pretty_active_status(false);
1873
+		$template_args['additional_limit']                = $this->_cpt_model_obj->additional_limit();
1874
+		$template_args['default_registration_status']     = EEH_Form_Fields::select_input(
1875
+			'default_reg_status',
1876
+			$default_reg_status_values,
1877
+			$this->_cpt_model_obj->default_registration_status()
1878
+		);
1879
+		$template_args['display_description']             = EEH_Form_Fields::select_input(
1880
+			'display_desc',
1881
+			$yes_no_values,
1882
+			$this->_cpt_model_obj->display_description()
1883
+		);
1884
+		$template_args['display_ticket_selector']         = EEH_Form_Fields::select_input(
1885
+			'display_ticket_selector',
1886
+			$yes_no_values,
1887
+			$this->_cpt_model_obj->display_ticket_selector(),
1888
+			'',
1889
+			'',
1890
+			false
1891
+		);
1892
+		$template_args['additional_registration_options'] = apply_filters(
1893
+			'FHEE__Events_Admin_Page__registration_options_meta_box__additional_registration_options',
1894
+			'',
1895
+			$template_args,
1896
+			$yes_no_values,
1897
+			$default_reg_status_values
1898
+		);
1899
+		EEH_Template::display_template(
1900
+			EVENTS_TEMPLATE_PATH . 'event_registration_options.template.php',
1901
+			$template_args
1902
+		);
1903
+	}
1904
+
1905
+
1906
+	/**
1907
+	 * _get_events()
1908
+	 * This method simply returns all the events (for the given _view and paging)
1909
+	 *
1910
+	 * @access public
1911
+	 * @param int  $per_page     count of items per page (20 default);
1912
+	 * @param int  $current_page what is the current page being viewed.
1913
+	 * @param bool $count        if TRUE then we just return a count of ALL events matching the given _view.
1914
+	 *                           If FALSE then we return an array of event objects
1915
+	 *                           that match the given _view and paging parameters.
1916
+	 * @return array|int         an array of event objects or a count of them.
1917
+	 * @throws Exception
1918
+	 */
1919
+	public function get_events($per_page = 10, $current_page = 1, $count = false)
1920
+	{
1921
+		$EEM_Event   = $this->_event_model();
1922
+		$offset      = ($current_page - 1) * $per_page;
1923
+		$limit       = $count ? null : $offset . ',' . $per_page;
1924
+		$orderby     = $this->request->getRequestParam('orderby', 'EVT_ID');
1925
+		$order       = $this->request->getRequestParam('order', 'DESC');
1926
+		$month_range = $this->request->getRequestParam('month_range');
1927
+		if ($month_range) {
1928
+			$pieces = explode(' ', $month_range, 3);
1929
+			// simulate the FIRST day of the month, that fixes issues for months like February
1930
+			// where PHP doesn't know what to assume for date.
1931
+			// @see https://events.codebasehq.com/projects/event-espresso/tickets/10437
1932
+			$month_r = ! empty($pieces[0]) ? date('m', EEH_DTT_Helper::first_of_month_timestamp($pieces[0])) : '';
1933
+			$year_r  = ! empty($pieces[1]) ? $pieces[1] : '';
1934
+		}
1935
+		$where  = [];
1936
+		$status = $this->request->getRequestParam('status');
1937
+		// determine what post_status our condition will have for the query.
1938
+		switch ($status) {
1939
+			case 'month':
1940
+			case 'today':
1941
+			case null:
1942
+			case 'all':
1943
+				break;
1944
+			case 'draft':
1945
+				$where['status'] = ['IN', ['draft', 'auto-draft']];
1946
+				break;
1947
+			default:
1948
+				$where['status'] = $status;
1949
+		}
1950
+		// categories? The default for all categories is -1
1951
+		$category = $this->request->getRequestParam('EVT_CAT', -1, 'int');
1952
+		if ($category !== -1) {
1953
+			$where['Term_Taxonomy.taxonomy'] = EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY;
1954
+			$where['Term_Taxonomy.term_id']  = $category;
1955
+		}
1956
+		// date where conditions
1957
+		$start_formats = EEM_Datetime::instance()->get_formats_for('DTT_EVT_start');
1958
+		if ($month_range) {
1959
+			$DateTime = new DateTime(
1960
+				$year_r . '-' . $month_r . '-01 00:00:00',
1961
+				new DateTimeZone('UTC')
1962
+			);
1963
+			$start    = $DateTime->getTimestamp();
1964
+			// set the datetime to be the end of the month
1965
+			$DateTime->setDate(
1966
+				$year_r,
1967
+				$month_r,
1968
+				$DateTime->format('t')
1969
+			)->setTime(23, 59, 59);
1970
+			$end                             = $DateTime->getTimestamp();
1971
+			$where['Datetime.DTT_EVT_start'] = ['BETWEEN', [$start, $end]];
1972
+		} elseif ($status === 'today') {
1973
+			$DateTime                        =
1974
+				new DateTime('now', new DateTimeZone(EEM_Event::instance()->get_timezone()));
1975
+			$start                           = $DateTime->setTime(0, 0)->format(implode(' ', $start_formats));
1976
+			$end                             = $DateTime->setTime(23, 59, 59)->format(implode(' ', $start_formats));
1977
+			$where['Datetime.DTT_EVT_start'] = ['BETWEEN', [$start, $end]];
1978
+		} elseif ($status === 'month') {
1979
+			$now                             = date('Y-m-01');
1980
+			$DateTime                        =
1981
+				new DateTime($now, new DateTimeZone(EEM_Event::instance()->get_timezone()));
1982
+			$start                           = $DateTime->setTime(0, 0)->format(implode(' ', $start_formats));
1983
+			$end                             = $DateTime->setDate(date('Y'), date('m'), $DateTime->format('t'))
1984
+														->setTime(23, 59, 59)
1985
+														->format(implode(' ', $start_formats));
1986
+			$where['Datetime.DTT_EVT_start'] = ['BETWEEN', [$start, $end]];
1987
+		}
1988
+		if (! EE_Registry::instance()->CAP->current_user_can('ee_read_others_events', 'get_events')) {
1989
+			$where['EVT_wp_user'] = get_current_user_id();
1990
+		} else {
1991
+			if (! isset($where['status'])) {
1992
+				if (! EE_Registry::instance()->CAP->current_user_can('ee_read_private_events', 'get_events')) {
1993
+					$where['OR'] = [
1994
+						'status*restrict_private' => ['!=', 'private'],
1995
+						'AND'                     => [
1996
+							'status*inclusive' => ['=', 'private'],
1997
+							'EVT_wp_user'      => get_current_user_id(),
1998
+						],
1999
+					];
2000
+				}
2001
+			}
2002
+		}
2003
+		$wp_user = $this->request->getRequestParam('EVT_wp_user', 0, 'int');
2004
+		if (
2005
+			$wp_user
2006
+			&& $wp_user !== get_current_user_id()
2007
+			&& EE_Registry::instance()->CAP->current_user_can('ee_read_others_events', 'get_events')
2008
+		) {
2009
+			$where['EVT_wp_user'] = $wp_user;
2010
+		}
2011
+		// search query handling
2012
+		$search_term = $this->request->getRequestParam('s');
2013
+		if ($search_term) {
2014
+			$search_term = '%' . $search_term . '%';
2015
+			$where['OR'] = [
2016
+				'EVT_name'       => ['LIKE', $search_term],
2017
+				'EVT_desc'       => ['LIKE', $search_term],
2018
+				'EVT_short_desc' => ['LIKE', $search_term],
2019
+			];
2020
+		}
2021
+		// filter events by venue.
2022
+		$venue = $this->request->getRequestParam('venue', 0, 'int');
2023
+		if ($venue) {
2024
+			$where['Venue.VNU_ID'] = $venue;
2025
+		}
2026
+		$request_params = $this->request->requestParams();
2027
+		$where          = apply_filters('FHEE__Events_Admin_Page__get_events__where', $where, $request_params);
2028
+		$query_params   = apply_filters(
2029
+			'FHEE__Events_Admin_Page__get_events__query_params',
2030
+			[
2031
+				$where,
2032
+				'limit'    => $limit,
2033
+				'order_by' => $orderby,
2034
+				'order'    => $order,
2035
+				'group_by' => 'EVT_ID',
2036
+			],
2037
+			$request_params
2038
+		);
2039
+
2040
+		// let's first check if we have special requests coming in.
2041
+		$active_status = $this->request->getRequestParam('active_status');
2042
+		if ($active_status) {
2043
+			switch ($active_status) {
2044
+				case 'upcoming':
2045
+					return $EEM_Event->get_upcoming_events($query_params, $count);
2046
+				case 'expired':
2047
+					return $EEM_Event->get_expired_events($query_params, $count);
2048
+				case 'active':
2049
+					return $EEM_Event->get_active_events($query_params, $count);
2050
+				case 'inactive':
2051
+					return $EEM_Event->get_inactive_events($query_params, $count);
2052
+			}
2053
+		}
2054
+
2055
+		return $count ? $EEM_Event->count([$where], 'EVT_ID', true) : $EEM_Event->get_all($query_params);
2056
+	}
2057
+
2058
+
2059
+	/**
2060
+	 * handling for WordPress CPT actions (trash, restore, delete)
2061
+	 *
2062
+	 * @param string $post_id
2063
+	 * @throws EE_Error
2064
+	 * @throws ReflectionException
2065
+	 */
2066
+	public function trash_cpt_item($post_id)
2067
+	{
2068
+		$this->request->setRequestParam('EVT_ID', $post_id);
2069
+		$this->_trash_or_restore_event('trash', false);
2070
+	}
2071
+
2072
+
2073
+	/**
2074
+	 * @param string $post_id
2075
+	 * @throws EE_Error
2076
+	 * @throws ReflectionException
2077
+	 */
2078
+	public function restore_cpt_item($post_id)
2079
+	{
2080
+		$this->request->setRequestParam('EVT_ID', $post_id);
2081
+		$this->_trash_or_restore_event('draft', false);
2082
+	}
2083
+
2084
+
2085
+	/**
2086
+	 * @param string $post_id
2087
+	 * @throws EE_Error
2088
+	 * @throws EE_Error
2089
+	 */
2090
+	public function delete_cpt_item($post_id)
2091
+	{
2092
+		throw new EE_Error(
2093
+			esc_html__(
2094
+				'Please contact Event Espresso support with the details of the steps taken to produce this error.',
2095
+				'event_espresso'
2096
+			)
2097
+		);
2098
+		// $this->request->setRequestParam('EVT_ID', $post_id);
2099
+		// $this->_delete_event();
2100
+	}
2101
+
2102
+
2103
+	/**
2104
+	 * _trash_or_restore_event
2105
+	 *
2106
+	 * @access protected
2107
+	 * @param string $event_status
2108
+	 * @param bool   $redirect_after
2109
+	 * @throws EE_Error
2110
+	 * @throws EE_Error
2111
+	 * @throws ReflectionException
2112
+	 */
2113
+	protected function _trash_or_restore_event($event_status = 'trash', $redirect_after = true)
2114
+	{
2115
+		// determine the event id and set to array.
2116
+		$EVT_ID = $this->request->getRequestParam('EVT_ID', 0, 'int');
2117
+		// loop thru events
2118
+		if ($EVT_ID) {
2119
+			// clean status
2120
+			$event_status = sanitize_key($event_status);
2121
+			// grab status
2122
+			if (! empty($event_status)) {
2123
+				$success = $this->_change_event_status($EVT_ID, $event_status);
2124
+			} else {
2125
+				$success = false;
2126
+				$msg     = esc_html__(
2127
+					'An error occurred. The event could not be moved to the trash because a valid event status was not not supplied.',
2128
+					'event_espresso'
2129
+				);
2130
+				EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2131
+			}
2132
+		} else {
2133
+			$success = false;
2134
+			$msg     = esc_html__(
2135
+				'An error occurred. The event could not be moved to the trash because a valid event ID was not not supplied.',
2136
+				'event_espresso'
2137
+			);
2138
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2139
+		}
2140
+		$action = $event_status === 'trash' ? 'moved to the trash' : 'restored from the trash';
2141
+		if ($redirect_after) {
2142
+			$this->_redirect_after_action($success, 'Event', $action, ['action' => 'default']);
2143
+		}
2144
+	}
2145
+
2146
+
2147
+	/**
2148
+	 * _trash_or_restore_events
2149
+	 *
2150
+	 * @access protected
2151
+	 * @param string $event_status
2152
+	 * @return void
2153
+	 * @throws EE_Error
2154
+	 * @throws EE_Error
2155
+	 * @throws ReflectionException
2156
+	 */
2157
+	protected function _trash_or_restore_events($event_status = 'trash')
2158
+	{
2159
+		// clean status
2160
+		$event_status = sanitize_key($event_status);
2161
+		// grab status
2162
+		if (! empty($event_status)) {
2163
+			$success = true;
2164
+			// determine the event id and set to array.
2165
+			$EVT_IDs = $this->request->getRequestParam('EVT_IDs', [], 'int', true);
2166
+			// loop thru events
2167
+			foreach ($EVT_IDs as $EVT_ID) {
2168
+				if ($EVT_ID = absint($EVT_ID)) {
2169
+					$results = $this->_change_event_status($EVT_ID, $event_status);
2170
+					$success = $results !== false ? $success : false;
2171
+				} else {
2172
+					$msg = sprintf(
2173
+						esc_html__(
2174
+							'An error occurred. Event #%d could not be moved to the trash because a valid event ID was not not supplied.',
2175
+							'event_espresso'
2176
+						),
2177
+						$EVT_ID
2178
+					);
2179
+					EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2180
+					$success = false;
2181
+				}
2182
+			}
2183
+		} else {
2184
+			$success = false;
2185
+			$msg     = esc_html__(
2186
+				'An error occurred. The event could not be moved to the trash because a valid event status was not not supplied.',
2187
+				'event_espresso'
2188
+			);
2189
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2190
+		}
2191
+		// in order to force a pluralized result message we need to send back a success status greater than 1
2192
+		$success = $success ? 2 : false;
2193
+		$action  = $event_status === 'trash' ? 'moved to the trash' : 'restored from the trash';
2194
+		$this->_redirect_after_action($success, 'Events', $action, ['action' => 'default']);
2195
+	}
2196
+
2197
+
2198
+	/**
2199
+	 * @param int    $EVT_ID
2200
+	 * @param string $event_status
2201
+	 * @return bool
2202
+	 * @throws EE_Error
2203
+	 * @throws ReflectionException
2204
+	 */
2205
+	private function _change_event_status($EVT_ID = 0, $event_status = '')
2206
+	{
2207
+		// grab event id
2208
+		if (! $EVT_ID) {
2209
+			$msg = esc_html__(
2210
+				'An error occurred. No Event ID or an invalid Event ID was received.',
2211
+				'event_espresso'
2212
+			);
2213
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2214
+			return false;
2215
+		}
2216
+		$this->_cpt_model_obj = EEM_Event::instance()->get_one_by_ID($EVT_ID);
2217
+		// clean status
2218
+		$event_status = sanitize_key($event_status);
2219
+		// grab status
2220
+		if (empty($event_status)) {
2221
+			$msg = esc_html__(
2222
+				'An error occurred. No Event Status or an invalid Event Status was received.',
2223
+				'event_espresso'
2224
+			);
2225
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2226
+			return false;
2227
+		}
2228
+		// was event trashed or restored ?
2229
+		switch ($event_status) {
2230
+			case 'draft':
2231
+				$action = 'restored from the trash';
2232
+				$hook   = 'AHEE_event_restored_from_trash';
2233
+				break;
2234
+			case 'trash':
2235
+				$action = 'moved to the trash';
2236
+				$hook   = 'AHEE_event_moved_to_trash';
2237
+				break;
2238
+			default:
2239
+				$action = 'updated';
2240
+				$hook   = false;
2241
+		}
2242
+		// use class to change status
2243
+		$this->_cpt_model_obj->set_status($event_status);
2244
+		$success = $this->_cpt_model_obj->save();
2245
+		if (! $success) {
2246
+			$msg = sprintf(esc_html__('An error occurred. The event could not be %s.', 'event_espresso'), $action);
2247
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2248
+			return false;
2249
+		}
2250
+		if ($hook) {
2251
+			do_action($hook);
2252
+		}
2253
+		return true;
2254
+	}
2255
+
2256
+
2257
+	/**
2258
+	 * @param array $event_ids
2259
+	 * @return array
2260
+	 * @since   4.10.23.p
2261
+	 */
2262
+	private function cleanEventIds(array $event_ids)
2263
+	{
2264
+		return array_map('absint', $event_ids);
2265
+	}
2266
+
2267
+
2268
+	/**
2269
+	 * @return array
2270
+	 * @since   4.10.23.p
2271
+	 */
2272
+	private function getEventIdsFromRequest()
2273
+	{
2274
+		if ($this->request->requestParamIsSet('EVT_IDs')) {
2275
+			return $this->request->getRequestParam('EVT_IDs', [], 'int', true);
2276
+		} else {
2277
+			return $this->request->getRequestParam('EVT_ID', [], 'int', true);
2278
+		}
2279
+	}
2280
+
2281
+
2282
+	/**
2283
+	 * @param bool $preview_delete
2284
+	 * @throws EE_Error
2285
+	 */
2286
+	protected function _delete_event($preview_delete = true)
2287
+	{
2288
+		$this->_delete_events($preview_delete);
2289
+	}
2290
+
2291
+
2292
+	/**
2293
+	 * Gets the tree traversal batch persister.
2294
+	 *
2295
+	 * @return NodeGroupDao
2296
+	 * @throws InvalidArgumentException
2297
+	 * @throws InvalidDataTypeException
2298
+	 * @throws InvalidInterfaceException
2299
+	 * @since 4.10.12.p
2300
+	 */
2301
+	protected function getModelObjNodeGroupPersister()
2302
+	{
2303
+		if (! $this->model_obj_node_group_persister instanceof NodeGroupDao) {
2304
+			$this->model_obj_node_group_persister =
2305
+				$this->getLoader()->load('\EventEspresso\core\services\orm\tree_traversal\NodeGroupDao');
2306
+		}
2307
+		return $this->model_obj_node_group_persister;
2308
+	}
2309
+
2310
+
2311
+	/**
2312
+	 * @param bool $preview_delete
2313
+	 * @return void
2314
+	 * @throws EE_Error
2315
+	 */
2316
+	protected function _delete_events($preview_delete = true)
2317
+	{
2318
+		$event_ids = $this->getEventIdsFromRequest();
2319
+		if ($preview_delete) {
2320
+			$this->generateDeletionPreview($event_ids);
2321
+		} else {
2322
+			EEM_Event::instance()->delete_permanently([['EVT_ID' => ['IN', $event_ids]]]);
2323
+		}
2324
+	}
2325
+
2326
+
2327
+	/**
2328
+	 * @param array $event_ids
2329
+	 */
2330
+	protected function generateDeletionPreview(array $event_ids)
2331
+	{
2332
+		$event_ids = $this->cleanEventIds($event_ids);
2333
+		// Set a code we can use to reference this deletion task in the batch jobs and preview page.
2334
+		$deletion_job_code = $this->getModelObjNodeGroupPersister()->generateGroupCode();
2335
+		$return_url        = EE_Admin_Page::add_query_args_and_nonce(
2336
+			[
2337
+				'action'            => 'preview_deletion',
2338
+				'deletion_job_code' => $deletion_job_code,
2339
+			],
2340
+			$this->_admin_base_url
2341
+		);
2342
+		EEH_URL::safeRedirectAndExit(
2343
+			EE_Admin_Page::add_query_args_and_nonce(
2344
+				[
2345
+					'page'              => EED_Batch::PAGE_SLUG,
2346
+					'batch'             => EED_Batch::batch_job,
2347
+					'EVT_IDs'           => $event_ids,
2348
+					'deletion_job_code' => $deletion_job_code,
2349
+					'job_handler'       => urlencode('EventEspressoBatchRequest\JobHandlers\PreviewEventDeletion'),
2350
+					'return_url'        => urlencode($return_url),
2351
+				],
2352
+				admin_url()
2353
+			)
2354
+		);
2355
+	}
2356
+
2357
+
2358
+	/**
2359
+	 * Checks for a POST submission
2360
+	 *
2361
+	 * @since 4.10.12.p
2362
+	 */
2363
+	protected function confirmDeletion()
2364
+	{
2365
+		$deletion_redirect_logic =
2366
+			$this->getLoader()->getShared('\EventEspresso\core\domain\services\admin\events\data\ConfirmDeletion');
2367
+		$deletion_redirect_logic->handle($this->get_request_data(), $this->admin_base_url());
2368
+	}
2369
+
2370
+
2371
+	/**
2372
+	 * A page for users to preview what exactly will be deleted, and confirm they want to delete it.
2373
+	 *
2374
+	 * @throws EE_Error
2375
+	 * @since 4.10.12.p
2376
+	 */
2377
+	protected function previewDeletion()
2378
+	{
2379
+		$preview_deletion_logic =
2380
+			$this->getLoader()->getShared('\EventEspresso\core\domain\services\admin\events\data\PreviewDeletion');
2381
+		$this->set_template_args($preview_deletion_logic->handle($this->get_request_data(), $this->admin_base_url()));
2382
+		$this->display_admin_page_with_no_sidebar();
2383
+	}
2384
+
2385
+
2386
+	/**
2387
+	 * get total number of events
2388
+	 *
2389
+	 * @access public
2390
+	 * @return int
2391
+	 * @throws EE_Error
2392
+	 * @throws EE_Error
2393
+	 */
2394
+	public function total_events()
2395
+	{
2396
+		return EEM_Event::instance()->count(
2397
+			['caps' => 'read_admin'],
2398
+			'EVT_ID',
2399
+			true
2400
+		);
2401
+	}
2402
+
2403
+
2404
+	/**
2405
+	 * get total number of draft events
2406
+	 *
2407
+	 * @access public
2408
+	 * @return int
2409
+	 * @throws EE_Error
2410
+	 * @throws EE_Error
2411
+	 */
2412
+	public function total_events_draft()
2413
+	{
2414
+		return EEM_Event::instance()->count(
2415
+			[
2416
+				['status' => ['IN', ['draft', 'auto-draft']]],
2417
+				'caps' => 'read_admin',
2418
+			],
2419
+			'EVT_ID',
2420
+			true
2421
+		);
2422
+	}
2423
+
2424
+
2425
+	/**
2426
+	 * get total number of trashed events
2427
+	 *
2428
+	 * @access public
2429
+	 * @return int
2430
+	 * @throws EE_Error
2431
+	 * @throws EE_Error
2432
+	 */
2433
+	public function total_trashed_events()
2434
+	{
2435
+		return EEM_Event::instance()->count(
2436
+			[
2437
+				['status' => 'trash'],
2438
+				'caps' => 'read_admin',
2439
+			],
2440
+			'EVT_ID',
2441
+			true
2442
+		);
2443
+	}
2444
+
2445
+
2446
+	/**
2447
+	 *    _default_event_settings
2448
+	 *    This generates the Default Settings Tab
2449
+	 *
2450
+	 * @return void
2451
+	 * @throws DomainException
2452
+	 * @throws EE_Error
2453
+	 * @throws InvalidArgumentException
2454
+	 * @throws InvalidDataTypeException
2455
+	 * @throws InvalidInterfaceException
2456
+	 */
2457
+	protected function _default_event_settings()
2458
+	{
2459
+		$this->_set_add_edit_form_tags('update_default_event_settings');
2460
+		$this->_set_publish_post_box_vars(null, false, false, null, false);
2461
+		$this->_template_args['admin_page_content'] = EEH_HTML::div(
2462
+			$this->_default_event_settings_form()->get_html(),
2463
+			'',
2464
+			'padding'
2465
+		);
2466
+		$this->display_admin_page_with_sidebar();
2467
+	}
2468
+
2469
+
2470
+	/**
2471
+	 * Return the form for event settings.
2472
+	 *
2473
+	 * @return EE_Form_Section_Proper
2474
+	 * @throws EE_Error
2475
+	 */
2476
+	protected function _default_event_settings_form()
2477
+	{
2478
+		$registration_config              = EE_Registry::instance()->CFG->registration;
2479
+		$registration_stati_for_selection = EEM_Registration::reg_status_array(
2480
+		// exclude
2481
+			[
2482
+				EEM_Registration::status_id_cancelled,
2483
+				EEM_Registration::status_id_declined,
2484
+				EEM_Registration::status_id_incomplete,
2485
+				EEM_Registration::status_id_wait_list,
2486
+			],
2487
+			true
2488
+		);
2489
+		// setup Advanced Editor ???
2490
+		if (
2491
+			$this->raw_req_action === 'default_event_settings'
2492
+			|| $this->raw_req_action === 'update_default_event_settings'
2493
+		) {
2494
+			$this->advanced_editor_admin_form = $this->loader->getShared(AdvancedEditorAdminFormSection::class);
2495
+		}
2496
+		return new EE_Form_Section_Proper(
2497
+			[
2498
+				'name'            => 'update_default_event_settings',
2499
+				'html_id'         => 'update_default_event_settings',
2500
+				'html_class'      => 'form-table',
2501
+				'layout_strategy' => new EE_Admin_Two_Column_Layout(),
2502
+				'subsections'     => apply_filters(
2503
+					'FHEE__Events_Admin_Page___default_event_settings_form__form_subsections',
2504
+					[
2505
+						'defaults_section_header' => new EE_Form_Section_HTML(
2506
+							EEH_HTML::h2(
2507
+								esc_html__('Default Settings', 'event_espresso'),
2508
+								'',
2509
+								'ee-admin-settings-hdr'
2510
+							)
2511
+						),
2512
+						'default_reg_status'  => new EE_Select_Input(
2513
+							$registration_stati_for_selection,
2514
+							[
2515
+								'default'         => isset($registration_config->default_STS_ID)
2516
+													 && array_key_exists(
2517
+														 $registration_config->default_STS_ID,
2518
+														 $registration_stati_for_selection
2519
+													 )
2520
+									? sanitize_text_field($registration_config->default_STS_ID)
2521
+									: EEM_Registration::status_id_pending_payment,
2522
+								'html_label_text' => esc_html__('Default Registration Status', 'event_espresso')
2523
+													 . EEH_Template::get_help_tab_link(
2524
+														 'default_settings_status_help_tab'
2525
+													 ),
2526
+								'html_help_text'  => esc_html__(
2527
+									'This setting allows you to preselect what the default registration status setting is when creating an event.  Note that changing this setting does NOT retroactively apply it to existing events.',
2528
+									'event_espresso'
2529
+								),
2530
+							]
2531
+						),
2532
+						'default_max_tickets' => new EE_Integer_Input(
2533
+							[
2534
+								'default'         => isset($registration_config->default_maximum_number_of_tickets)
2535
+									? $registration_config->default_maximum_number_of_tickets
2536
+									: EEM_Event::get_default_additional_limit(),
2537
+								'html_label_text' => esc_html__(
2538
+									'Default Maximum Tickets Allowed Per Order:',
2539
+									'event_espresso'
2540
+								)
2541
+													 . EEH_Template::get_help_tab_link(
2542
+														 'default_maximum_tickets_help_tab"'
2543
+													 ),
2544
+								'html_help_text'  => esc_html__(
2545
+									'This setting allows you to indicate what will be the default for the maximum number of tickets per order when creating new events.',
2546
+									'event_espresso'
2547
+								),
2548
+							]
2549
+						),
2550
+					]
2551
+				),
2552
+			]
2553
+		);
2554
+	}
2555
+
2556
+
2557
+	/**
2558
+	 * @return void
2559
+	 * @throws EE_Error
2560
+	 * @throws InvalidArgumentException
2561
+	 * @throws InvalidDataTypeException
2562
+	 * @throws InvalidInterfaceException
2563
+	 */
2564
+	protected function _update_default_event_settings()
2565
+	{
2566
+		$form = $this->_default_event_settings_form();
2567
+		if ($form->was_submitted()) {
2568
+			$form->receive_form_submission();
2569
+			if ($form->is_valid()) {
2570
+				$registration_config = EE_Registry::instance()->CFG->registration;
2571
+				$valid_data          = $form->valid_data();
2572
+				if (isset($valid_data['default_reg_status'])) {
2573
+					$registration_config->default_STS_ID = $valid_data['default_reg_status'];
2574
+				}
2575
+				if (isset($valid_data['default_max_tickets'])) {
2576
+					$registration_config->default_maximum_number_of_tickets = $valid_data['default_max_tickets'];
2577
+				}
2578
+				do_action(
2579
+					'AHEE__Events_Admin_Page___update_default_event_settings',
2580
+					$valid_data,
2581
+					EE_Registry::instance()->CFG,
2582
+					$this
2583
+				);
2584
+				// update because data was valid!
2585
+				EE_Registry::instance()->CFG->update_espresso_config();
2586
+				EE_Error::overwrite_success();
2587
+				EE_Error::add_success(
2588
+					esc_html__('Default Event Settings were updated', 'event_espresso')
2589
+				);
2590
+			}
2591
+		}
2592
+		$this->_redirect_after_action(0, '', '', ['action' => 'default_event_settings'], true);
2593
+	}
2594
+
2595
+
2596
+	/*************        Templates        *************
21 2597
      *
22
-     * @var EE_Event $_event
23
-     */
24
-    protected $_event;
25
-
26
-
27
-    /**
28
-     * This will hold the category object for category_details screen.
29
-     *
30
-     * @var stdClass $_category
31
-     */
32
-    protected $_category;
33
-
34
-
35
-    /**
36
-     * This will hold the event model instance
37
-     *
38
-     * @var EEM_Event $_event_model
39
-     */
40
-    protected $_event_model;
41
-
42
-
43
-    /**
44
-     * @var EE_Event
45
-     */
46
-    protected $_cpt_model_obj = false;
47
-
48
-
49
-    /**
50
-     * @var NodeGroupDao
51
-     */
52
-    protected $model_obj_node_group_persister;
53
-
54
-    /**
55
-     * @var AdvancedEditorAdminFormSection
56
-     */
57
-    protected $advanced_editor_admin_form;
58
-
59
-
60
-    /**
61
-     * Initialize page props for this admin page group.
62
-     */
63
-    protected function _init_page_props()
64
-    {
65
-        $this->page_slug        = EVENTS_PG_SLUG;
66
-        $this->page_label       = EVENTS_LABEL;
67
-        $this->_admin_base_url  = EVENTS_ADMIN_URL;
68
-        $this->_admin_base_path = EVENTS_ADMIN;
69
-        $this->_cpt_model_names = [
70
-            'create_new' => 'EEM_Event',
71
-            'edit'       => 'EEM_Event',
72
-        ];
73
-        $this->_cpt_edit_routes = [
74
-            'espresso_events' => 'edit',
75
-        ];
76
-        add_action(
77
-            'AHEE__EE_Admin_Page_CPT__set_model_object__after_set_object',
78
-            [$this, 'verify_event_edit'],
79
-            10,
80
-            2
81
-        );
82
-    }
83
-
84
-
85
-    /**
86
-     * Sets the ajax hooks used for this admin page group.
87
-     */
88
-    protected function _ajax_hooks()
89
-    {
90
-        add_action('wp_ajax_ee_save_timezone_setting', [$this, 'saveTimezoneString']);
91
-    }
92
-
93
-
94
-    /**
95
-     * Sets the page properties for this admin page group.
96
-     */
97
-    protected function _define_page_props()
98
-    {
99
-        $this->_admin_page_title = EVENTS_LABEL;
100
-        $this->_labels           = [
101
-            'buttons'      => [
102
-                'add'             => esc_html__('Add New Event', 'event_espresso'),
103
-                'edit'            => esc_html__('Edit Event', 'event_espresso'),
104
-                'delete'          => esc_html__('Delete Event', 'event_espresso'),
105
-                'add_category'    => esc_html__('Add New Category', 'event_espresso'),
106
-                'edit_category'   => esc_html__('Edit Category', 'event_espresso'),
107
-                'delete_category' => esc_html__('Delete Category', 'event_espresso'),
108
-            ],
109
-            'editor_title' => [
110
-                'espresso_events' => esc_html__('Enter event title here', 'event_espresso'),
111
-            ],
112
-            'publishbox'   => [
113
-                'create_new'        => esc_html__('Save New Event', 'event_espresso'),
114
-                'edit'              => esc_html__('Update Event', 'event_espresso'),
115
-                'add_category'      => esc_html__('Save New Category', 'event_espresso'),
116
-                'edit_category'     => esc_html__('Update Category', 'event_espresso'),
117
-                'template_settings' => esc_html__('Update Settings', 'event_espresso'),
118
-            ],
119
-        ];
120
-    }
121
-
122
-
123
-    /**
124
-     * Sets the page routes property for this admin page group.
125
-     */
126
-    protected function _set_page_routes()
127
-    {
128
-        // load formatter helper
129
-        // load field generator helper
130
-        // is there a evt_id in the request?
131
-        $EVT_ID = $this->request->getRequestParam('EVT_ID', 0, 'int');
132
-        $EVT_ID = $this->request->getRequestParam('post', $EVT_ID, 'int');
133
-
134
-        $this->_page_routes = [
135
-            'default'                       => [
136
-                'func'       => '_events_overview_list_table',
137
-                'capability' => 'ee_read_events',
138
-            ],
139
-            'create_new'                    => [
140
-                'func'       => '_create_new_cpt_item',
141
-                'capability' => 'ee_edit_events',
142
-            ],
143
-            'edit'                          => [
144
-                'func'       => '_edit_cpt_item',
145
-                'capability' => 'ee_edit_event',
146
-                'obj_id'     => $EVT_ID,
147
-            ],
148
-            'copy_event'                    => [
149
-                'func'       => '_copy_events',
150
-                'capability' => 'ee_edit_event',
151
-                'obj_id'     => $EVT_ID,
152
-                'noheader'   => true,
153
-            ],
154
-            'trash_event'                   => [
155
-                'func'       => '_trash_or_restore_event',
156
-                'args'       => ['event_status' => 'trash'],
157
-                'capability' => 'ee_delete_event',
158
-                'obj_id'     => $EVT_ID,
159
-                'noheader'   => true,
160
-            ],
161
-            'trash_events'                  => [
162
-                'func'       => '_trash_or_restore_events',
163
-                'args'       => ['event_status' => 'trash'],
164
-                'capability' => 'ee_delete_events',
165
-                'noheader'   => true,
166
-            ],
167
-            'restore_event'                 => [
168
-                'func'       => '_trash_or_restore_event',
169
-                'args'       => ['event_status' => 'draft'],
170
-                'capability' => 'ee_delete_event',
171
-                'obj_id'     => $EVT_ID,
172
-                'noheader'   => true,
173
-            ],
174
-            'restore_events'                => [
175
-                'func'       => '_trash_or_restore_events',
176
-                'args'       => ['event_status' => 'draft'],
177
-                'capability' => 'ee_delete_events',
178
-                'noheader'   => true,
179
-            ],
180
-            'delete_event'                  => [
181
-                'func'       => '_delete_event',
182
-                'capability' => 'ee_delete_event',
183
-                'obj_id'     => $EVT_ID,
184
-                'noheader'   => true,
185
-            ],
186
-            'delete_events'                 => [
187
-                'func'       => '_delete_events',
188
-                'capability' => 'ee_delete_events',
189
-                'noheader'   => true,
190
-            ],
191
-            'view_report'                   => [
192
-                'func'       => '_view_report',
193
-                'capability' => 'ee_edit_events',
194
-            ],
195
-            'default_event_settings'        => [
196
-                'func'       => '_default_event_settings',
197
-                'capability' => 'manage_options',
198
-            ],
199
-            'update_default_event_settings' => [
200
-                'func'       => '_update_default_event_settings',
201
-                'capability' => 'manage_options',
202
-                'noheader'   => true,
203
-            ],
204
-            'template_settings'             => [
205
-                'func'       => '_template_settings',
206
-                'capability' => 'manage_options',
207
-            ],
208
-            // event category tab related
209
-            'add_category'                  => [
210
-                'func'       => '_category_details',
211
-                'capability' => 'ee_edit_event_category',
212
-                'args'       => ['add'],
213
-            ],
214
-            'edit_category'                 => [
215
-                'func'       => '_category_details',
216
-                'capability' => 'ee_edit_event_category',
217
-                'args'       => ['edit'],
218
-            ],
219
-            'delete_categories'             => [
220
-                'func'       => '_delete_categories',
221
-                'capability' => 'ee_delete_event_category',
222
-                'noheader'   => true,
223
-            ],
224
-            'delete_category'               => [
225
-                'func'       => '_delete_categories',
226
-                'capability' => 'ee_delete_event_category',
227
-                'noheader'   => true,
228
-            ],
229
-            'insert_category'               => [
230
-                'func'       => '_insert_or_update_category',
231
-                'args'       => ['new_category' => true],
232
-                'capability' => 'ee_edit_event_category',
233
-                'noheader'   => true,
234
-            ],
235
-            'update_category'               => [
236
-                'func'       => '_insert_or_update_category',
237
-                'args'       => ['new_category' => false],
238
-                'capability' => 'ee_edit_event_category',
239
-                'noheader'   => true,
240
-            ],
241
-            'category_list'                 => [
242
-                'func'       => '_category_list_table',
243
-                'capability' => 'ee_manage_event_categories',
244
-            ],
245
-            'preview_deletion'              => [
246
-                'func'       => 'previewDeletion',
247
-                'capability' => 'ee_delete_events',
248
-            ],
249
-            'confirm_deletion'              => [
250
-                'func'       => 'confirmDeletion',
251
-                'capability' => 'ee_delete_events',
252
-                'noheader'   => true,
253
-            ],
254
-        ];
255
-    }
256
-
257
-
258
-    /**
259
-     * Set the _page_config property for this admin page group.
260
-     */
261
-    protected function _set_page_config()
262
-    {
263
-        $post_id            = $this->request->getRequestParam('post', 0, 'int');
264
-        $EVT_CAT_ID         = $this->request->getRequestParam('EVT_CAT_ID', 0, 'int');
265
-        $this->_page_config = [
266
-            'default'                => [
267
-                'nav'           => [
268
-                    'label' => esc_html__('Overview', 'event_espresso'),
269
-                    'icon' => 'dashicons-list-view',
270
-                    'order' => 10,
271
-                ],
272
-                'list_table'    => 'Events_Admin_List_Table',
273
-                'help_tabs'     => [
274
-                    'events_overview_help_tab'                       => [
275
-                        'title'    => esc_html__('Events Overview', 'event_espresso'),
276
-                        'filename' => 'events_overview',
277
-                    ],
278
-                    'events_overview_table_column_headings_help_tab' => [
279
-                        'title'    => esc_html__('Events Overview Table Column Headings', 'event_espresso'),
280
-                        'filename' => 'events_overview_table_column_headings',
281
-                    ],
282
-                    'events_overview_filters_help_tab'               => [
283
-                        'title'    => esc_html__('Events Overview Filters', 'event_espresso'),
284
-                        'filename' => 'events_overview_filters',
285
-                    ],
286
-                    'events_overview_view_help_tab'                  => [
287
-                        'title'    => esc_html__('Events Overview Views', 'event_espresso'),
288
-                        'filename' => 'events_overview_views',
289
-                    ],
290
-                    'events_overview_other_help_tab'                 => [
291
-                        'title'    => esc_html__('Events Overview Other', 'event_espresso'),
292
-                        'filename' => 'events_overview_other',
293
-                    ],
294
-                ],
295
-                'require_nonce' => false,
296
-            ],
297
-            'create_new'             => [
298
-                'nav'           => [
299
-                    'label'      => esc_html__('Add New Event', 'event_espresso'),
300
-                    'icon' => 'dashicons-plus-alt',
301
-                    'order'      => 15,
302
-                    'persistent' => false,
303
-                ],
304
-                'metaboxes'     => ['_register_event_editor_meta_boxes'],
305
-                'help_tabs'     => [
306
-                    'event_editor_help_tab'                            => [
307
-                        'title'    => esc_html__('Event Editor', 'event_espresso'),
308
-                        'filename' => 'event_editor',
309
-                    ],
310
-                    'event_editor_title_richtexteditor_help_tab'       => [
311
-                        'title'    => esc_html__('Event Title & Rich Text Editor', 'event_espresso'),
312
-                        'filename' => 'event_editor_title_richtexteditor',
313
-                    ],
314
-                    'event_editor_venue_details_help_tab'              => [
315
-                        'title'    => esc_html__('Event Venue Details', 'event_espresso'),
316
-                        'filename' => 'event_editor_venue_details',
317
-                    ],
318
-                    'event_editor_event_datetimes_help_tab'            => [
319
-                        'title'    => esc_html__('Event Datetimes', 'event_espresso'),
320
-                        'filename' => 'event_editor_event_datetimes',
321
-                    ],
322
-                    'event_editor_event_tickets_help_tab'              => [
323
-                        'title'    => esc_html__('Event Tickets', 'event_espresso'),
324
-                        'filename' => 'event_editor_event_tickets',
325
-                    ],
326
-                    'event_editor_event_registration_options_help_tab' => [
327
-                        'title'    => esc_html__('Event Registration Options', 'event_espresso'),
328
-                        'filename' => 'event_editor_event_registration_options',
329
-                    ],
330
-                    'event_editor_tags_categories_help_tab'            => [
331
-                        'title'    => esc_html__('Event Tags & Categories', 'event_espresso'),
332
-                        'filename' => 'event_editor_tags_categories',
333
-                    ],
334
-                    'event_editor_questions_registrants_help_tab'      => [
335
-                        'title'    => esc_html__('Questions for Registrants', 'event_espresso'),
336
-                        'filename' => 'event_editor_questions_registrants',
337
-                    ],
338
-                    'event_editor_save_new_event_help_tab'             => [
339
-                        'title'    => esc_html__('Save New Event', 'event_espresso'),
340
-                        'filename' => 'event_editor_save_new_event',
341
-                    ],
342
-                    'event_editor_other_help_tab'                      => [
343
-                        'title'    => esc_html__('Event Other', 'event_espresso'),
344
-                        'filename' => 'event_editor_other',
345
-                    ],
346
-                ],
347
-                'qtips'         => ['EE_Event_Editor_Decaf_Tips'],
348
-                'require_nonce' => false,
349
-            ],
350
-            'edit'                   => [
351
-                'nav'           => [
352
-                    'label'      => esc_html__('Edit Event', 'event_espresso'),
353
-                    'icon' => 'dashicons-edit',
354
-                    'order'      => 15,
355
-                    'persistent' => false,
356
-                    'url'        => $post_id
357
-                        ? EE_Admin_Page::add_query_args_and_nonce(
358
-                            ['post' => $post_id, 'action' => 'edit'],
359
-                            $this->_current_page_view_url
360
-                        )
361
-                        : $this->_admin_base_url,
362
-                ],
363
-                'metaboxes'     => ['_register_event_editor_meta_boxes'],
364
-                'help_tabs'     => [
365
-                    'event_editor_help_tab'                            => [
366
-                        'title'    => esc_html__('Event Editor', 'event_espresso'),
367
-                        'filename' => 'event_editor',
368
-                    ],
369
-                    'event_editor_title_richtexteditor_help_tab'       => [
370
-                        'title'    => esc_html__('Event Title & Rich Text Editor', 'event_espresso'),
371
-                        'filename' => 'event_editor_title_richtexteditor',
372
-                    ],
373
-                    'event_editor_venue_details_help_tab'              => [
374
-                        'title'    => esc_html__('Event Venue Details', 'event_espresso'),
375
-                        'filename' => 'event_editor_venue_details',
376
-                    ],
377
-                    'event_editor_event_datetimes_help_tab'            => [
378
-                        'title'    => esc_html__('Event Datetimes', 'event_espresso'),
379
-                        'filename' => 'event_editor_event_datetimes',
380
-                    ],
381
-                    'event_editor_event_tickets_help_tab'              => [
382
-                        'title'    => esc_html__('Event Tickets', 'event_espresso'),
383
-                        'filename' => 'event_editor_event_tickets',
384
-                    ],
385
-                    'event_editor_event_registration_options_help_tab' => [
386
-                        'title'    => esc_html__('Event Registration Options', 'event_espresso'),
387
-                        'filename' => 'event_editor_event_registration_options',
388
-                    ],
389
-                    'event_editor_tags_categories_help_tab'            => [
390
-                        'title'    => esc_html__('Event Tags & Categories', 'event_espresso'),
391
-                        'filename' => 'event_editor_tags_categories',
392
-                    ],
393
-                    'event_editor_questions_registrants_help_tab'      => [
394
-                        'title'    => esc_html__('Questions for Registrants', 'event_espresso'),
395
-                        'filename' => 'event_editor_questions_registrants',
396
-                    ],
397
-                    'event_editor_save_new_event_help_tab'             => [
398
-                        'title'    => esc_html__('Save New Event', 'event_espresso'),
399
-                        'filename' => 'event_editor_save_new_event',
400
-                    ],
401
-                    'event_editor_other_help_tab'                      => [
402
-                        'title'    => esc_html__('Event Other', 'event_espresso'),
403
-                        'filename' => 'event_editor_other',
404
-                    ],
405
-                ],
406
-                'require_nonce' => false,
407
-            ],
408
-            'default_event_settings' => [
409
-                'nav'           => [
410
-                    'label' => esc_html__('Default Settings', 'event_espresso'),
411
-                    'icon' => 'dashicons-admin-generic',
412
-                    'order' => 40,
413
-                ],
414
-                'metaboxes'     => array_merge(['_publish_post_box'], $this->_default_espresso_metaboxes),
415
-                'labels'        => [
416
-                    'publishbox' => esc_html__('Update Settings', 'event_espresso'),
417
-                ],
418
-                'help_tabs'     => [
419
-                    'default_settings_help_tab'        => [
420
-                        'title'    => esc_html__('Default Event Settings', 'event_espresso'),
421
-                        'filename' => 'events_default_settings',
422
-                    ],
423
-                    'default_settings_status_help_tab' => [
424
-                        'title'    => esc_html__('Default Registration Status', 'event_espresso'),
425
-                        'filename' => 'events_default_settings_status',
426
-                    ],
427
-                    'default_maximum_tickets_help_tab' => [
428
-                        'title'    => esc_html__('Default Maximum Tickets Per Order', 'event_espresso'),
429
-                        'filename' => 'events_default_settings_max_tickets',
430
-                    ],
431
-                ],
432
-                'require_nonce' => false,
433
-            ],
434
-            // template settings
435
-            'template_settings'      => [
436
-                'nav'           => [
437
-                    'label' => esc_html__('Templates', 'event_espresso'),
438
-                    'icon' => 'dashicons-layout',
439
-                    'order' => 30,
440
-                ],
441
-                'metaboxes'     => $this->_default_espresso_metaboxes,
442
-                'help_tabs'     => [
443
-                    'general_settings_templates_help_tab' => [
444
-                        'title'    => esc_html__('Templates', 'event_espresso'),
445
-                        'filename' => 'general_settings_templates',
446
-                    ],
447
-                ],
448
-                'require_nonce' => false,
449
-            ],
450
-            // event category stuff
451
-            'add_category'           => [
452
-                'nav'           => [
453
-                    'label'      => esc_html__('Add Category', 'event_espresso'),
454
-                    'icon' => 'dashicons-plus-alt',
455
-                    'order'      => 25,
456
-                    'persistent' => false,
457
-                ],
458
-                'help_tabs'     => [
459
-                    'add_category_help_tab' => [
460
-                        'title'    => esc_html__('Add New Event Category', 'event_espresso'),
461
-                        'filename' => 'events_add_category',
462
-                    ],
463
-                ],
464
-                'metaboxes'     => ['_publish_post_box'],
465
-                'require_nonce' => false,
466
-            ],
467
-            'edit_category'          => [
468
-                'nav'           => [
469
-                    'label'      => esc_html__('Edit Category', 'event_espresso'),
470
-                    'icon' => 'dashicons-edit',
471
-                    'order'      => 25,
472
-                    'persistent' => false,
473
-                    'url'        => $EVT_CAT_ID
474
-                        ? add_query_arg(
475
-                            ['EVT_CAT_ID' => $EVT_CAT_ID],
476
-                            $this->_current_page_view_url
477
-                        )
478
-                        : $this->_admin_base_url,
479
-                ],
480
-                'help_tabs'     => [
481
-                    'edit_category_help_tab' => [
482
-                        'title'    => esc_html__('Edit Event Category', 'event_espresso'),
483
-                        'filename' => 'events_edit_category',
484
-                    ],
485
-                ],
486
-                'metaboxes'     => ['_publish_post_box'],
487
-                'require_nonce' => false,
488
-            ],
489
-            'category_list'          => [
490
-                'nav'           => [
491
-                    'label' => esc_html__('Categories', 'event_espresso'),
492
-                    'icon' => 'dashicons-networking',
493
-                    'order' => 20,
494
-                ],
495
-                'list_table'    => 'Event_Categories_Admin_List_Table',
496
-                'help_tabs'     => [
497
-                    'events_categories_help_tab'                       => [
498
-                        'title'    => esc_html__('Event Categories', 'event_espresso'),
499
-                        'filename' => 'events_categories',
500
-                    ],
501
-                    'events_categories_table_column_headings_help_tab' => [
502
-                        'title'    => esc_html__('Event Categories Table Column Headings', 'event_espresso'),
503
-                        'filename' => 'events_categories_table_column_headings',
504
-                    ],
505
-                    'events_categories_view_help_tab'                  => [
506
-                        'title'    => esc_html__('Event Categories Views', 'event_espresso'),
507
-                        'filename' => 'events_categories_views',
508
-                    ],
509
-                    'events_categories_other_help_tab'                 => [
510
-                        'title'    => esc_html__('Event Categories Other', 'event_espresso'),
511
-                        'filename' => 'events_categories_other',
512
-                    ],
513
-                ],
514
-                'metaboxes'     => $this->_default_espresso_metaboxes,
515
-                'require_nonce' => false,
516
-            ],
517
-            'preview_deletion'       => [
518
-                'nav'           => [
519
-                    'label'      => esc_html__('Preview Deletion', 'event_espresso'),
520
-                    'icon' => 'dashicons-remove',
521
-                    'order'      => 15,
522
-                    'persistent' => false,
523
-                    'url'        => '',
524
-                ],
525
-                'require_nonce' => false,
526
-            ],
527
-        ];
528
-    }
529
-
530
-
531
-    /**
532
-     * Used to register any global screen options if necessary for every route in this admin page group.
533
-     */
534
-    protected function _add_screen_options()
535
-    {
536
-    }
537
-
538
-
539
-    /**
540
-     * Implementing the screen options for the 'default' route.
541
-     *
542
-     * @throws InvalidArgumentException
543
-     * @throws InvalidDataTypeException
544
-     * @throws InvalidInterfaceException
545
-     */
546
-    protected function _add_screen_options_default()
547
-    {
548
-        $this->_per_page_screen_option();
549
-    }
550
-
551
-
552
-    /**
553
-     * Implementing screen options for the category list route.
554
-     *
555
-     * @throws InvalidArgumentException
556
-     * @throws InvalidDataTypeException
557
-     * @throws InvalidInterfaceException
558
-     */
559
-    protected function _add_screen_options_category_list()
560
-    {
561
-        $page_title              = $this->_admin_page_title;
562
-        $this->_admin_page_title = esc_html__('Categories', 'event_espresso');
563
-        $this->_per_page_screen_option();
564
-        $this->_admin_page_title = $page_title;
565
-    }
566
-
567
-
568
-    /**
569
-     * Used to register any global feature pointers for the admin page group.
570
-     */
571
-    protected function _add_feature_pointers()
572
-    {
573
-    }
574
-
575
-
576
-    /**
577
-     * Registers and enqueues any global scripts and styles for the entire admin page group.
578
-     */
579
-    public function load_scripts_styles()
580
-    {
581
-        wp_register_style(
582
-            'events-admin-css',
583
-            EVENTS_ASSETS_URL . 'events-admin-page.css',
584
-            [],
585
-            EVENT_ESPRESSO_VERSION
586
-        );
587
-        wp_register_style(
588
-            'ee-cat-admin',
589
-            EVENTS_ASSETS_URL . 'ee-cat-admin.css',
590
-            [],
591
-            EVENT_ESPRESSO_VERSION
592
-        );
593
-        wp_enqueue_style('events-admin-css');
594
-        wp_enqueue_style('ee-cat-admin');
595
-        // scripts
596
-        wp_register_script(
597
-            'event_editor_js',
598
-            EVENTS_ASSETS_URL . 'event_editor.js',
599
-            ['ee_admin_js', 'jquery-ui-slider', 'jquery-ui-timepicker-addon'],
600
-            EVENT_ESPRESSO_VERSION,
601
-            true
602
-        );
603
-    }
604
-
605
-
606
-    /**
607
-     * Enqueuing scripts and styles specific to this view
608
-     */
609
-    public function load_scripts_styles_create_new()
610
-    {
611
-        $this->load_scripts_styles_edit();
612
-    }
613
-
614
-
615
-    /**
616
-     * Enqueuing scripts and styles specific to this view
617
-     */
618
-    public function load_scripts_styles_edit()
619
-    {
620
-        // styles
621
-        wp_enqueue_style('espresso-ui-theme');
622
-        wp_register_style(
623
-            'event-editor-css',
624
-            EVENTS_ASSETS_URL . 'event-editor.css',
625
-            ['ee-admin-css'],
626
-            EVENT_ESPRESSO_VERSION
627
-        );
628
-        wp_enqueue_style('event-editor-css');
629
-        // scripts
630
-        if (! $this->admin_config->useAdvancedEditor()) {
631
-            wp_register_script(
632
-                'event-datetime-metabox',
633
-                EVENTS_ASSETS_URL . 'event-datetime-metabox.js',
634
-                ['event_editor_js', 'ee-datepicker'],
635
-                EVENT_ESPRESSO_VERSION
636
-            );
637
-            wp_enqueue_script('event-datetime-metabox');
638
-        }
639
-    }
640
-
641
-
642
-    /**
643
-     * Populating the _views property for the category list table view.
644
-     */
645
-    protected function _set_list_table_views_category_list()
646
-    {
647
-        $this->_views = [
648
-            'all' => [
649
-                'slug'        => 'all',
650
-                'label'       => esc_html__('All', 'event_espresso'),
651
-                'count'       => 0,
652
-                'bulk_action' => [
653
-                    'delete_categories' => esc_html__('Delete Permanently', 'event_espresso'),
654
-                ],
655
-            ],
656
-        ];
657
-    }
658
-
659
-
660
-    /**
661
-     * For adding anything that fires on the admin_init hook for any route within this admin page group.
662
-     */
663
-    public function admin_init()
664
-    {
665
-        EE_Registry::$i18n_js_strings['image_confirm'] = esc_html__(
666
-            'Do you really want to delete this image? Please remember to update your event to complete the removal.',
667
-            'event_espresso'
668
-        );
669
-    }
670
-
671
-
672
-    /**
673
-     * For adding anything that should be triggered on the admin_notices hook for any route within this admin page
674
-     * group.
675
-     */
676
-    public function admin_notices()
677
-    {
678
-    }
679
-
680
-
681
-    /**
682
-     * For adding anything that should be triggered on the `admin_print_footer_scripts` hook for any route within
683
-     * this admin page group.
684
-     */
685
-    public function admin_footer_scripts()
686
-    {
687
-    }
688
-
689
-
690
-    /**
691
-     * Call this function to verify if an event is public and has tickets for sale.  If it does, then we need to show a
692
-     * warning (via EE_Error::add_error());
693
-     *
694
-     * @param EE_Event $event Event object
695
-     * @param string   $req_type
696
-     * @return void
697
-     * @throws EE_Error
698
-     * @throws ReflectionException
699
-     */
700
-    public function verify_event_edit($event = null, $req_type = '')
701
-    {
702
-        // don't need to do this when processing
703
-        if (! empty($req_type)) {
704
-            return;
705
-        }
706
-        // no event?
707
-        if (! $event instanceof EE_Event) {
708
-            $event = $this->_cpt_model_obj;
709
-        }
710
-        // STILL no event?
711
-        if (! $event instanceof EE_Event) {
712
-            return;
713
-        }
714
-        $orig_status = $event->status();
715
-        // first check if event is active.
716
-        if (
717
-            $orig_status === EEM_Event::cancelled
718
-            || $orig_status === EEM_Event::postponed
719
-            || $event->is_expired()
720
-            || $event->is_inactive()
721
-        ) {
722
-            return;
723
-        }
724
-        // made it here so it IS active... next check that any of the tickets are sold.
725
-        if ($event->is_sold_out(true)) {
726
-            if ($orig_status !== EEM_Event::sold_out && $event->status() !== $orig_status) {
727
-                EE_Error::add_attention(
728
-                    sprintf(
729
-                        esc_html__(
730
-                            'Please note that the Event Status has automatically been changed to %s because there are no more spaces available for this event.  However, this change is not permanent until you update the event.  You can change the status back to something else before updating if you wish.',
731
-                            'event_espresso'
732
-                        ),
733
-                        EEH_Template::pretty_status(EEM_Event::sold_out, false, 'sentence')
734
-                    )
735
-                );
736
-            }
737
-            return;
738
-        }
739
-        if ($orig_status === EEM_Event::sold_out) {
740
-            EE_Error::add_attention(
741
-                sprintf(
742
-                    esc_html__(
743
-                        'Please note that the Event Status has automatically been changed to %s because more spaces have become available for this event, most likely due to abandoned transactions freeing up reserved tickets.  However, this change is not permanent until you update the event. If you wish, you can change the status back to something else before updating.',
744
-                        'event_espresso'
745
-                    ),
746
-                    EEH_Template::pretty_status($event->status(), false, 'sentence')
747
-                )
748
-            );
749
-        }
750
-        // now we need to determine if the event has any tickets on sale.  If not then we dont' show the error
751
-        if (! $event->tickets_on_sale()) {
752
-            return;
753
-        }
754
-        // made it here so show warning
755
-        $this->_edit_event_warning();
756
-    }
757
-
758
-
759
-    /**
760
-     * This is the text used for when an event is being edited that is public and has tickets for sale.
761
-     * When needed, hook this into a EE_Error::add_error() notice.
762
-     *
763
-     * @access protected
764
-     * @return void
765
-     */
766
-    protected function _edit_event_warning()
767
-    {
768
-        // we don't want to add warnings during these requests
769
-        if ($this->request->getRequestParam('action') === 'editpost') {
770
-            return;
771
-        }
772
-        EE_Error::add_attention(
773
-            sprintf(
774
-                esc_html__(
775
-                    'Your event is open for registration. Making changes may disrupt any transactions in progress. %sLearn more%s',
776
-                    'event_espresso'
777
-                ),
778
-                '<a class="espresso-help-tab-lnk ee-help-tab-link">',
779
-                '</a>'
780
-            )
781
-        );
782
-    }
783
-
784
-
785
-    /**
786
-     * When a user is creating a new event, notify them if they haven't set their timezone.
787
-     * Otherwise, do the normal logic
788
-     *
789
-     * @return void
790
-     * @throws EE_Error
791
-     * @throws InvalidArgumentException
792
-     * @throws InvalidDataTypeException
793
-     * @throws InvalidInterfaceException
794
-     */
795
-    protected function _create_new_cpt_item()
796
-    {
797
-        $has_timezone_string = get_option('timezone_string');
798
-        // only nag them about setting their timezone if it's their first event, and they haven't already done it
799
-        if (! $has_timezone_string && ! EEM_Event::instance()->exists([])) {
800
-            EE_Error::add_attention(
801
-                sprintf(
802
-                    esc_html__(
803
-                        'Your website\'s timezone is currently set to a UTC offset. We recommend updating your timezone to a city or region near you before you create an event. Change your timezone now:%1$s%2$s%3$sChange Timezone%4$s',
804
-                        'event_espresso'
805
-                    ),
806
-                    '<br>',
807
-                    '<select id="timezone_string" name="timezone_string" aria-describedby="timezone-description">'
808
-                    . EEH_DTT_Helper::wp_timezone_choice('', EEH_DTT_Helper::get_user_locale())
809
-                    . '</select>',
810
-                    '<button class="button button--secondary timezone-submit">',
811
-                    '</button><span class="spinner"></span>'
812
-                ),
813
-                __FILE__,
814
-                __FUNCTION__,
815
-                __LINE__
816
-            );
817
-        }
818
-        parent::_create_new_cpt_item();
819
-    }
820
-
821
-
822
-    /**
823
-     * Sets the _views property for the default route in this admin page group.
824
-     */
825
-    protected function _set_list_table_views_default()
826
-    {
827
-        $this->_views = [
828
-            'all'   => [
829
-                'slug'        => 'all',
830
-                'label'       => esc_html__('View All Events', 'event_espresso'),
831
-                'count'       => 0,
832
-                'bulk_action' => [
833
-                    'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
834
-                ],
835
-            ],
836
-            'draft' => [
837
-                'slug'        => 'draft',
838
-                'label'       => esc_html__('Draft', 'event_espresso'),
839
-                'count'       => 0,
840
-                'bulk_action' => [
841
-                    'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
842
-                ],
843
-            ],
844
-        ];
845
-        if (EE_Registry::instance()->CAP->current_user_can('ee_delete_events', 'espresso_events_trash_events')) {
846
-            $this->_views['trash'] = [
847
-                'slug'        => 'trash',
848
-                'label'       => esc_html__('Trash', 'event_espresso'),
849
-                'count'       => 0,
850
-                'bulk_action' => [
851
-                    'restore_events' => esc_html__('Restore From Trash', 'event_espresso'),
852
-                    'delete_events'  => esc_html__('Delete Permanently', 'event_espresso'),
853
-                ],
854
-            ];
855
-        }
856
-    }
857
-
858
-
859
-    /**
860
-     * Provides the legend item array for the default list table view.
861
-     *
862
-     * @return array
863
-     * @throws EE_Error
864
-     * @throws EE_Error
865
-     */
866
-    protected function _event_legend_items()
867
-    {
868
-        $items    = [
869
-            'view_details'   => [
870
-                'class' => 'dashicons dashicons-visibility',
871
-                'desc'  => esc_html__('View Event', 'event_espresso'),
872
-            ],
873
-            'edit_event'     => [
874
-                'class' => 'dashicons dashicons-calendar-alt',
875
-                'desc'  => esc_html__('Edit Event Details', 'event_espresso'),
876
-            ],
877
-            'view_attendees' => [
878
-                'class' => 'dashicons dashicons-groups',
879
-                'desc'  => esc_html__('View Registrations for Event', 'event_espresso'),
880
-            ],
881
-        ];
882
-        $items    = apply_filters('FHEE__Events_Admin_Page___event_legend_items__items', $items);
883
-        $statuses = [
884
-            'sold_out_status'  => [
885
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::sold_out,
886
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::sold_out, false, 'sentence'),
887
-            ],
888
-            'active_status'    => [
889
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::active,
890
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::active, false, 'sentence'),
891
-            ],
892
-            'upcoming_status'  => [
893
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::upcoming,
894
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::upcoming, false, 'sentence'),
895
-            ],
896
-            'postponed_status' => [
897
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::postponed,
898
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::postponed, false, 'sentence'),
899
-            ],
900
-            'cancelled_status' => [
901
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::cancelled,
902
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::cancelled, false, 'sentence'),
903
-            ],
904
-            'expired_status'   => [
905
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::expired,
906
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::expired, false, 'sentence'),
907
-            ],
908
-            'inactive_status'  => [
909
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::inactive,
910
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::inactive, false, 'sentence'),
911
-            ],
912
-        ];
913
-        $statuses = apply_filters('FHEE__Events_Admin_Page__event_legend_items__statuses', $statuses);
914
-        return array_merge($items, $statuses);
915
-    }
916
-
917
-
918
-    /**
919
-     * @return EEM_Event
920
-     * @throws EE_Error
921
-     * @throws InvalidArgumentException
922
-     * @throws InvalidDataTypeException
923
-     * @throws InvalidInterfaceException
924
-     * @throws ReflectionException
925
-     */
926
-    private function _event_model()
927
-    {
928
-        if (! $this->_event_model instanceof EEM_Event) {
929
-            $this->_event_model = EE_Registry::instance()->load_model('Event');
930
-        }
931
-        return $this->_event_model;
932
-    }
933
-
934
-
935
-    /**
936
-     * Adds extra buttons to the WP CPT permalink field row.
937
-     * Method is called from parent and is hooked into the wp 'get_sample_permalink_html' filter.
938
-     *
939
-     * @param string $return    the current html
940
-     * @param int    $id        the post id for the page
941
-     * @param string $new_title What the title is
942
-     * @param string $new_slug  what the slug is
943
-     * @return string            The new html string for the permalink area
944
-     */
945
-    public function extra_permalink_field_buttons($return, $id, $new_title, $new_slug)
946
-    {
947
-        // make sure this is only when editing
948
-        if (! empty($id)) {
949
-            $post = get_post($id);
950
-            $return .= '<a class="button button--small button--secondary" onclick="prompt(\'Shortcode:\', jQuery(\'#shortcode\').val()); return false;" href="#"  tabindex="-1">'
951
-                       . esc_html__('Shortcode', 'event_espresso')
952
-                       . '</a> ';
953
-            $return .= '<input id="shortcode" type="hidden" value="[ESPRESSO_TICKET_SELECTOR event_id='
954
-                       . $post->ID
955
-                       . ']">';
956
-        }
957
-        return $return;
958
-    }
959
-
960
-
961
-    /**
962
-     * _events_overview_list_table
963
-     * This contains the logic for showing the events_overview list
964
-     *
965
-     * @access protected
966
-     * @return void
967
-     * @throws DomainException
968
-     * @throws EE_Error
969
-     * @throws InvalidArgumentException
970
-     * @throws InvalidDataTypeException
971
-     * @throws InvalidInterfaceException
972
-     */
973
-    protected function _events_overview_list_table()
974
-    {
975
-        $after_list_table                           = [];
976
-        $links_html = EEH_HTML::div('', '', 'ee-admin-section ee-layout-stack');
977
-        $links_html .= EEH_HTML::h3(esc_html__('Links', 'event_espresso'));
978
-        $links_html .= EEH_HTML::div(
979
-            EEH_Template::get_button_or_link(
980
-                get_post_type_archive_link('espresso_events'),
981
-                esc_html__('View Event Archive Page', 'event_espresso'),
982
-                'button button--small button--secondary'
983
-            ),
984
-            '',
985
-            'ee-admin-button-row ee-admin-button-row--align-start'
986
-        );
987
-        $links_html .= EEH_HTML::divx();
988
-
989
-        $after_list_table['view_event_list_button'] = $links_html;
990
-
991
-        $after_list_table['legend'] = $this->_display_legend($this->_event_legend_items());
992
-        $this->_admin_page_title                    .= ' ' . $this->get_action_link_or_button(
993
-            'create_new',
994
-            'add',
995
-            [],
996
-            'add-new-h2'
997
-        );
998
-
999
-        $this->_template_args['after_list_table']   = array_merge(
1000
-            (array) $this->_template_args['after_list_table'],
1001
-            $after_list_table
1002
-        );
1003
-        $this->display_admin_list_table_page_with_no_sidebar();
1004
-    }
1005
-
1006
-
1007
-    /**
1008
-     * this allows for extra misc actions in the default WP publish box
1009
-     *
1010
-     * @return void
1011
-     * @throws DomainException
1012
-     * @throws EE_Error
1013
-     * @throws InvalidArgumentException
1014
-     * @throws InvalidDataTypeException
1015
-     * @throws InvalidInterfaceException
1016
-     * @throws ReflectionException
1017
-     */
1018
-    public function extra_misc_actions_publish_box()
1019
-    {
1020
-        $this->_generate_publish_box_extra_content();
1021
-    }
1022
-
1023
-
1024
-    /**
1025
-     * This is hooked into the WordPress do_action('save_post') hook and runs after the custom post type has been
1026
-     * saved.
1027
-     * Typically you would use this to save any additional data.
1028
-     * Keep in mind also that "save_post" runs on EVERY post update to the database.
1029
-     * ALSO very important.  When a post transitions from scheduled to published,
1030
-     * the save_post action is fired but you will NOT have any _POST data containing any extra info you may have from
1031
-     * other meta saves. So MAKE sure that you handle this accordingly.
1032
-     *
1033
-     * @access protected
1034
-     * @abstract
1035
-     * @param string $post_id The ID of the cpt that was saved (so you can link relationally)
1036
-     * @param WP_Post $post    The post object of the cpt that was saved.
1037
-     * @return void
1038
-     * @throws EE_Error
1039
-     * @throws InvalidArgumentException
1040
-     * @throws InvalidDataTypeException
1041
-     * @throws InvalidInterfaceException
1042
-     * @throws ReflectionException
1043
-     */
1044
-    protected function _insert_update_cpt_item($post_id, $post)
1045
-    {
1046
-        if ($post instanceof WP_Post && $post->post_type !== 'espresso_events') {
1047
-            // get out we're not processing an event save.
1048
-            return;
1049
-        }
1050
-        $event_values = [
1051
-            'EVT_member_only'     => $this->request->getRequestParam('member_only', false, 'bool'),
1052
-            'EVT_allow_overflow'  => $this->request->getRequestParam('EVT_allow_overflow', false, 'bool'),
1053
-            'EVT_timezone_string' => $this->request->getRequestParam('timezone_string'),
1054
-        ];
1055
-        // check if the new EDTR reg options meta box is being used, and if so, don't run updates for legacy version
1056
-        if (! $this->admin_config->useAdvancedEditor() || ! $this->feature->allowed('use_reg_options_meta_box')) {
1057
-            $event_values['EVT_display_ticket_selector']     = $this->request->getRequestParam(
1058
-                'display_ticket_selector',
1059
-                false,
1060
-                'bool'
1061
-            );
1062
-            $event_values['EVT_additional_limit']            = min(
1063
-                apply_filters('FHEE__EE_Events_Admin__insert_update_cpt_item__EVT_additional_limit_max', 255),
1064
-                $this->request->getRequestParam('additional_limit', null, 'int')
1065
-            );
1066
-            $event_values['EVT_default_registration_status'] = $this->request->getRequestParam(
1067
-                'EVT_default_registration_status',
1068
-                EE_Registry::instance()->CFG->registration->default_STS_ID
1069
-            );
1070
-
1071
-            $event_values['EVT_external_URL'] = $this->request->getRequestParam('externalURL');
1072
-            $event_values['EVT_phone']        = $this->request->getRequestParam('event_phone');
1073
-            $event_values['EVT_display_desc'] = $this->request->getRequestParam('display_desc', false, 'bool');
1074
-        }
1075
-        // update event
1076
-        $success = $this->_event_model()->update_by_ID($event_values, $post_id);
1077
-        // get event_object for other metaboxes...
1078
-        // though it would seem to make sense to just use $this->_event_model()->get_one_by_ID( $post_id )..
1079
-        // i have to setup where conditions to override the filters in the model
1080
-        // that filter out autodraft and inherit statuses so we GET the inherit id!
1081
-        $event = $this->_event_model()->get_one(
1082
-            [
1083
-                [
1084
-                    $this->_event_model()->primary_key_name() => $post_id,
1085
-                    'OR'                                      => [
1086
-                        'status'   => $post->post_status,
1087
-                        // if trying to "Publish" a sold out event, it's status will get switched back to "sold_out" in the db,
1088
-                        // but the returned object here has a status of "publish", so use the original post status as well
1089
-                        'status*1' => $this->request->getRequestParam('original_post_status'),
1090
-                    ],
1091
-                ],
1092
-            ]
1093
-        );
1094
-
1095
-        // the following are default callbacks for event attachment updates
1096
-        // that can be overridden by caffeinated functionality and/or addons.
1097
-        $event_update_callbacks = [];
1098
-        if (! $this->admin_config->useAdvancedEditor()) {
1099
-            $event_update_callbacks['_default_venue_update']   = [$this, '_default_venue_update'];
1100
-            $event_update_callbacks['_default_tickets_update'] = [$this, '_default_tickets_update'];
1101
-        }
1102
-        $event_update_callbacks = apply_filters(
1103
-            'FHEE__Events_Admin_Page___insert_update_cpt_item__event_update_callbacks',
1104
-            $event_update_callbacks
1105
-        );
1106
-
1107
-        $att_success = true;
1108
-        foreach ($event_update_callbacks as $e_callback) {
1109
-            $_success = is_callable($e_callback)
1110
-                ? $e_callback($event, $this->request->requestParams())
1111
-                : false;
1112
-            // if ANY of these updates fail then we want the appropriate global error message
1113
-            $att_success = $_success !== false ? $att_success : false;
1114
-        }
1115
-        // any errors?
1116
-        if ($success && $att_success === false) {
1117
-            EE_Error::add_error(
1118
-                esc_html__(
1119
-                    'Event Details saved successfully but something went wrong with saving attachments.',
1120
-                    'event_espresso'
1121
-                ),
1122
-                __FILE__,
1123
-                __FUNCTION__,
1124
-                __LINE__
1125
-            );
1126
-        } elseif ($success === false) {
1127
-            EE_Error::add_error(
1128
-                esc_html__('Event Details did not save successfully.', 'event_espresso'),
1129
-                __FILE__,
1130
-                __FUNCTION__,
1131
-                __LINE__
1132
-            );
1133
-        }
1134
-    }
1135
-
1136
-
1137
-    /**
1138
-     * @param int $post_id
1139
-     * @param int $revision_id
1140
-     * @throws EE_Error
1141
-     * @throws EE_Error
1142
-     * @throws ReflectionException
1143
-     * @see parent::restore_item()
1144
-     */
1145
-    protected function _restore_cpt_item($post_id, $revision_id)
1146
-    {
1147
-        // copy existing event meta to new post
1148
-        $post_evt = $this->_event_model()->get_one_by_ID($post_id);
1149
-        if ($post_evt instanceof EE_Event) {
1150
-            // meta revision restore
1151
-            $post_evt->restore_revision($revision_id);
1152
-            // related objs restore
1153
-            $post_evt->restore_revision($revision_id, ['Venue', 'Datetime', 'Price']);
1154
-        }
1155
-    }
1156
-
1157
-
1158
-    /**
1159
-     * Attach the venue to the Event
1160
-     *
1161
-     * @param EE_Event $event Event Object to add the venue to
1162
-     * @param array    $data  The request data from the form
1163
-     * @return bool           Success or fail.
1164
-     * @throws EE_Error
1165
-     * @throws ReflectionException
1166
-     */
1167
-    protected function _default_venue_update(EE_Event $event, $data)
1168
-    {
1169
-        require_once(EE_MODELS . 'EEM_Venue.model.php');
1170
-        $venue_model = EE_Registry::instance()->load_model('Venue');
1171
-        $venue_id    = ! empty($data['venue_id']) ? $data['venue_id'] : null;
1172
-        // very important.  If we don't have a venue name...
1173
-        // then we'll get out because not necessary to create empty venue
1174
-        if (empty($data['venue_title'])) {
1175
-            return false;
1176
-        }
1177
-        $venue_array = [
1178
-            'VNU_wp_user'         => $event->get('EVT_wp_user'),
1179
-            'VNU_name'            => ! empty($data['venue_title']) ? $data['venue_title'] : null,
1180
-            'VNU_desc'            => ! empty($data['venue_description']) ? $data['venue_description'] : null,
1181
-            'VNU_identifier'      => ! empty($data['venue_identifier']) ? $data['venue_identifier'] : null,
1182
-            'VNU_short_desc'      => ! empty($data['venue_short_description'])
1183
-                ? $data['venue_short_description']
1184
-                : null,
1185
-            'VNU_address'         => ! empty($data['address']) ? $data['address'] : null,
1186
-            'VNU_address2'        => ! empty($data['address2']) ? $data['address2'] : null,
1187
-            'VNU_city'            => ! empty($data['city']) ? $data['city'] : null,
1188
-            'STA_ID'              => ! empty($data['state']) ? $data['state'] : null,
1189
-            'CNT_ISO'             => ! empty($data['countries']) ? $data['countries'] : null,
1190
-            'VNU_zip'             => ! empty($data['zip']) ? $data['zip'] : null,
1191
-            'VNU_phone'           => ! empty($data['venue_phone']) ? $data['venue_phone'] : null,
1192
-            'VNU_capacity'        => ! empty($data['venue_capacity']) ? $data['venue_capacity'] : null,
1193
-            'VNU_url'             => ! empty($data['venue_url']) ? $data['venue_url'] : null,
1194
-            'VNU_virtual_phone'   => ! empty($data['virtual_phone']) ? $data['virtual_phone'] : null,
1195
-            'VNU_virtual_url'     => ! empty($data['virtual_url']) ? $data['virtual_url'] : null,
1196
-            'VNU_enable_for_gmap' => isset($data['enable_for_gmap']) ? 1 : 0,
1197
-            'status'              => 'publish',
1198
-        ];
1199
-        // if we've got the venue_id then we're just updating the existing venue so let's do that and then get out.
1200
-        if (! empty($venue_id)) {
1201
-            $update_where  = [$venue_model->primary_key_name() => $venue_id];
1202
-            $rows_affected = $venue_model->update($venue_array, [$update_where]);
1203
-            // we've gotta make sure that the venue is always attached to a revision..
1204
-            // add_relation_to should take care of making sure that the relation is already present.
1205
-            $event->_add_relation_to($venue_id, 'Venue');
1206
-            return $rows_affected > 0;
1207
-        }
1208
-        // we insert the venue
1209
-        $venue_id = $venue_model->insert($venue_array);
1210
-        $event->_add_relation_to($venue_id, 'Venue');
1211
-        return ! empty($venue_id);
1212
-        // when we have the ancestor come in it's already been handled by the revision save.
1213
-    }
1214
-
1215
-
1216
-    /**
1217
-     * Handles saving everything related to Tickets (datetimes, tickets, prices)
1218
-     *
1219
-     * @param EE_Event $event The Event object we're attaching data to
1220
-     * @param array    $data  The request data from the form
1221
-     * @return array
1222
-     * @throws EE_Error
1223
-     * @throws ReflectionException
1224
-     * @throws Exception
1225
-     */
1226
-    protected function _default_tickets_update(EE_Event $event, $data)
1227
-    {
1228
-        if ($this->admin_config->useAdvancedEditor()) {
1229
-            return [];
1230
-        }
1231
-        $datetime       = null;
1232
-        $saved_tickets  = [];
1233
-        $event_timezone = $event->get_timezone();
1234
-        $date_formats   = ['Y-m-d', 'h:i a'];
1235
-        foreach ($data['edit_event_datetimes'] as $row => $datetime_data) {
1236
-            // trim all values to ensure any excess whitespace is removed.
1237
-            $datetime_data                = array_map('trim', $datetime_data);
1238
-            $datetime_data['DTT_EVT_end'] =
1239
-                isset($datetime_data['DTT_EVT_end']) && ! empty($datetime_data['DTT_EVT_end'])
1240
-                    ? $datetime_data['DTT_EVT_end']
1241
-                    : $datetime_data['DTT_EVT_start'];
1242
-            $datetime_values              = [
1243
-                'DTT_ID'        => ! empty($datetime_data['DTT_ID']) ? $datetime_data['DTT_ID'] : null,
1244
-                'DTT_EVT_start' => $datetime_data['DTT_EVT_start'],
1245
-                'DTT_EVT_end'   => $datetime_data['DTT_EVT_end'],
1246
-                'DTT_reg_limit' => empty($datetime_data['DTT_reg_limit']) ? EE_INF : $datetime_data['DTT_reg_limit'],
1247
-                'DTT_order'     => $row,
1248
-            ];
1249
-            // if we have an id then let's get existing object first and then set the new values.
1250
-            //  Otherwise we instantiate a new object for save.
1251
-            if (! empty($datetime_data['DTT_ID'])) {
1252
-                $datetime = EEM_Datetime::instance($event_timezone)->get_one_by_ID($datetime_data['DTT_ID']);
1253
-                if (! $datetime instanceof EE_Datetime) {
1254
-                    throw new RuntimeException(
1255
-                        sprintf(
1256
-                            esc_html__(
1257
-                                'Something went wrong! A valid Datetime could not be retrieved from the database using the supplied ID: %1$d',
1258
-                                'event_espresso'
1259
-                            ),
1260
-                            $datetime_data['DTT_ID']
1261
-                        )
1262
-                    );
1263
-                }
1264
-                $datetime->set_date_format($date_formats[0]);
1265
-                $datetime->set_time_format($date_formats[1]);
1266
-                foreach ($datetime_values as $field => $value) {
1267
-                    $datetime->set($field, $value);
1268
-                }
1269
-            } else {
1270
-                $datetime = EE_Datetime::new_instance($datetime_values, $event_timezone, $date_formats);
1271
-            }
1272
-            if (! $datetime instanceof EE_Datetime) {
1273
-                throw new RuntimeException(
1274
-                    sprintf(
1275
-                        esc_html__(
1276
-                            'Something went wrong! A valid Datetime could not be generated or retrieved using the supplied data: %1$s',
1277
-                            'event_espresso'
1278
-                        ),
1279
-                        print_r($datetime_values, true)
1280
-                    )
1281
-                );
1282
-            }
1283
-            // before going any further make sure our dates are setup correctly
1284
-            // so that the end date is always equal or greater than the start date.
1285
-            if ($datetime->get_raw('DTT_EVT_start') > $datetime->get_raw('DTT_EVT_end')) {
1286
-                $datetime->set('DTT_EVT_end', $datetime->get('DTT_EVT_start'));
1287
-                $datetime = EEH_DTT_Helper::date_time_add($datetime, 'DTT_EVT_end', 'days');
1288
-            }
1289
-            $datetime->save();
1290
-            $event->_add_relation_to($datetime, 'Datetime');
1291
-        }
1292
-        // no datetimes get deleted so we don't do any of that logic here.
1293
-        // update tickets next
1294
-        $old_tickets = isset($data['ticket_IDs']) ? explode(',', $data['ticket_IDs']) : [];
1295
-
1296
-        // set up some default start and end dates in case those are not present in the incoming data
1297
-        $default_start_date = new DateTime('now', new DateTimeZone($event->get_timezone()));
1298
-        $default_start_date = $default_start_date->format($date_formats[0] . ' ' . $date_formats[1]);
1299
-        // use the start date of the first datetime for the end date
1300
-        $first_datetime   = $event->first_datetime();
1301
-        $default_end_date = $first_datetime->start_date_and_time($date_formats[0], $date_formats[1]);
1302
-
1303
-        // now process the incoming data
1304
-        foreach ($data['edit_tickets'] as $row => $ticket_data) {
1305
-            $update_prices = false;
1306
-            $ticket_price  = isset($data['edit_prices'][ $row ][1]['PRC_amount'])
1307
-                ? $data['edit_prices'][ $row ][1]['PRC_amount']
1308
-                : 0;
1309
-            // trim inputs to ensure any excess whitespace is removed.
1310
-            $ticket_data   = array_map('trim', $ticket_data);
1311
-            $ticket_values = [
1312
-                'TKT_ID'          => ! empty($ticket_data['TKT_ID']) ? $ticket_data['TKT_ID'] : null,
1313
-                'TTM_ID'          => ! empty($ticket_data['TTM_ID']) ? $ticket_data['TTM_ID'] : 0,
1314
-                'TKT_name'        => ! empty($ticket_data['TKT_name']) ? $ticket_data['TKT_name'] : '',
1315
-                'TKT_description' => ! empty($ticket_data['TKT_description']) ? $ticket_data['TKT_description'] : '',
1316
-                'TKT_start_date'  => ! empty($ticket_data['TKT_start_date'])
1317
-                    ? $ticket_data['TKT_start_date']
1318
-                    : $default_start_date,
1319
-                'TKT_end_date'    => ! empty($ticket_data['TKT_end_date'])
1320
-                    ? $ticket_data['TKT_end_date']
1321
-                    : $default_end_date,
1322
-                'TKT_qty'         => ! empty($ticket_data['TKT_qty'])
1323
-                                     || (isset($ticket_data['TKT_qty']) && (int) $ticket_data['TKT_qty'] === 0)
1324
-                    ? $ticket_data['TKT_qty']
1325
-                    : EE_INF,
1326
-                'TKT_uses'        => ! empty($ticket_data['TKT_uses'])
1327
-                                     || (isset($ticket_data['TKT_uses']) && (int) $ticket_data['TKT_uses'] === 0)
1328
-                    ? $ticket_data['TKT_uses']
1329
-                    : EE_INF,
1330
-                'TKT_min'         => ! empty($ticket_data['TKT_min']) ? $ticket_data['TKT_min'] : 0,
1331
-                'TKT_max'         => ! empty($ticket_data['TKT_max']) ? $ticket_data['TKT_max'] : EE_INF,
1332
-                'TKT_order'       => isset($ticket_data['TKT_order']) ? $ticket_data['TKT_order'] : $row,
1333
-                'TKT_price'       => $ticket_price,
1334
-                'TKT_row'         => $row,
1335
-            ];
1336
-            // if this is a default ticket, then we need to set the TKT_ID to 0 and update accordingly,
1337
-            // which means in turn that the prices will become new prices as well.
1338
-            if (isset($ticket_data['TKT_is_default']) && $ticket_data['TKT_is_default']) {
1339
-                $ticket_values['TKT_ID']         = 0;
1340
-                $ticket_values['TKT_is_default'] = 0;
1341
-                $update_prices                   = true;
1342
-            }
1343
-            // if we have a TKT_ID then we need to get that existing TKT_obj and update it
1344
-            // we actually do our saves ahead of adding any relations because its entirely possible that this
1345
-            // ticket didn't get removed or added to any datetime in the session but DID have it's items modified.
1346
-            // keep in mind that if the ticket has been sold (and we have changed pricing information),
1347
-            // then we won't be updating the tkt but instead a new tkt will be created and the old one archived.
1348
-            if (! empty($ticket_data['TKT_ID'])) {
1349
-                $existing_ticket = EEM_Ticket::instance($event_timezone)->get_one_by_ID($ticket_data['TKT_ID']);
1350
-                if (! $existing_ticket instanceof EE_Ticket) {
1351
-                    throw new RuntimeException(
1352
-                        sprintf(
1353
-                            esc_html__(
1354
-                                'Something went wrong! A valid Ticket could not be retrieved from the database using the supplied ID: %1$d',
1355
-                                'event_espresso'
1356
-                            ),
1357
-                            $ticket_data['TKT_ID']
1358
-                        )
1359
-                    );
1360
-                }
1361
-                $ticket_sold = $existing_ticket->count_related(
1362
-                    'Registration',
1363
-                    [
1364
-                            [
1365
-                                'STS_ID' => [
1366
-                                    'NOT IN',
1367
-                                    [EEM_Registration::status_id_incomplete],
1368
-                                ],
1369
-                            ],
1370
-                        ]
1371
-                ) > 0;
1372
-                // let's just check the total price for the existing ticket and determine if it matches the new total price.
1373
-                // if they are different then we create a new ticket (if $ticket_sold)
1374
-                // if they aren't different then we go ahead and modify existing ticket.
1375
-                $create_new_ticket = $ticket_sold
1376
-                                     && $ticket_price !== $existing_ticket->price()
1377
-                                     && ! $existing_ticket->deleted();
1378
-                $existing_ticket->set_date_format($date_formats[0]);
1379
-                $existing_ticket->set_time_format($date_formats[1]);
1380
-                // set new values
1381
-                foreach ($ticket_values as $field => $value) {
1382
-                    if ($field == 'TKT_qty') {
1383
-                        $existing_ticket->set_qty($value);
1384
-                    } elseif ($field == 'TKT_price') {
1385
-                        $existing_ticket->set('TKT_price', $ticket_price);
1386
-                    } else {
1387
-                        $existing_ticket->set($field, $value);
1388
-                    }
1389
-                }
1390
-                $ticket = $existing_ticket;
1391
-                // if $create_new_ticket is false then we can safely update the existing ticket.
1392
-                //  Otherwise we have to create a new ticket.
1393
-                if ($create_new_ticket) {
1394
-                    // archive the old ticket first
1395
-                    $existing_ticket->set('TKT_deleted', 1);
1396
-                    $existing_ticket->save();
1397
-                    // make sure this ticket is still recorded in our $saved_tickets
1398
-                    // so we don't run it through the regular trash routine.
1399
-                    $saved_tickets[ $existing_ticket->ID() ] = $existing_ticket;
1400
-                    // create new ticket that's a copy of the existing except,
1401
-                    // (a new id of course and not archived) AND has the new TKT_price associated with it.
1402
-                    $new_ticket = clone $existing_ticket;
1403
-                    $new_ticket->set('TKT_ID', 0);
1404
-                    $new_ticket->set('TKT_deleted', 0);
1405
-                    $new_ticket->set('TKT_sold', 0);
1406
-                    // now we need to make sure that $new prices are created as well and attached to new ticket.
1407
-                    $update_prices = true;
1408
-                    $ticket        = $new_ticket;
1409
-                }
1410
-            } else {
1411
-                // no TKT_id so a new ticket
1412
-                $ticket_values['TKT_price'] = $ticket_price;
1413
-                $ticket                     = EE_Ticket::new_instance($ticket_values, $event_timezone, $date_formats);
1414
-                $update_prices              = true;
1415
-            }
1416
-            if (! $ticket instanceof EE_Ticket) {
1417
-                throw new RuntimeException(
1418
-                    sprintf(
1419
-                        esc_html__(
1420
-                            'Something went wrong! A valid Ticket could not be generated or retrieved using the supplied data: %1$s',
1421
-                            'event_espresso'
1422
-                        ),
1423
-                        print_r($ticket_values, true)
1424
-                    )
1425
-                );
1426
-            }
1427
-            // cap ticket qty by datetime reg limits
1428
-            $ticket->set_qty(min($ticket->qty(), $ticket->qty('reg_limit')));
1429
-            // update ticket.
1430
-            $ticket->save();
1431
-            // before going any further make sure our dates are setup correctly
1432
-            // so that the end date is always equal or greater than the start date.
1433
-            if ($ticket->get_raw('TKT_start_date') > $ticket->get_raw('TKT_end_date')) {
1434
-                $ticket->set('TKT_end_date', $ticket->get('TKT_start_date'));
1435
-                $ticket = EEH_DTT_Helper::date_time_add($ticket, 'TKT_end_date', 'days');
1436
-                $ticket->save();
1437
-            }
1438
-            // initially let's add the ticket to the datetime
1439
-            $datetime->_add_relation_to($ticket, 'Ticket');
1440
-            $saved_tickets[ $ticket->ID() ] = $ticket;
1441
-            // add prices to ticket
1442
-            $prices_data = isset($data['edit_prices'][ $row ]) && is_array($data['edit_prices'][ $row ])
1443
-                ? $data['edit_prices'][ $row ]
1444
-                : [];
1445
-            $this->_add_prices_to_ticket($prices_data, $ticket, $update_prices);
1446
-        }
1447
-        // however now we need to handle permanently deleting tickets via the ui.
1448
-        // Keep in mind that the ui does not allow deleting/archiving tickets that have ticket sold.
1449
-        // However, it does allow for deleting tickets that have no tickets sold,
1450
-        // in which case we want to get rid of permanently because there is no need to save in db.
1451
-        $old_tickets     = isset($old_tickets[0]) && $old_tickets[0] === '' ? [] : $old_tickets;
1452
-        $tickets_removed = array_diff($old_tickets, array_keys($saved_tickets));
1453
-        foreach ($tickets_removed as $id) {
1454
-            $id = absint($id);
1455
-            // get the ticket for this id
1456
-            $ticket_to_remove = EEM_Ticket::instance()->get_one_by_ID($id);
1457
-            if (! $ticket_to_remove instanceof EE_Ticket) {
1458
-                continue;
1459
-            }
1460
-            // need to get all the related datetimes on this ticket and remove from every single one of them
1461
-            // (remember this process can ONLY kick off if there are NO tickets sold)
1462
-            $related_datetimes = $ticket_to_remove->get_many_related('Datetime');
1463
-            foreach ($related_datetimes as $related_datetime) {
1464
-                $ticket_to_remove->_remove_relation_to($related_datetime, 'Datetime');
1465
-            }
1466
-            // need to do the same for prices (except these prices can also be deleted because again,
1467
-            // tickets can only be trashed if they don't have any TKTs sold (otherwise they are just archived))
1468
-            $ticket_to_remove->delete_related_permanently('Price');
1469
-            // finally let's delete this ticket
1470
-            // (which should not be blocked at this point b/c we've removed all our relationships)
1471
-            $ticket_to_remove->delete_permanently();
1472
-        }
1473
-        return [$datetime, $saved_tickets];
1474
-    }
1475
-
1476
-
1477
-    /**
1478
-     * This attaches a list of given prices to a ticket.
1479
-     * Note we dont' have to worry about ever removing relationships (or archiving prices)
1480
-     * because if there is a change in price information on a ticket, a new ticket is created anyways
1481
-     * so the archived ticket will retain the old price info and prices are automatically "archived" via the ticket.
1482
-     *
1483
-     * @access  private
1484
-     * @param array     $prices_data Array of prices from the form.
1485
-     * @param EE_Ticket $ticket      EE_Ticket object that prices are being attached to.
1486
-     * @param bool      $new_prices  Whether attach existing incoming prices or create new ones.
1487
-     * @return  void
1488
-     * @throws EE_Error
1489
-     * @throws ReflectionException
1490
-     */
1491
-    private function _add_prices_to_ticket($prices_data, EE_Ticket $ticket, $new_prices = false)
1492
-    {
1493
-        $timezone = $ticket->get_timezone();
1494
-        foreach ($prices_data as $row => $price_data) {
1495
-            $price_values = [
1496
-                'PRC_ID'         => ! empty($price_data['PRC_ID']) ? $price_data['PRC_ID'] : null,
1497
-                'PRT_ID'         => ! empty($price_data['PRT_ID']) ? $price_data['PRT_ID'] : null,
1498
-                'PRC_amount'     => ! empty($price_data['PRC_amount']) ? $price_data['PRC_amount'] : 0,
1499
-                'PRC_name'       => ! empty($price_data['PRC_name']) ? $price_data['PRC_name'] : '',
1500
-                'PRC_desc'       => ! empty($price_data['PRC_desc']) ? $price_data['PRC_desc'] : '',
1501
-                'PRC_is_default' => 0, // make sure prices are NOT set as default from this context
1502
-                'PRC_order'      => $row,
1503
-            ];
1504
-            if ($new_prices || empty($price_values['PRC_ID'])) {
1505
-                $price_values['PRC_ID'] = 0;
1506
-                $price                  = EE_Price::new_instance($price_values, $timezone);
1507
-            } else {
1508
-                $price = EEM_Price::instance($timezone)->get_one_by_ID($price_data['PRC_ID']);
1509
-                // update this price with new values
1510
-                foreach ($price_values as $field => $new_price) {
1511
-                    $price->set($field, $new_price);
1512
-                }
1513
-            }
1514
-            if (! $price instanceof EE_Price) {
1515
-                throw new RuntimeException(
1516
-                    sprintf(
1517
-                        esc_html__(
1518
-                            'Something went wrong! A valid Price could not be generated or retrieved using the supplied data: %1$s',
1519
-                            'event_espresso'
1520
-                        ),
1521
-                        print_r($price_values, true)
1522
-                    )
1523
-                );
1524
-            }
1525
-            $price->save();
1526
-            $ticket->_add_relation_to($price, 'Price');
1527
-        }
1528
-    }
1529
-
1530
-
1531
-    /**
1532
-     * Add in our autosave ajax handlers
1533
-     *
1534
-     */
1535
-    protected function _ee_autosave_create_new()
1536
-    {
1537
-    }
1538
-
1539
-
1540
-    /**
1541
-     * More autosave handlers.
1542
-     */
1543
-    protected function _ee_autosave_edit()
1544
-    {
1545
-    }
1546
-
1547
-
1548
-    /**
1549
-     * @throws EE_Error
1550
-     * @throws ReflectionException
1551
-     */
1552
-    private function _generate_publish_box_extra_content()
1553
-    {
1554
-        // load formatter helper
1555
-        // args for getting related registrations
1556
-        $approved_query_args        = [
1557
-            [
1558
-                'REG_deleted' => 0,
1559
-                'STS_ID'      => EEM_Registration::status_id_approved,
1560
-            ],
1561
-        ];
1562
-        $not_approved_query_args    = [
1563
-            [
1564
-                'REG_deleted' => 0,
1565
-                'STS_ID'      => EEM_Registration::status_id_not_approved,
1566
-            ],
1567
-        ];
1568
-        $pending_payment_query_args = [
1569
-            [
1570
-                'REG_deleted' => 0,
1571
-                'STS_ID'      => EEM_Registration::status_id_pending_payment,
1572
-            ],
1573
-        ];
1574
-        // publish box
1575
-        $publish_box_extra_args = [
1576
-            'view_approved_reg_url'        => add_query_arg(
1577
-                [
1578
-                    'action'      => 'default',
1579
-                    'event_id'    => $this->_cpt_model_obj->ID(),
1580
-                    '_reg_status' => EEM_Registration::status_id_approved,
1581
-                ],
1582
-                REG_ADMIN_URL
1583
-            ),
1584
-            'view_not_approved_reg_url'    => add_query_arg(
1585
-                [
1586
-                    'action'      => 'default',
1587
-                    'event_id'    => $this->_cpt_model_obj->ID(),
1588
-                    '_reg_status' => EEM_Registration::status_id_not_approved,
1589
-                ],
1590
-                REG_ADMIN_URL
1591
-            ),
1592
-            'view_pending_payment_reg_url' => add_query_arg(
1593
-                [
1594
-                    'action'      => 'default',
1595
-                    'event_id'    => $this->_cpt_model_obj->ID(),
1596
-                    '_reg_status' => EEM_Registration::status_id_pending_payment,
1597
-                ],
1598
-                REG_ADMIN_URL
1599
-            ),
1600
-            'approved_regs'                => $this->_cpt_model_obj->count_related(
1601
-                'Registration',
1602
-                $approved_query_args
1603
-            ),
1604
-            'not_approved_regs'            => $this->_cpt_model_obj->count_related(
1605
-                'Registration',
1606
-                $not_approved_query_args
1607
-            ),
1608
-            'pending_payment_regs'         => $this->_cpt_model_obj->count_related(
1609
-                'Registration',
1610
-                $pending_payment_query_args
1611
-            ),
1612
-            'misc_pub_section_class'       => apply_filters(
1613
-                'FHEE_Events_Admin_Page___generate_publish_box_extra_content__misc_pub_section_class',
1614
-                'misc-pub-section'
1615
-            ),
1616
-        ];
1617
-        ob_start();
1618
-        do_action(
1619
-            'AHEE__Events_Admin_Page___generate_publish_box_extra_content__event_editor_overview_add',
1620
-            $this->_cpt_model_obj
1621
-        );
1622
-        $publish_box_extra_args['event_editor_overview_add'] = ob_get_clean();
1623
-        // load template
1624
-        EEH_Template::display_template(
1625
-            EVENTS_TEMPLATE_PATH . 'event_publish_box_extras.template.php',
1626
-            $publish_box_extra_args
1627
-        );
1628
-    }
1629
-
1630
-
1631
-    /**
1632
-     * @return EE_Event
1633
-     */
1634
-    public function get_event_object()
1635
-    {
1636
-        return $this->_cpt_model_obj;
1637
-    }
1638
-
1639
-
1640
-
1641
-
1642
-    /** METABOXES * */
1643
-    /**
1644
-     * _register_event_editor_meta_boxes
1645
-     * add all metaboxes related to the event_editor
1646
-     *
1647
-     * @return void
1648
-     * @throws EE_Error
1649
-     * @throws ReflectionException
1650
-     */
1651
-    protected function _register_event_editor_meta_boxes()
1652
-    {
1653
-        $this->verify_cpt_object();
1654
-        $use_advanced_editor = $this->admin_config->useAdvancedEditor();
1655
-        // check if the new EDTR reg options meta box is being used, and if so, don't load the legacy version
1656
-        if (! $use_advanced_editor || ! $this->feature->allowed('use_reg_options_meta_box')) {
1657
-            $this->addMetaBox(
1658
-                'espresso_event_editor_event_options',
1659
-                esc_html__('Event Registration Options', 'event_espresso'),
1660
-                [$this, 'registration_options_meta_box'],
1661
-                $this->page_slug,
1662
-                'side'
1663
-            );
1664
-        }
1665
-        if (! $use_advanced_editor) {
1666
-            $this->addMetaBox(
1667
-                'espresso_event_editor_tickets',
1668
-                esc_html__('Event Datetime & Ticket', 'event_espresso'),
1669
-                [$this, 'ticket_metabox'],
1670
-                $this->page_slug,
1671
-                'normal',
1672
-                'high'
1673
-            );
1674
-        } elseif ($this->feature->allowed('use_reg_options_meta_box')) {
1675
-            add_action(
1676
-                'add_meta_boxes_espresso_events',
1677
-                function () {
1678
-                    global $current_screen;
1679
-                    remove_meta_box('authordiv', $current_screen, 'normal');
1680
-                },
1681
-                99
1682
-            );
1683
-        }
1684
-        // NOTE: if you're looking for other metaboxes in here,
1685
-        // where a metabox has a related management page in the admin
1686
-        // you will find it setup in the related management page's "_Hooks" file.
1687
-        // i.e. messages metabox is found in "espresso_events_Messages_Hooks.class.php".
1688
-    }
1689
-
1690
-
1691
-    /**
1692
-     * @throws DomainException
1693
-     * @throws EE_Error
1694
-     * @throws ReflectionException
1695
-     */
1696
-    public function ticket_metabox()
1697
-    {
1698
-        $existing_datetime_ids = $existing_ticket_ids = [];
1699
-        // defaults for template args
1700
-        $template_args = [
1701
-            'existing_datetime_ids'    => '',
1702
-            'event_datetime_help_link' => '',
1703
-            'ticket_options_help_link' => '',
1704
-            'time'                     => null,
1705
-            'ticket_rows'              => '',
1706
-            'existing_ticket_ids'      => '',
1707
-            'total_ticket_rows'        => 1,
1708
-            'ticket_js_structure'      => '',
1709
-            'trash_icon'               => 'dashicons dashicons-lock',
1710
-            'disabled'                 => '',
1711
-        ];
1712
-        $event_id      = is_object($this->_cpt_model_obj) ? $this->_cpt_model_obj->ID() : null;
1713
-        /**
1714
-         * 1. Start with retrieving Datetimes
1715
-         * 2. Fore each datetime get related tickets
1716
-         * 3. For each ticket get related prices
1717
-         */
1718
-        /** @var EEM_Datetime $datetime_model */
1719
-        $datetime_model = EE_Registry::instance()->load_model('Datetime');
1720
-        /** @var EEM_Ticket $datetime_model */
1721
-        $ticket_model = EE_Registry::instance()->load_model('Ticket');
1722
-        $times        = $datetime_model->get_all_event_dates($event_id);
1723
-        /** @type EE_Datetime $first_datetime */
1724
-        $first_datetime = reset($times);
1725
-        // do we get related tickets?
1726
-        if (
1727
-            $first_datetime instanceof EE_Datetime
1728
-            && $first_datetime->ID() !== 0
1729
-        ) {
1730
-            $existing_datetime_ids[] = $first_datetime->get('DTT_ID');
1731
-            $template_args['time']   = $first_datetime;
1732
-            $related_tickets         = $first_datetime->tickets(
1733
-                [
1734
-                    ['OR' => ['TKT_deleted' => 1, 'TKT_deleted*' => 0]],
1735
-                    'default_where_conditions' => 'none',
1736
-                ]
1737
-            );
1738
-            if (! empty($related_tickets)) {
1739
-                $template_args['total_ticket_rows'] = count($related_tickets);
1740
-                $row                                = 0;
1741
-                foreach ($related_tickets as $ticket) {
1742
-                    $existing_ticket_ids[]        = $ticket->get('TKT_ID');
1743
-                    $template_args['ticket_rows'] .= $this->_get_ticket_row($ticket, false, $row);
1744
-                    $row++;
1745
-                }
1746
-            } else {
1747
-                $template_args['total_ticket_rows'] = 1;
1748
-                /** @type EE_Ticket $ticket */
1749
-                $ticket                       = $ticket_model->create_default_object();
1750
-                $template_args['ticket_rows'] .= $this->_get_ticket_row($ticket);
1751
-            }
1752
-        } else {
1753
-            $template_args['time'] = $times[0];
1754
-            /** @type EE_Ticket[] $tickets */
1755
-            $tickets                      = $ticket_model->get_all_default_tickets();
1756
-            $template_args['ticket_rows'] .= $this->_get_ticket_row($tickets[1]);
1757
-            // NOTE: we're just sending the first default row
1758
-            // (decaf can't manage default tickets so this should be sufficient);
1759
-        }
1760
-        $template_args['event_datetime_help_link'] = $this->_get_help_tab_link(
1761
-            'event_editor_event_datetimes_help_tab'
1762
-        );
1763
-        $template_args['ticket_options_help_link'] = $this->_get_help_tab_link('ticket_options_info');
1764
-        $template_args['existing_datetime_ids']    = implode(',', $existing_datetime_ids);
1765
-        $template_args['existing_ticket_ids']      = implode(',', $existing_ticket_ids);
1766
-        $template_args['ticket_js_structure']      = $this->_get_ticket_row(
1767
-            $ticket_model->create_default_object(),
1768
-            true
1769
-        );
1770
-        $template                                  = apply_filters(
1771
-            'FHEE__Events_Admin_Page__ticket_metabox__template',
1772
-            EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_main.template.php'
1773
-        );
1774
-        EEH_Template::display_template($template, $template_args);
1775
-    }
1776
-
1777
-
1778
-    /**
1779
-     * Setup an individual ticket form for the decaf event editor page
1780
-     *
1781
-     * @access private
1782
-     * @param EE_Ticket $ticket   the ticket object
1783
-     * @param boolean   $skeleton whether we're generating a skeleton for js manipulation
1784
-     * @param int       $row
1785
-     * @return string generated html for the ticket row.
1786
-     * @throws EE_Error
1787
-     * @throws ReflectionException
1788
-     */
1789
-    private function _get_ticket_row($ticket, $skeleton = false, $row = 0)
1790
-    {
1791
-        $template_args = [
1792
-            'tkt_status_class'    => ' tkt-status-' . $ticket->ticket_status(),
1793
-            'tkt_archive_class'   => $ticket->ticket_status() === EE_Ticket::archived && ! $skeleton ? ' tkt-archived'
1794
-                : '',
1795
-            'ticketrow'           => $skeleton ? 'TICKETNUM' : $row,
1796
-            'TKT_ID'              => $ticket->get('TKT_ID'),
1797
-            'TKT_name'            => $ticket->get('TKT_name'),
1798
-            'TKT_start_date'      => $skeleton ? '' : $ticket->get_date('TKT_start_date', 'Y-m-d h:i a'),
1799
-            'TKT_end_date'        => $skeleton ? '' : $ticket->get_date('TKT_end_date', 'Y-m-d h:i a'),
1800
-            'TKT_is_default'      => $ticket->get('TKT_is_default'),
1801
-            'TKT_qty'             => $ticket->get_pretty('TKT_qty', 'input'),
1802
-            'edit_ticketrow_name' => $skeleton ? 'TICKETNAMEATTR' : 'edit_tickets',
1803
-            'TKT_sold'            => $skeleton ? 0 : $ticket->get('TKT_sold'),
1804
-            'trash_icon'          => ($skeleton || (! empty($ticket) && ! $ticket->get('TKT_deleted')))
1805
-                                     && (! empty($ticket) && $ticket->get('TKT_sold') === 0)
1806
-                ? 'trash-icon dashicons dashicons-post-trash clickable' : 'dashicons dashicons-lock',
1807
-            'disabled'            => $skeleton || (! empty($ticket) && ! $ticket->get('TKT_deleted')) ? ''
1808
-                : ' disabled=disabled',
1809
-        ];
1810
-        $price         = $ticket->ID() !== 0
1811
-            ? $ticket->get_first_related('Price', ['default_where_conditions' => 'none'])
1812
-            : null;
1813
-        $price         = $price instanceof EE_Price
1814
-            ? $price
1815
-            : EEM_Price::instance()->create_default_object();
1816
-        $price_args    = [
1817
-            'price_currency_symbol' => EE_Registry::instance()->CFG->currency->sign,
1818
-            'PRC_amount'            => $price->get('PRC_amount'),
1819
-            'PRT_ID'                => $price->get('PRT_ID'),
1820
-            'PRC_ID'                => $price->get('PRC_ID'),
1821
-            'PRC_is_default'        => $price->get('PRC_is_default'),
1822
-        ];
1823
-        // make sure we have default start and end dates if skeleton
1824
-        // handle rows that should NOT be empty
1825
-        if (empty($template_args['TKT_start_date'])) {
1826
-            // if empty then the start date will be now.
1827
-            $template_args['TKT_start_date'] = date('Y-m-d h:i a', current_time('timestamp'));
1828
-        }
1829
-        if (empty($template_args['TKT_end_date'])) {
1830
-            // get the earliest datetime (if present);
1831
-            $earliest_datetime             = $this->_cpt_model_obj->ID() > 0
1832
-                ? $this->_cpt_model_obj->get_first_related(
1833
-                    'Datetime',
1834
-                    ['order_by' => ['DTT_EVT_start' => 'ASC']]
1835
-                )
1836
-                : null;
1837
-            $template_args['TKT_end_date'] = $earliest_datetime instanceof EE_Datetime
1838
-                ? $earliest_datetime->get_datetime('DTT_EVT_start', 'Y-m-d', 'h:i a')
1839
-                : date('Y-m-d h:i a', mktime(0, 0, 0, date('m'), date('d') + 7, date('Y')));
1840
-        }
1841
-        $template_args = array_merge($template_args, $price_args);
1842
-        $template      = apply_filters(
1843
-            'FHEE__Events_Admin_Page__get_ticket_row__template',
1844
-            EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_ticket_row.template.php',
1845
-            $ticket
1846
-        );
1847
-        return EEH_Template::display_template($template, $template_args, true);
1848
-    }
1849
-
1850
-
1851
-    /**
1852
-     * @throws EE_Error
1853
-     * @throws ReflectionException
1854
-     */
1855
-    public function registration_options_meta_box()
1856
-    {
1857
-        $yes_no_values             = [
1858
-            ['id' => true, 'text' => esc_html__('Yes', 'event_espresso')],
1859
-            ['id' => false, 'text' => esc_html__('No', 'event_espresso')],
1860
-        ];
1861
-        $default_reg_status_values = EEM_Registration::reg_status_array(
1862
-            [
1863
-                EEM_Registration::status_id_cancelled,
1864
-                EEM_Registration::status_id_declined,
1865
-                EEM_Registration::status_id_incomplete,
1866
-            ],
1867
-            true
1868
-        );
1869
-        // $template_args['is_active_select'] = EEH_Form_Fields::select_input('is_active', $yes_no_values, $this->_cpt_model_obj->is_active());
1870
-        $template_args['_event']                          = $this->_cpt_model_obj;
1871
-        $template_args['event']                           = $this->_cpt_model_obj;
1872
-        $template_args['active_status']                   = $this->_cpt_model_obj->pretty_active_status(false);
1873
-        $template_args['additional_limit']                = $this->_cpt_model_obj->additional_limit();
1874
-        $template_args['default_registration_status']     = EEH_Form_Fields::select_input(
1875
-            'default_reg_status',
1876
-            $default_reg_status_values,
1877
-            $this->_cpt_model_obj->default_registration_status()
1878
-        );
1879
-        $template_args['display_description']             = EEH_Form_Fields::select_input(
1880
-            'display_desc',
1881
-            $yes_no_values,
1882
-            $this->_cpt_model_obj->display_description()
1883
-        );
1884
-        $template_args['display_ticket_selector']         = EEH_Form_Fields::select_input(
1885
-            'display_ticket_selector',
1886
-            $yes_no_values,
1887
-            $this->_cpt_model_obj->display_ticket_selector(),
1888
-            '',
1889
-            '',
1890
-            false
1891
-        );
1892
-        $template_args['additional_registration_options'] = apply_filters(
1893
-            'FHEE__Events_Admin_Page__registration_options_meta_box__additional_registration_options',
1894
-            '',
1895
-            $template_args,
1896
-            $yes_no_values,
1897
-            $default_reg_status_values
1898
-        );
1899
-        EEH_Template::display_template(
1900
-            EVENTS_TEMPLATE_PATH . 'event_registration_options.template.php',
1901
-            $template_args
1902
-        );
1903
-    }
1904
-
1905
-
1906
-    /**
1907
-     * _get_events()
1908
-     * This method simply returns all the events (for the given _view and paging)
1909
-     *
1910
-     * @access public
1911
-     * @param int  $per_page     count of items per page (20 default);
1912
-     * @param int  $current_page what is the current page being viewed.
1913
-     * @param bool $count        if TRUE then we just return a count of ALL events matching the given _view.
1914
-     *                           If FALSE then we return an array of event objects
1915
-     *                           that match the given _view and paging parameters.
1916
-     * @return array|int         an array of event objects or a count of them.
1917
-     * @throws Exception
1918
-     */
1919
-    public function get_events($per_page = 10, $current_page = 1, $count = false)
1920
-    {
1921
-        $EEM_Event   = $this->_event_model();
1922
-        $offset      = ($current_page - 1) * $per_page;
1923
-        $limit       = $count ? null : $offset . ',' . $per_page;
1924
-        $orderby     = $this->request->getRequestParam('orderby', 'EVT_ID');
1925
-        $order       = $this->request->getRequestParam('order', 'DESC');
1926
-        $month_range = $this->request->getRequestParam('month_range');
1927
-        if ($month_range) {
1928
-            $pieces = explode(' ', $month_range, 3);
1929
-            // simulate the FIRST day of the month, that fixes issues for months like February
1930
-            // where PHP doesn't know what to assume for date.
1931
-            // @see https://events.codebasehq.com/projects/event-espresso/tickets/10437
1932
-            $month_r = ! empty($pieces[0]) ? date('m', EEH_DTT_Helper::first_of_month_timestamp($pieces[0])) : '';
1933
-            $year_r  = ! empty($pieces[1]) ? $pieces[1] : '';
1934
-        }
1935
-        $where  = [];
1936
-        $status = $this->request->getRequestParam('status');
1937
-        // determine what post_status our condition will have for the query.
1938
-        switch ($status) {
1939
-            case 'month':
1940
-            case 'today':
1941
-            case null:
1942
-            case 'all':
1943
-                break;
1944
-            case 'draft':
1945
-                $where['status'] = ['IN', ['draft', 'auto-draft']];
1946
-                break;
1947
-            default:
1948
-                $where['status'] = $status;
1949
-        }
1950
-        // categories? The default for all categories is -1
1951
-        $category = $this->request->getRequestParam('EVT_CAT', -1, 'int');
1952
-        if ($category !== -1) {
1953
-            $where['Term_Taxonomy.taxonomy'] = EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY;
1954
-            $where['Term_Taxonomy.term_id']  = $category;
1955
-        }
1956
-        // date where conditions
1957
-        $start_formats = EEM_Datetime::instance()->get_formats_for('DTT_EVT_start');
1958
-        if ($month_range) {
1959
-            $DateTime = new DateTime(
1960
-                $year_r . '-' . $month_r . '-01 00:00:00',
1961
-                new DateTimeZone('UTC')
1962
-            );
1963
-            $start    = $DateTime->getTimestamp();
1964
-            // set the datetime to be the end of the month
1965
-            $DateTime->setDate(
1966
-                $year_r,
1967
-                $month_r,
1968
-                $DateTime->format('t')
1969
-            )->setTime(23, 59, 59);
1970
-            $end                             = $DateTime->getTimestamp();
1971
-            $where['Datetime.DTT_EVT_start'] = ['BETWEEN', [$start, $end]];
1972
-        } elseif ($status === 'today') {
1973
-            $DateTime                        =
1974
-                new DateTime('now', new DateTimeZone(EEM_Event::instance()->get_timezone()));
1975
-            $start                           = $DateTime->setTime(0, 0)->format(implode(' ', $start_formats));
1976
-            $end                             = $DateTime->setTime(23, 59, 59)->format(implode(' ', $start_formats));
1977
-            $where['Datetime.DTT_EVT_start'] = ['BETWEEN', [$start, $end]];
1978
-        } elseif ($status === 'month') {
1979
-            $now                             = date('Y-m-01');
1980
-            $DateTime                        =
1981
-                new DateTime($now, new DateTimeZone(EEM_Event::instance()->get_timezone()));
1982
-            $start                           = $DateTime->setTime(0, 0)->format(implode(' ', $start_formats));
1983
-            $end                             = $DateTime->setDate(date('Y'), date('m'), $DateTime->format('t'))
1984
-                                                        ->setTime(23, 59, 59)
1985
-                                                        ->format(implode(' ', $start_formats));
1986
-            $where['Datetime.DTT_EVT_start'] = ['BETWEEN', [$start, $end]];
1987
-        }
1988
-        if (! EE_Registry::instance()->CAP->current_user_can('ee_read_others_events', 'get_events')) {
1989
-            $where['EVT_wp_user'] = get_current_user_id();
1990
-        } else {
1991
-            if (! isset($where['status'])) {
1992
-                if (! EE_Registry::instance()->CAP->current_user_can('ee_read_private_events', 'get_events')) {
1993
-                    $where['OR'] = [
1994
-                        'status*restrict_private' => ['!=', 'private'],
1995
-                        'AND'                     => [
1996
-                            'status*inclusive' => ['=', 'private'],
1997
-                            'EVT_wp_user'      => get_current_user_id(),
1998
-                        ],
1999
-                    ];
2000
-                }
2001
-            }
2002
-        }
2003
-        $wp_user = $this->request->getRequestParam('EVT_wp_user', 0, 'int');
2004
-        if (
2005
-            $wp_user
2006
-            && $wp_user !== get_current_user_id()
2007
-            && EE_Registry::instance()->CAP->current_user_can('ee_read_others_events', 'get_events')
2008
-        ) {
2009
-            $where['EVT_wp_user'] = $wp_user;
2010
-        }
2011
-        // search query handling
2012
-        $search_term = $this->request->getRequestParam('s');
2013
-        if ($search_term) {
2014
-            $search_term = '%' . $search_term . '%';
2015
-            $where['OR'] = [
2016
-                'EVT_name'       => ['LIKE', $search_term],
2017
-                'EVT_desc'       => ['LIKE', $search_term],
2018
-                'EVT_short_desc' => ['LIKE', $search_term],
2019
-            ];
2020
-        }
2021
-        // filter events by venue.
2022
-        $venue = $this->request->getRequestParam('venue', 0, 'int');
2023
-        if ($venue) {
2024
-            $where['Venue.VNU_ID'] = $venue;
2025
-        }
2026
-        $request_params = $this->request->requestParams();
2027
-        $where          = apply_filters('FHEE__Events_Admin_Page__get_events__where', $where, $request_params);
2028
-        $query_params   = apply_filters(
2029
-            'FHEE__Events_Admin_Page__get_events__query_params',
2030
-            [
2031
-                $where,
2032
-                'limit'    => $limit,
2033
-                'order_by' => $orderby,
2034
-                'order'    => $order,
2035
-                'group_by' => 'EVT_ID',
2036
-            ],
2037
-            $request_params
2038
-        );
2039
-
2040
-        // let's first check if we have special requests coming in.
2041
-        $active_status = $this->request->getRequestParam('active_status');
2042
-        if ($active_status) {
2043
-            switch ($active_status) {
2044
-                case 'upcoming':
2045
-                    return $EEM_Event->get_upcoming_events($query_params, $count);
2046
-                case 'expired':
2047
-                    return $EEM_Event->get_expired_events($query_params, $count);
2048
-                case 'active':
2049
-                    return $EEM_Event->get_active_events($query_params, $count);
2050
-                case 'inactive':
2051
-                    return $EEM_Event->get_inactive_events($query_params, $count);
2052
-            }
2053
-        }
2054
-
2055
-        return $count ? $EEM_Event->count([$where], 'EVT_ID', true) : $EEM_Event->get_all($query_params);
2056
-    }
2057
-
2058
-
2059
-    /**
2060
-     * handling for WordPress CPT actions (trash, restore, delete)
2061
-     *
2062
-     * @param string $post_id
2063
-     * @throws EE_Error
2064
-     * @throws ReflectionException
2065
-     */
2066
-    public function trash_cpt_item($post_id)
2067
-    {
2068
-        $this->request->setRequestParam('EVT_ID', $post_id);
2069
-        $this->_trash_or_restore_event('trash', false);
2070
-    }
2071
-
2072
-
2073
-    /**
2074
-     * @param string $post_id
2075
-     * @throws EE_Error
2076
-     * @throws ReflectionException
2077
-     */
2078
-    public function restore_cpt_item($post_id)
2079
-    {
2080
-        $this->request->setRequestParam('EVT_ID', $post_id);
2081
-        $this->_trash_or_restore_event('draft', false);
2082
-    }
2083
-
2084
-
2085
-    /**
2086
-     * @param string $post_id
2087
-     * @throws EE_Error
2088
-     * @throws EE_Error
2089
-     */
2090
-    public function delete_cpt_item($post_id)
2091
-    {
2092
-        throw new EE_Error(
2093
-            esc_html__(
2094
-                'Please contact Event Espresso support with the details of the steps taken to produce this error.',
2095
-                'event_espresso'
2096
-            )
2097
-        );
2098
-        // $this->request->setRequestParam('EVT_ID', $post_id);
2099
-        // $this->_delete_event();
2100
-    }
2101
-
2102
-
2103
-    /**
2104
-     * _trash_or_restore_event
2105
-     *
2106
-     * @access protected
2107
-     * @param string $event_status
2108
-     * @param bool   $redirect_after
2109
-     * @throws EE_Error
2110
-     * @throws EE_Error
2111
-     * @throws ReflectionException
2112
-     */
2113
-    protected function _trash_or_restore_event($event_status = 'trash', $redirect_after = true)
2114
-    {
2115
-        // determine the event id and set to array.
2116
-        $EVT_ID = $this->request->getRequestParam('EVT_ID', 0, 'int');
2117
-        // loop thru events
2118
-        if ($EVT_ID) {
2119
-            // clean status
2120
-            $event_status = sanitize_key($event_status);
2121
-            // grab status
2122
-            if (! empty($event_status)) {
2123
-                $success = $this->_change_event_status($EVT_ID, $event_status);
2124
-            } else {
2125
-                $success = false;
2126
-                $msg     = esc_html__(
2127
-                    'An error occurred. The event could not be moved to the trash because a valid event status was not not supplied.',
2128
-                    'event_espresso'
2129
-                );
2130
-                EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2131
-            }
2132
-        } else {
2133
-            $success = false;
2134
-            $msg     = esc_html__(
2135
-                'An error occurred. The event could not be moved to the trash because a valid event ID was not not supplied.',
2136
-                'event_espresso'
2137
-            );
2138
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2139
-        }
2140
-        $action = $event_status === 'trash' ? 'moved to the trash' : 'restored from the trash';
2141
-        if ($redirect_after) {
2142
-            $this->_redirect_after_action($success, 'Event', $action, ['action' => 'default']);
2143
-        }
2144
-    }
2145
-
2146
-
2147
-    /**
2148
-     * _trash_or_restore_events
2149
-     *
2150
-     * @access protected
2151
-     * @param string $event_status
2152
-     * @return void
2153
-     * @throws EE_Error
2154
-     * @throws EE_Error
2155
-     * @throws ReflectionException
2156
-     */
2157
-    protected function _trash_or_restore_events($event_status = 'trash')
2158
-    {
2159
-        // clean status
2160
-        $event_status = sanitize_key($event_status);
2161
-        // grab status
2162
-        if (! empty($event_status)) {
2163
-            $success = true;
2164
-            // determine the event id and set to array.
2165
-            $EVT_IDs = $this->request->getRequestParam('EVT_IDs', [], 'int', true);
2166
-            // loop thru events
2167
-            foreach ($EVT_IDs as $EVT_ID) {
2168
-                if ($EVT_ID = absint($EVT_ID)) {
2169
-                    $results = $this->_change_event_status($EVT_ID, $event_status);
2170
-                    $success = $results !== false ? $success : false;
2171
-                } else {
2172
-                    $msg = sprintf(
2173
-                        esc_html__(
2174
-                            'An error occurred. Event #%d could not be moved to the trash because a valid event ID was not not supplied.',
2175
-                            'event_espresso'
2176
-                        ),
2177
-                        $EVT_ID
2178
-                    );
2179
-                    EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2180
-                    $success = false;
2181
-                }
2182
-            }
2183
-        } else {
2184
-            $success = false;
2185
-            $msg     = esc_html__(
2186
-                'An error occurred. The event could not be moved to the trash because a valid event status was not not supplied.',
2187
-                'event_espresso'
2188
-            );
2189
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2190
-        }
2191
-        // in order to force a pluralized result message we need to send back a success status greater than 1
2192
-        $success = $success ? 2 : false;
2193
-        $action  = $event_status === 'trash' ? 'moved to the trash' : 'restored from the trash';
2194
-        $this->_redirect_after_action($success, 'Events', $action, ['action' => 'default']);
2195
-    }
2196
-
2197
-
2198
-    /**
2199
-     * @param int    $EVT_ID
2200
-     * @param string $event_status
2201
-     * @return bool
2202
-     * @throws EE_Error
2203
-     * @throws ReflectionException
2204
-     */
2205
-    private function _change_event_status($EVT_ID = 0, $event_status = '')
2206
-    {
2207
-        // grab event id
2208
-        if (! $EVT_ID) {
2209
-            $msg = esc_html__(
2210
-                'An error occurred. No Event ID or an invalid Event ID was received.',
2211
-                'event_espresso'
2212
-            );
2213
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2214
-            return false;
2215
-        }
2216
-        $this->_cpt_model_obj = EEM_Event::instance()->get_one_by_ID($EVT_ID);
2217
-        // clean status
2218
-        $event_status = sanitize_key($event_status);
2219
-        // grab status
2220
-        if (empty($event_status)) {
2221
-            $msg = esc_html__(
2222
-                'An error occurred. No Event Status or an invalid Event Status was received.',
2223
-                'event_espresso'
2224
-            );
2225
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2226
-            return false;
2227
-        }
2228
-        // was event trashed or restored ?
2229
-        switch ($event_status) {
2230
-            case 'draft':
2231
-                $action = 'restored from the trash';
2232
-                $hook   = 'AHEE_event_restored_from_trash';
2233
-                break;
2234
-            case 'trash':
2235
-                $action = 'moved to the trash';
2236
-                $hook   = 'AHEE_event_moved_to_trash';
2237
-                break;
2238
-            default:
2239
-                $action = 'updated';
2240
-                $hook   = false;
2241
-        }
2242
-        // use class to change status
2243
-        $this->_cpt_model_obj->set_status($event_status);
2244
-        $success = $this->_cpt_model_obj->save();
2245
-        if (! $success) {
2246
-            $msg = sprintf(esc_html__('An error occurred. The event could not be %s.', 'event_espresso'), $action);
2247
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2248
-            return false;
2249
-        }
2250
-        if ($hook) {
2251
-            do_action($hook);
2252
-        }
2253
-        return true;
2254
-    }
2255
-
2256
-
2257
-    /**
2258
-     * @param array $event_ids
2259
-     * @return array
2260
-     * @since   4.10.23.p
2261
-     */
2262
-    private function cleanEventIds(array $event_ids)
2263
-    {
2264
-        return array_map('absint', $event_ids);
2265
-    }
2266
-
2267
-
2268
-    /**
2269
-     * @return array
2270
-     * @since   4.10.23.p
2271
-     */
2272
-    private function getEventIdsFromRequest()
2273
-    {
2274
-        if ($this->request->requestParamIsSet('EVT_IDs')) {
2275
-            return $this->request->getRequestParam('EVT_IDs', [], 'int', true);
2276
-        } else {
2277
-            return $this->request->getRequestParam('EVT_ID', [], 'int', true);
2278
-        }
2279
-    }
2280
-
2281
-
2282
-    /**
2283
-     * @param bool $preview_delete
2284
-     * @throws EE_Error
2285
-     */
2286
-    protected function _delete_event($preview_delete = true)
2287
-    {
2288
-        $this->_delete_events($preview_delete);
2289
-    }
2290
-
2291
-
2292
-    /**
2293
-     * Gets the tree traversal batch persister.
2294
-     *
2295
-     * @return NodeGroupDao
2296
-     * @throws InvalidArgumentException
2297
-     * @throws InvalidDataTypeException
2298
-     * @throws InvalidInterfaceException
2299
-     * @since 4.10.12.p
2300
-     */
2301
-    protected function getModelObjNodeGroupPersister()
2302
-    {
2303
-        if (! $this->model_obj_node_group_persister instanceof NodeGroupDao) {
2304
-            $this->model_obj_node_group_persister =
2305
-                $this->getLoader()->load('\EventEspresso\core\services\orm\tree_traversal\NodeGroupDao');
2306
-        }
2307
-        return $this->model_obj_node_group_persister;
2308
-    }
2309
-
2310
-
2311
-    /**
2312
-     * @param bool $preview_delete
2313
-     * @return void
2314
-     * @throws EE_Error
2315
-     */
2316
-    protected function _delete_events($preview_delete = true)
2317
-    {
2318
-        $event_ids = $this->getEventIdsFromRequest();
2319
-        if ($preview_delete) {
2320
-            $this->generateDeletionPreview($event_ids);
2321
-        } else {
2322
-            EEM_Event::instance()->delete_permanently([['EVT_ID' => ['IN', $event_ids]]]);
2323
-        }
2324
-    }
2325
-
2326
-
2327
-    /**
2328
-     * @param array $event_ids
2329
-     */
2330
-    protected function generateDeletionPreview(array $event_ids)
2331
-    {
2332
-        $event_ids = $this->cleanEventIds($event_ids);
2333
-        // Set a code we can use to reference this deletion task in the batch jobs and preview page.
2334
-        $deletion_job_code = $this->getModelObjNodeGroupPersister()->generateGroupCode();
2335
-        $return_url        = EE_Admin_Page::add_query_args_and_nonce(
2336
-            [
2337
-                'action'            => 'preview_deletion',
2338
-                'deletion_job_code' => $deletion_job_code,
2339
-            ],
2340
-            $this->_admin_base_url
2341
-        );
2342
-        EEH_URL::safeRedirectAndExit(
2343
-            EE_Admin_Page::add_query_args_and_nonce(
2344
-                [
2345
-                    'page'              => EED_Batch::PAGE_SLUG,
2346
-                    'batch'             => EED_Batch::batch_job,
2347
-                    'EVT_IDs'           => $event_ids,
2348
-                    'deletion_job_code' => $deletion_job_code,
2349
-                    'job_handler'       => urlencode('EventEspressoBatchRequest\JobHandlers\PreviewEventDeletion'),
2350
-                    'return_url'        => urlencode($return_url),
2351
-                ],
2352
-                admin_url()
2353
-            )
2354
-        );
2355
-    }
2356
-
2357
-
2358
-    /**
2359
-     * Checks for a POST submission
2360
-     *
2361
-     * @since 4.10.12.p
2362
-     */
2363
-    protected function confirmDeletion()
2364
-    {
2365
-        $deletion_redirect_logic =
2366
-            $this->getLoader()->getShared('\EventEspresso\core\domain\services\admin\events\data\ConfirmDeletion');
2367
-        $deletion_redirect_logic->handle($this->get_request_data(), $this->admin_base_url());
2368
-    }
2369
-
2370
-
2371
-    /**
2372
-     * A page for users to preview what exactly will be deleted, and confirm they want to delete it.
2373
-     *
2374
-     * @throws EE_Error
2375
-     * @since 4.10.12.p
2376
-     */
2377
-    protected function previewDeletion()
2378
-    {
2379
-        $preview_deletion_logic =
2380
-            $this->getLoader()->getShared('\EventEspresso\core\domain\services\admin\events\data\PreviewDeletion');
2381
-        $this->set_template_args($preview_deletion_logic->handle($this->get_request_data(), $this->admin_base_url()));
2382
-        $this->display_admin_page_with_no_sidebar();
2383
-    }
2384
-
2385
-
2386
-    /**
2387
-     * get total number of events
2388
-     *
2389
-     * @access public
2390
-     * @return int
2391
-     * @throws EE_Error
2392
-     * @throws EE_Error
2393
-     */
2394
-    public function total_events()
2395
-    {
2396
-        return EEM_Event::instance()->count(
2397
-            ['caps' => 'read_admin'],
2398
-            'EVT_ID',
2399
-            true
2400
-        );
2401
-    }
2402
-
2403
-
2404
-    /**
2405
-     * get total number of draft events
2406
-     *
2407
-     * @access public
2408
-     * @return int
2409
-     * @throws EE_Error
2410
-     * @throws EE_Error
2411
-     */
2412
-    public function total_events_draft()
2413
-    {
2414
-        return EEM_Event::instance()->count(
2415
-            [
2416
-                ['status' => ['IN', ['draft', 'auto-draft']]],
2417
-                'caps' => 'read_admin',
2418
-            ],
2419
-            'EVT_ID',
2420
-            true
2421
-        );
2422
-    }
2423
-
2424
-
2425
-    /**
2426
-     * get total number of trashed events
2427
-     *
2428
-     * @access public
2429
-     * @return int
2430
-     * @throws EE_Error
2431
-     * @throws EE_Error
2432
-     */
2433
-    public function total_trashed_events()
2434
-    {
2435
-        return EEM_Event::instance()->count(
2436
-            [
2437
-                ['status' => 'trash'],
2438
-                'caps' => 'read_admin',
2439
-            ],
2440
-            'EVT_ID',
2441
-            true
2442
-        );
2443
-    }
2444
-
2445
-
2446
-    /**
2447
-     *    _default_event_settings
2448
-     *    This generates the Default Settings Tab
2449
-     *
2450
-     * @return void
2451
-     * @throws DomainException
2452
-     * @throws EE_Error
2453
-     * @throws InvalidArgumentException
2454
-     * @throws InvalidDataTypeException
2455
-     * @throws InvalidInterfaceException
2456
-     */
2457
-    protected function _default_event_settings()
2458
-    {
2459
-        $this->_set_add_edit_form_tags('update_default_event_settings');
2460
-        $this->_set_publish_post_box_vars(null, false, false, null, false);
2461
-        $this->_template_args['admin_page_content'] = EEH_HTML::div(
2462
-            $this->_default_event_settings_form()->get_html(),
2463
-            '',
2464
-            'padding'
2465
-        );
2466
-        $this->display_admin_page_with_sidebar();
2467
-    }
2468
-
2469
-
2470
-    /**
2471
-     * Return the form for event settings.
2472
-     *
2473
-     * @return EE_Form_Section_Proper
2474
-     * @throws EE_Error
2475
-     */
2476
-    protected function _default_event_settings_form()
2477
-    {
2478
-        $registration_config              = EE_Registry::instance()->CFG->registration;
2479
-        $registration_stati_for_selection = EEM_Registration::reg_status_array(
2480
-        // exclude
2481
-            [
2482
-                EEM_Registration::status_id_cancelled,
2483
-                EEM_Registration::status_id_declined,
2484
-                EEM_Registration::status_id_incomplete,
2485
-                EEM_Registration::status_id_wait_list,
2486
-            ],
2487
-            true
2488
-        );
2489
-        // setup Advanced Editor ???
2490
-        if (
2491
-            $this->raw_req_action === 'default_event_settings'
2492
-            || $this->raw_req_action === 'update_default_event_settings'
2493
-        ) {
2494
-            $this->advanced_editor_admin_form = $this->loader->getShared(AdvancedEditorAdminFormSection::class);
2495
-        }
2496
-        return new EE_Form_Section_Proper(
2497
-            [
2498
-                'name'            => 'update_default_event_settings',
2499
-                'html_id'         => 'update_default_event_settings',
2500
-                'html_class'      => 'form-table',
2501
-                'layout_strategy' => new EE_Admin_Two_Column_Layout(),
2502
-                'subsections'     => apply_filters(
2503
-                    'FHEE__Events_Admin_Page___default_event_settings_form__form_subsections',
2504
-                    [
2505
-                        'defaults_section_header' => new EE_Form_Section_HTML(
2506
-                            EEH_HTML::h2(
2507
-                                esc_html__('Default Settings', 'event_espresso'),
2508
-                                '',
2509
-                                'ee-admin-settings-hdr'
2510
-                            )
2511
-                        ),
2512
-                        'default_reg_status'  => new EE_Select_Input(
2513
-                            $registration_stati_for_selection,
2514
-                            [
2515
-                                'default'         => isset($registration_config->default_STS_ID)
2516
-                                                     && array_key_exists(
2517
-                                                         $registration_config->default_STS_ID,
2518
-                                                         $registration_stati_for_selection
2519
-                                                     )
2520
-                                    ? sanitize_text_field($registration_config->default_STS_ID)
2521
-                                    : EEM_Registration::status_id_pending_payment,
2522
-                                'html_label_text' => esc_html__('Default Registration Status', 'event_espresso')
2523
-                                                     . EEH_Template::get_help_tab_link(
2524
-                                                         'default_settings_status_help_tab'
2525
-                                                     ),
2526
-                                'html_help_text'  => esc_html__(
2527
-                                    'This setting allows you to preselect what the default registration status setting is when creating an event.  Note that changing this setting does NOT retroactively apply it to existing events.',
2528
-                                    'event_espresso'
2529
-                                ),
2530
-                            ]
2531
-                        ),
2532
-                        'default_max_tickets' => new EE_Integer_Input(
2533
-                            [
2534
-                                'default'         => isset($registration_config->default_maximum_number_of_tickets)
2535
-                                    ? $registration_config->default_maximum_number_of_tickets
2536
-                                    : EEM_Event::get_default_additional_limit(),
2537
-                                'html_label_text' => esc_html__(
2538
-                                    'Default Maximum Tickets Allowed Per Order:',
2539
-                                    'event_espresso'
2540
-                                )
2541
-                                                     . EEH_Template::get_help_tab_link(
2542
-                                                         'default_maximum_tickets_help_tab"'
2543
-                                                     ),
2544
-                                'html_help_text'  => esc_html__(
2545
-                                    'This setting allows you to indicate what will be the default for the maximum number of tickets per order when creating new events.',
2546
-                                    'event_espresso'
2547
-                                ),
2548
-                            ]
2549
-                        ),
2550
-                    ]
2551
-                ),
2552
-            ]
2553
-        );
2554
-    }
2555
-
2556
-
2557
-    /**
2558
-     * @return void
2559
-     * @throws EE_Error
2560
-     * @throws InvalidArgumentException
2561
-     * @throws InvalidDataTypeException
2562
-     * @throws InvalidInterfaceException
2563
-     */
2564
-    protected function _update_default_event_settings()
2565
-    {
2566
-        $form = $this->_default_event_settings_form();
2567
-        if ($form->was_submitted()) {
2568
-            $form->receive_form_submission();
2569
-            if ($form->is_valid()) {
2570
-                $registration_config = EE_Registry::instance()->CFG->registration;
2571
-                $valid_data          = $form->valid_data();
2572
-                if (isset($valid_data['default_reg_status'])) {
2573
-                    $registration_config->default_STS_ID = $valid_data['default_reg_status'];
2574
-                }
2575
-                if (isset($valid_data['default_max_tickets'])) {
2576
-                    $registration_config->default_maximum_number_of_tickets = $valid_data['default_max_tickets'];
2577
-                }
2578
-                do_action(
2579
-                    'AHEE__Events_Admin_Page___update_default_event_settings',
2580
-                    $valid_data,
2581
-                    EE_Registry::instance()->CFG,
2582
-                    $this
2583
-                );
2584
-                // update because data was valid!
2585
-                EE_Registry::instance()->CFG->update_espresso_config();
2586
-                EE_Error::overwrite_success();
2587
-                EE_Error::add_success(
2588
-                    esc_html__('Default Event Settings were updated', 'event_espresso')
2589
-                );
2590
-            }
2591
-        }
2592
-        $this->_redirect_after_action(0, '', '', ['action' => 'default_event_settings'], true);
2593
-    }
2594
-
2595
-
2596
-    /*************        Templates        *************
2597
-     *
2598
-     * @throws EE_Error
2599
-     */
2600
-    protected function _template_settings()
2601
-    {
2602
-        $this->_admin_page_title              = esc_html__('Template Settings (Preview)', 'event_espresso');
2603
-        $this->_template_args['preview_img']  = '<img src="'
2604
-                                                . EVENTS_ASSETS_URL
2605
-                                                . '/images/'
2606
-                                                . 'caffeinated_template_features.jpg" alt="'
2607
-                                                . esc_attr__('Template Settings Preview screenshot', 'event_espresso')
2608
-                                                . '" />';
2609
-        $this->_template_args['preview_text'] = '<strong>'
2610
-                                                . esc_html__(
2611
-                                                    'Template Settings is a feature that is only available in the premium version of Event Espresso 4 which is available with a support license purchase on EventEspresso.com. Template Settings allow you to configure some of the appearance options for both the Event List and Event Details pages.',
2612
-                                                    'event_espresso'
2613
-                                                ) . '</strong>';
2614
-        $this->display_admin_caf_preview_page('template_settings_tab');
2615
-    }
2616
-
2617
-
2618
-    /** Event Category Stuff **/
2619
-    /**
2620
-     * set the _category property with the category object for the loaded page.
2621
-     *
2622
-     * @access private
2623
-     * @return void
2624
-     */
2625
-    private function _set_category_object()
2626
-    {
2627
-        if (isset($this->_category->id) && ! empty($this->_category->id)) {
2628
-            return;
2629
-        } //already have the category object so get out.
2630
-        // set default category object
2631
-        $this->_set_empty_category_object();
2632
-        // only set if we've got an id
2633
-        $category_ID = $this->request->getRequestParam('EVT_CAT_ID', 0, 'int');
2634
-        if (! $category_ID) {
2635
-            return;
2636
-        }
2637
-        $term = get_term($category_ID, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY);
2638
-        if (! empty($term)) {
2639
-            $this->_category->category_name       = $term->name;
2640
-            $this->_category->category_identifier = $term->slug;
2641
-            $this->_category->category_desc       = $term->description;
2642
-            $this->_category->id                  = $term->term_id;
2643
-            $this->_category->parent              = $term->parent;
2644
-        }
2645
-    }
2646
-
2647
-
2648
-    /**
2649
-     * Clears out category properties.
2650
-     */
2651
-    private function _set_empty_category_object()
2652
-    {
2653
-        $this->_category                = new stdClass();
2654
-        $this->_category->category_name = $this->_category->category_identifier = $this->_category->category_desc = '';
2655
-        $this->_category->id            = $this->_category->parent = 0;
2656
-    }
2657
-
2658
-
2659
-    /**
2660
-     * @throws DomainException
2661
-     * @throws EE_Error
2662
-     * @throws InvalidArgumentException
2663
-     * @throws InvalidDataTypeException
2664
-     * @throws InvalidInterfaceException
2665
-     */
2666
-    protected function _category_list_table()
2667
-    {
2668
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2669
-        $this->_search_btn_label = esc_html__('Categories', 'event_espresso');
2670
-        $this->_admin_page_title .= ' ';
2671
-        $this->_admin_page_title .= $this->get_action_link_or_button(
2672
-            'add_category',
2673
-            'add_category',
2674
-            [],
2675
-            'add-new-h2'
2676
-        );
2677
-        $this->display_admin_list_table_page_with_sidebar();
2678
-    }
2679
-
2680
-
2681
-    /**
2682
-     * Output category details view.
2683
-     *
2684
-     * @throws EE_Error
2685
-     * @throws EE_Error
2686
-     */
2687
-    protected function _category_details($view)
2688
-    {
2689
-        // load formatter helper
2690
-        // load field generator helper
2691
-        $route = $view === 'edit' ? 'update_category' : 'insert_category';
2692
-        $this->_set_add_edit_form_tags($route);
2693
-        $this->_set_category_object();
2694
-        $id            = ! empty($this->_category->id) ? $this->_category->id : '';
2695
-        $delete_action = 'delete_category';
2696
-        // custom redirect
2697
-        $redirect = EE_Admin_Page::add_query_args_and_nonce(
2698
-            ['action' => 'category_list'],
2699
-            $this->_admin_base_url
2700
-        );
2701
-        $this->_set_publish_post_box_vars('EVT_CAT_ID', $id, $delete_action, $redirect);
2702
-        // take care of contents
2703
-        $this->_template_args['admin_page_content'] = $this->_category_details_content();
2704
-        $this->display_admin_page_with_sidebar();
2705
-    }
2706
-
2707
-
2708
-    /**
2709
-     * Output category details content.
2710
-     *
2711
-     * @throws DomainException
2712
-     */
2713
-    protected function _category_details_content()
2714
-    {
2715
-        $editor_args['category_desc'] = [
2716
-            'type'          => 'wp_editor',
2717
-            'value'         => EEH_Formatter::admin_format_content($this->_category->category_desc),
2718
-            'class'         => 'my_editor_custom',
2719
-            'wpeditor_args' => ['media_buttons' => false],
2720
-        ];
2721
-        $_wp_editor                   = $this->_generate_admin_form_fields($editor_args, 'array');
2722
-        $all_terms                    = get_terms(
2723
-            [EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY],
2724
-            ['hide_empty' => 0, 'exclude' => [$this->_category->id]]
2725
-        );
2726
-        // setup category select for term parents.
2727
-        $category_select_values[] = [
2728
-            'text' => esc_html__('No Parent', 'event_espresso'),
2729
-            'id'   => 0,
2730
-        ];
2731
-        foreach ($all_terms as $term) {
2732
-            $category_select_values[] = [
2733
-                'text' => $term->name,
2734
-                'id'   => $term->term_id,
2735
-            ];
2736
-        }
2737
-        $category_select = EEH_Form_Fields::select_input(
2738
-            'category_parent',
2739
-            $category_select_values,
2740
-            $this->_category->parent
2741
-        );
2742
-        $template_args   = [
2743
-            'category'                 => $this->_category,
2744
-            'category_select'          => $category_select,
2745
-            'unique_id_info_help_link' => $this->_get_help_tab_link('unique_id_info'),
2746
-            'category_desc_editor'     => $_wp_editor['category_desc']['field'],
2747
-            'disable'                  => '',
2748
-            'disabled_message'         => false,
2749
-        ];
2750
-        $template        = EVENTS_TEMPLATE_PATH . 'event_category_details.template.php';
2751
-        return EEH_Template::display_template($template, $template_args, true);
2752
-    }
2753
-
2754
-
2755
-    /**
2756
-     * Handles deleting categories.
2757
-     *
2758
-     * @throws EE_Error
2759
-     */
2760
-    protected function _delete_categories()
2761
-    {
2762
-        $category_IDs = $this->request->getRequestParam('EVT_CAT_ID', 0, 'int', true);
2763
-        foreach ($category_IDs as $category_ID) {
2764
-            $this->_delete_category($category_ID);
2765
-        }
2766
-        // doesn't matter what page we're coming from... we're going to the same place after delete.
2767
-        $query_args = [
2768
-            'action' => 'category_list',
2769
-        ];
2770
-        $this->_redirect_after_action(0, '', '', $query_args);
2771
-    }
2772
-
2773
-
2774
-    /**
2775
-     * Handles deleting specific category.
2776
-     *
2777
-     * @param int $cat_id
2778
-     */
2779
-    protected function _delete_category($cat_id)
2780
-    {
2781
-        $cat_id = absint($cat_id);
2782
-        wp_delete_term($cat_id, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY);
2783
-    }
2784
-
2785
-
2786
-    /**
2787
-     * Handles triggering the update or insertion of a new category.
2788
-     *
2789
-     * @param bool $new_category true means we're triggering the insert of a new category.
2790
-     * @throws EE_Error
2791
-     * @throws EE_Error
2792
-     */
2793
-    protected function _insert_or_update_category($new_category)
2794
-    {
2795
-        $cat_id  = $new_category ? $this->_insert_category() : $this->_insert_category(true);
2796
-        $success = 0; // we already have a success message so lets not send another.
2797
-        if ($cat_id) {
2798
-            $query_args = [
2799
-                'action'     => 'edit_category',
2800
-                'EVT_CAT_ID' => $cat_id,
2801
-            ];
2802
-        } else {
2803
-            $query_args = ['action' => 'add_category'];
2804
-        }
2805
-        $this->_redirect_after_action($success, '', '', $query_args, true);
2806
-    }
2807
-
2808
-
2809
-    /**
2810
-     * Inserts or updates category
2811
-     *
2812
-     * @param bool $update (true indicates we're updating a category).
2813
-     * @return bool|mixed|string
2814
-     */
2815
-    private function _insert_category($update = false)
2816
-    {
2817
-        $category_ID         = $update ? $this->request->getRequestParam('EVT_CAT_ID', 0, 'int') : 0;
2818
-        $category_name       = $this->request->getRequestParam('category_name', '');
2819
-        $category_desc       = $this->request->getRequestParam('category_desc', '');
2820
-        $category_parent     = $this->request->getRequestParam('category_parent', 0, 'int');
2821
-        $category_identifier = $this->request->getRequestParam('category_identifier', '');
2822
-
2823
-        if (empty($category_name)) {
2824
-            $msg = esc_html__('You must add a name for the category.', 'event_espresso');
2825
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2826
-            return false;
2827
-        }
2828
-        $term_args = [
2829
-            'name'        => $category_name,
2830
-            'description' => $category_desc,
2831
-            'parent'      => $category_parent,
2832
-        ];
2833
-        // was the category_identifier input disabled?
2834
-        if ($category_identifier) {
2835
-            $term_args['slug'] = $category_identifier;
2836
-        }
2837
-        $insert_ids = $update
2838
-            ? wp_update_term($category_ID, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY, $term_args)
2839
-            : wp_insert_term($category_name, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY, $term_args);
2840
-        if (! is_array($insert_ids)) {
2841
-            $msg = esc_html__(
2842
-                'An error occurred and the category has not been saved to the database.',
2843
-                'event_espresso'
2844
-            );
2845
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2846
-        } else {
2847
-            $category_ID = $insert_ids['term_id'];
2848
-            $msg         = sprintf(
2849
-                esc_html__('The category %s was successfully saved', 'event_espresso'),
2850
-                $category_name
2851
-            );
2852
-            EE_Error::add_success($msg);
2853
-        }
2854
-        return $category_ID;
2855
-    }
2856
-
2857
-
2858
-    /**
2859
-     * Gets categories or count of categories matching the arguments in the request.
2860
-     *
2861
-     * @param int  $per_page
2862
-     * @param int  $current_page
2863
-     * @param bool $count
2864
-     * @return EE_Term_Taxonomy[]|int
2865
-     * @throws EE_Error
2866
-     */
2867
-    public function get_categories($per_page = 10, $current_page = 1, $count = false)
2868
-    {
2869
-        // testing term stuff
2870
-        $orderby     = $this->request->getRequestParam('orderby', 'Term.term_id');
2871
-        $order       = $this->request->getRequestParam('order', 'DESC');
2872
-        $limit       = ($current_page - 1) * $per_page;
2873
-        $where       = ['taxonomy' => EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY];
2874
-        $search_term = $this->request->getRequestParam('s');
2875
-        if ($search_term) {
2876
-            $search_term = '%' . $search_term . '%';
2877
-            $where['OR'] = [
2878
-                'Term.name'   => ['LIKE', $search_term],
2879
-                'description' => ['LIKE', $search_term],
2880
-            ];
2881
-        }
2882
-        $query_params = [
2883
-            $where,
2884
-            'order_by'   => [$orderby => $order],
2885
-            'limit'      => $limit . ',' . $per_page,
2886
-            'force_join' => ['Term'],
2887
-        ];
2888
-        return $count
2889
-            ? EEM_Term_Taxonomy::instance()->count($query_params, 'term_id')
2890
-            : EEM_Term_Taxonomy::instance()->get_all($query_params);
2891
-    }
2892
-
2893
-    /* end category stuff */
2894
-
2895
-
2896
-    /**************/
2897
-
2898
-
2899
-    /**
2900
-     * Callback for the `ee_save_timezone_setting` ajax action.
2901
-     *
2902
-     * @throws EE_Error
2903
-     * @throws InvalidArgumentException
2904
-     * @throws InvalidDataTypeException
2905
-     * @throws InvalidInterfaceException
2906
-     */
2907
-    public function saveTimezoneString()
2908
-    {
2909
-        $timezone_string = $this->request->getRequestParam('timezone_selected');
2910
-        if (empty($timezone_string) || ! EEH_DTT_Helper::validate_timezone($timezone_string, false)) {
2911
-            EE_Error::add_error(
2912
-                esc_html__('An invalid timezone string submitted.', 'event_espresso'),
2913
-                __FILE__,
2914
-                __FUNCTION__,
2915
-                __LINE__
2916
-            );
2917
-            $this->_template_args['error'] = true;
2918
-            $this->_return_json();
2919
-        }
2920
-
2921
-        update_option('timezone_string', $timezone_string);
2922
-        EE_Error::add_success(
2923
-            esc_html__('Your timezone string was updated.', 'event_espresso')
2924
-        );
2925
-        $this->_template_args['success'] = true;
2926
-        $this->_return_json(true, ['action' => 'create_new']);
2927
-    }
2928
-
2929
-
2930
-    /**
2931 2598
      * @throws EE_Error
2932
-     * @deprecated 4.10.25.p
2933 2599
      */
2934
-    public function save_timezonestring_setting()
2935
-    {
2936
-        $this->saveTimezoneString();
2937
-    }
2600
+	protected function _template_settings()
2601
+	{
2602
+		$this->_admin_page_title              = esc_html__('Template Settings (Preview)', 'event_espresso');
2603
+		$this->_template_args['preview_img']  = '<img src="'
2604
+												. EVENTS_ASSETS_URL
2605
+												. '/images/'
2606
+												. 'caffeinated_template_features.jpg" alt="'
2607
+												. esc_attr__('Template Settings Preview screenshot', 'event_espresso')
2608
+												. '" />';
2609
+		$this->_template_args['preview_text'] = '<strong>'
2610
+												. esc_html__(
2611
+													'Template Settings is a feature that is only available in the premium version of Event Espresso 4 which is available with a support license purchase on EventEspresso.com. Template Settings allow you to configure some of the appearance options for both the Event List and Event Details pages.',
2612
+													'event_espresso'
2613
+												) . '</strong>';
2614
+		$this->display_admin_caf_preview_page('template_settings_tab');
2615
+	}
2616
+
2617
+
2618
+	/** Event Category Stuff **/
2619
+	/**
2620
+	 * set the _category property with the category object for the loaded page.
2621
+	 *
2622
+	 * @access private
2623
+	 * @return void
2624
+	 */
2625
+	private function _set_category_object()
2626
+	{
2627
+		if (isset($this->_category->id) && ! empty($this->_category->id)) {
2628
+			return;
2629
+		} //already have the category object so get out.
2630
+		// set default category object
2631
+		$this->_set_empty_category_object();
2632
+		// only set if we've got an id
2633
+		$category_ID = $this->request->getRequestParam('EVT_CAT_ID', 0, 'int');
2634
+		if (! $category_ID) {
2635
+			return;
2636
+		}
2637
+		$term = get_term($category_ID, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY);
2638
+		if (! empty($term)) {
2639
+			$this->_category->category_name       = $term->name;
2640
+			$this->_category->category_identifier = $term->slug;
2641
+			$this->_category->category_desc       = $term->description;
2642
+			$this->_category->id                  = $term->term_id;
2643
+			$this->_category->parent              = $term->parent;
2644
+		}
2645
+	}
2646
+
2647
+
2648
+	/**
2649
+	 * Clears out category properties.
2650
+	 */
2651
+	private function _set_empty_category_object()
2652
+	{
2653
+		$this->_category                = new stdClass();
2654
+		$this->_category->category_name = $this->_category->category_identifier = $this->_category->category_desc = '';
2655
+		$this->_category->id            = $this->_category->parent = 0;
2656
+	}
2657
+
2658
+
2659
+	/**
2660
+	 * @throws DomainException
2661
+	 * @throws EE_Error
2662
+	 * @throws InvalidArgumentException
2663
+	 * @throws InvalidDataTypeException
2664
+	 * @throws InvalidInterfaceException
2665
+	 */
2666
+	protected function _category_list_table()
2667
+	{
2668
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2669
+		$this->_search_btn_label = esc_html__('Categories', 'event_espresso');
2670
+		$this->_admin_page_title .= ' ';
2671
+		$this->_admin_page_title .= $this->get_action_link_or_button(
2672
+			'add_category',
2673
+			'add_category',
2674
+			[],
2675
+			'add-new-h2'
2676
+		);
2677
+		$this->display_admin_list_table_page_with_sidebar();
2678
+	}
2679
+
2680
+
2681
+	/**
2682
+	 * Output category details view.
2683
+	 *
2684
+	 * @throws EE_Error
2685
+	 * @throws EE_Error
2686
+	 */
2687
+	protected function _category_details($view)
2688
+	{
2689
+		// load formatter helper
2690
+		// load field generator helper
2691
+		$route = $view === 'edit' ? 'update_category' : 'insert_category';
2692
+		$this->_set_add_edit_form_tags($route);
2693
+		$this->_set_category_object();
2694
+		$id            = ! empty($this->_category->id) ? $this->_category->id : '';
2695
+		$delete_action = 'delete_category';
2696
+		// custom redirect
2697
+		$redirect = EE_Admin_Page::add_query_args_and_nonce(
2698
+			['action' => 'category_list'],
2699
+			$this->_admin_base_url
2700
+		);
2701
+		$this->_set_publish_post_box_vars('EVT_CAT_ID', $id, $delete_action, $redirect);
2702
+		// take care of contents
2703
+		$this->_template_args['admin_page_content'] = $this->_category_details_content();
2704
+		$this->display_admin_page_with_sidebar();
2705
+	}
2706
+
2707
+
2708
+	/**
2709
+	 * Output category details content.
2710
+	 *
2711
+	 * @throws DomainException
2712
+	 */
2713
+	protected function _category_details_content()
2714
+	{
2715
+		$editor_args['category_desc'] = [
2716
+			'type'          => 'wp_editor',
2717
+			'value'         => EEH_Formatter::admin_format_content($this->_category->category_desc),
2718
+			'class'         => 'my_editor_custom',
2719
+			'wpeditor_args' => ['media_buttons' => false],
2720
+		];
2721
+		$_wp_editor                   = $this->_generate_admin_form_fields($editor_args, 'array');
2722
+		$all_terms                    = get_terms(
2723
+			[EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY],
2724
+			['hide_empty' => 0, 'exclude' => [$this->_category->id]]
2725
+		);
2726
+		// setup category select for term parents.
2727
+		$category_select_values[] = [
2728
+			'text' => esc_html__('No Parent', 'event_espresso'),
2729
+			'id'   => 0,
2730
+		];
2731
+		foreach ($all_terms as $term) {
2732
+			$category_select_values[] = [
2733
+				'text' => $term->name,
2734
+				'id'   => $term->term_id,
2735
+			];
2736
+		}
2737
+		$category_select = EEH_Form_Fields::select_input(
2738
+			'category_parent',
2739
+			$category_select_values,
2740
+			$this->_category->parent
2741
+		);
2742
+		$template_args   = [
2743
+			'category'                 => $this->_category,
2744
+			'category_select'          => $category_select,
2745
+			'unique_id_info_help_link' => $this->_get_help_tab_link('unique_id_info'),
2746
+			'category_desc_editor'     => $_wp_editor['category_desc']['field'],
2747
+			'disable'                  => '',
2748
+			'disabled_message'         => false,
2749
+		];
2750
+		$template        = EVENTS_TEMPLATE_PATH . 'event_category_details.template.php';
2751
+		return EEH_Template::display_template($template, $template_args, true);
2752
+	}
2753
+
2754
+
2755
+	/**
2756
+	 * Handles deleting categories.
2757
+	 *
2758
+	 * @throws EE_Error
2759
+	 */
2760
+	protected function _delete_categories()
2761
+	{
2762
+		$category_IDs = $this->request->getRequestParam('EVT_CAT_ID', 0, 'int', true);
2763
+		foreach ($category_IDs as $category_ID) {
2764
+			$this->_delete_category($category_ID);
2765
+		}
2766
+		// doesn't matter what page we're coming from... we're going to the same place after delete.
2767
+		$query_args = [
2768
+			'action' => 'category_list',
2769
+		];
2770
+		$this->_redirect_after_action(0, '', '', $query_args);
2771
+	}
2772
+
2773
+
2774
+	/**
2775
+	 * Handles deleting specific category.
2776
+	 *
2777
+	 * @param int $cat_id
2778
+	 */
2779
+	protected function _delete_category($cat_id)
2780
+	{
2781
+		$cat_id = absint($cat_id);
2782
+		wp_delete_term($cat_id, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY);
2783
+	}
2784
+
2785
+
2786
+	/**
2787
+	 * Handles triggering the update or insertion of a new category.
2788
+	 *
2789
+	 * @param bool $new_category true means we're triggering the insert of a new category.
2790
+	 * @throws EE_Error
2791
+	 * @throws EE_Error
2792
+	 */
2793
+	protected function _insert_or_update_category($new_category)
2794
+	{
2795
+		$cat_id  = $new_category ? $this->_insert_category() : $this->_insert_category(true);
2796
+		$success = 0; // we already have a success message so lets not send another.
2797
+		if ($cat_id) {
2798
+			$query_args = [
2799
+				'action'     => 'edit_category',
2800
+				'EVT_CAT_ID' => $cat_id,
2801
+			];
2802
+		} else {
2803
+			$query_args = ['action' => 'add_category'];
2804
+		}
2805
+		$this->_redirect_after_action($success, '', '', $query_args, true);
2806
+	}
2807
+
2808
+
2809
+	/**
2810
+	 * Inserts or updates category
2811
+	 *
2812
+	 * @param bool $update (true indicates we're updating a category).
2813
+	 * @return bool|mixed|string
2814
+	 */
2815
+	private function _insert_category($update = false)
2816
+	{
2817
+		$category_ID         = $update ? $this->request->getRequestParam('EVT_CAT_ID', 0, 'int') : 0;
2818
+		$category_name       = $this->request->getRequestParam('category_name', '');
2819
+		$category_desc       = $this->request->getRequestParam('category_desc', '');
2820
+		$category_parent     = $this->request->getRequestParam('category_parent', 0, 'int');
2821
+		$category_identifier = $this->request->getRequestParam('category_identifier', '');
2822
+
2823
+		if (empty($category_name)) {
2824
+			$msg = esc_html__('You must add a name for the category.', 'event_espresso');
2825
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2826
+			return false;
2827
+		}
2828
+		$term_args = [
2829
+			'name'        => $category_name,
2830
+			'description' => $category_desc,
2831
+			'parent'      => $category_parent,
2832
+		];
2833
+		// was the category_identifier input disabled?
2834
+		if ($category_identifier) {
2835
+			$term_args['slug'] = $category_identifier;
2836
+		}
2837
+		$insert_ids = $update
2838
+			? wp_update_term($category_ID, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY, $term_args)
2839
+			: wp_insert_term($category_name, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY, $term_args);
2840
+		if (! is_array($insert_ids)) {
2841
+			$msg = esc_html__(
2842
+				'An error occurred and the category has not been saved to the database.',
2843
+				'event_espresso'
2844
+			);
2845
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2846
+		} else {
2847
+			$category_ID = $insert_ids['term_id'];
2848
+			$msg         = sprintf(
2849
+				esc_html__('The category %s was successfully saved', 'event_espresso'),
2850
+				$category_name
2851
+			);
2852
+			EE_Error::add_success($msg);
2853
+		}
2854
+		return $category_ID;
2855
+	}
2856
+
2857
+
2858
+	/**
2859
+	 * Gets categories or count of categories matching the arguments in the request.
2860
+	 *
2861
+	 * @param int  $per_page
2862
+	 * @param int  $current_page
2863
+	 * @param bool $count
2864
+	 * @return EE_Term_Taxonomy[]|int
2865
+	 * @throws EE_Error
2866
+	 */
2867
+	public function get_categories($per_page = 10, $current_page = 1, $count = false)
2868
+	{
2869
+		// testing term stuff
2870
+		$orderby     = $this->request->getRequestParam('orderby', 'Term.term_id');
2871
+		$order       = $this->request->getRequestParam('order', 'DESC');
2872
+		$limit       = ($current_page - 1) * $per_page;
2873
+		$where       = ['taxonomy' => EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY];
2874
+		$search_term = $this->request->getRequestParam('s');
2875
+		if ($search_term) {
2876
+			$search_term = '%' . $search_term . '%';
2877
+			$where['OR'] = [
2878
+				'Term.name'   => ['LIKE', $search_term],
2879
+				'description' => ['LIKE', $search_term],
2880
+			];
2881
+		}
2882
+		$query_params = [
2883
+			$where,
2884
+			'order_by'   => [$orderby => $order],
2885
+			'limit'      => $limit . ',' . $per_page,
2886
+			'force_join' => ['Term'],
2887
+		];
2888
+		return $count
2889
+			? EEM_Term_Taxonomy::instance()->count($query_params, 'term_id')
2890
+			: EEM_Term_Taxonomy::instance()->get_all($query_params);
2891
+	}
2892
+
2893
+	/* end category stuff */
2894
+
2895
+
2896
+	/**************/
2897
+
2898
+
2899
+	/**
2900
+	 * Callback for the `ee_save_timezone_setting` ajax action.
2901
+	 *
2902
+	 * @throws EE_Error
2903
+	 * @throws InvalidArgumentException
2904
+	 * @throws InvalidDataTypeException
2905
+	 * @throws InvalidInterfaceException
2906
+	 */
2907
+	public function saveTimezoneString()
2908
+	{
2909
+		$timezone_string = $this->request->getRequestParam('timezone_selected');
2910
+		if (empty($timezone_string) || ! EEH_DTT_Helper::validate_timezone($timezone_string, false)) {
2911
+			EE_Error::add_error(
2912
+				esc_html__('An invalid timezone string submitted.', 'event_espresso'),
2913
+				__FILE__,
2914
+				__FUNCTION__,
2915
+				__LINE__
2916
+			);
2917
+			$this->_template_args['error'] = true;
2918
+			$this->_return_json();
2919
+		}
2920
+
2921
+		update_option('timezone_string', $timezone_string);
2922
+		EE_Error::add_success(
2923
+			esc_html__('Your timezone string was updated.', 'event_espresso')
2924
+		);
2925
+		$this->_template_args['success'] = true;
2926
+		$this->_return_json(true, ['action' => 'create_new']);
2927
+	}
2928
+
2929
+
2930
+	/**
2931
+	 * @throws EE_Error
2932
+	 * @deprecated 4.10.25.p
2933
+	 */
2934
+	public function save_timezonestring_setting()
2935
+	{
2936
+		$this->saveTimezoneString();
2937
+	}
2938 2938
 }
Please login to merge, or discard this patch.