Completed
Branch more-edtr-ui-fixes (51588f)
by
unknown
15:10 queued 07:43
created
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.
caffeinated/admin/extend/events/Extend_Events_Admin_Page.core.php 1 patch
Indentation   +1358 added lines, -1358 removed lines patch added patch discarded remove patch
@@ -14,1368 +14,1368 @@
 block discarded – undo
14 14
  */
15 15
 class Extend_Events_Admin_Page extends Events_Admin_Page
16 16
 {
17
-    /**
18
-     * @var EE_Admin_Config
19
-     */
20
-    protected $admin_config;
21
-
22
-
23
-    /**
24
-     * Extend_Events_Admin_Page constructor.
25
-     *
26
-     * @param bool $routing
27
-     * @throws EE_Error
28
-     * @throws ReflectionException
29
-     */
30
-    public function __construct($routing = true)
31
-    {
32
-        if (! defined('EVENTS_CAF_TEMPLATE_PATH')) {
33
-            define('EVENTS_CAF_TEMPLATE_PATH', EE_CORE_CAF_ADMIN_EXTEND . 'events/templates/');
34
-            define('EVENTS_CAF_ASSETS', EE_CORE_CAF_ADMIN_EXTEND . 'events/assets/');
35
-            define('EVENTS_CAF_ASSETS_URL', EE_CORE_CAF_ADMIN_EXTEND_URL . 'events/assets/');
36
-        }
37
-        parent::__construct($routing);
38
-        $this->admin_config = $this->loader->getShared('EE_Admin_Config');
39
-    }
40
-
41
-
42
-    /**
43
-     * Sets routes.
44
-     *
45
-     * @throws EE_Error
46
-     */
47
-    protected function _extend_page_config()
48
-    {
49
-        $this->_admin_base_path = EE_CORE_CAF_ADMIN_EXTEND . 'events';
50
-        // is there a evt_id in the request?
51
-        $EVT_ID             = $this->request->getRequestParam('EVT_ID', 0, 'int');
52
-        $EVT_ID             = $this->request->getRequestParam('post', $EVT_ID, 'int');
53
-        $TKT_ID             = $this->request->getRequestParam('TKT_ID', 0, 'int');
54
-        $new_page_routes    = [
55
-            'duplicate_event'          => [
56
-                'func'       => '_duplicate_event',
57
-                'capability' => 'ee_edit_event',
58
-                'obj_id'     => $EVT_ID,
59
-                'noheader'   => true,
60
-            ],
61
-            'import_page'              => [
62
-                'func'       => '_import_page',
63
-                'capability' => 'import',
64
-            ],
65
-            'import'                   => [
66
-                'func'       => '_import_events',
67
-                'capability' => 'import',
68
-                'noheader'   => true,
69
-            ],
70
-            'import_events'            => [
71
-                'func'       => '_import_events',
72
-                'capability' => 'import',
73
-                'noheader'   => true,
74
-            ],
75
-            'export_events'            => [
76
-                'func'       => '_events_export',
77
-                'capability' => 'export',
78
-                'noheader'   => true,
79
-            ],
80
-            'export_categories'        => [
81
-                'func'       => '_categories_export',
82
-                'capability' => 'export',
83
-                'noheader'   => true,
84
-            ],
85
-            'sample_export_file'       => [
86
-                'func'       => '_sample_export_file',
87
-                'capability' => 'export',
88
-                'noheader'   => true,
89
-            ],
90
-            'update_template_settings' => [
91
-                'func'       => '_update_template_settings',
92
-                'capability' => 'manage_options',
93
-                'noheader'   => true,
94
-            ],
95
-            'ticket_list_table'        => [
96
-                'func'       => '_tickets_overview_list_table',
97
-                'capability' => 'ee_read_default_tickets',
98
-            ],
99
-        ];
100
-        $this->_page_config['create_new']['metaboxes'][] = '_premium_event_editor_meta_boxes';
101
-        $this->_page_config['edit']['metaboxes'][]       = '_premium_event_editor_meta_boxes';
102
-        // don't load these meta boxes if using the advanced editor
103
-        if (
104
-            ! $this->admin_config->useAdvancedEditor()
105
-            || ! $this->feature->allowed('use_default_ticket_manager')
106
-        ) {
107
-            $this->_page_config['create_new']['qtips'][] = 'EE_Event_Editor_Tips';
108
-            $this->_page_config['edit']['qtips'][]       = 'EE_Event_Editor_Tips';
109
-
110
-            $legacy_editor_page_routes = [
111
-                'trash_ticket'    => [
112
-                    'func'       => '_trash_or_restore_ticket',
113
-                    'capability' => 'ee_delete_default_ticket',
114
-                    'obj_id'     => $TKT_ID,
115
-                    'noheader'   => true,
116
-                    'args'       => ['trash' => true],
117
-                ],
118
-                'trash_tickets'   => [
119
-                    'func'       => '_trash_or_restore_ticket',
120
-                    'capability' => 'ee_delete_default_tickets',
121
-                    'noheader'   => true,
122
-                    'args'       => ['trash' => true],
123
-                ],
124
-                'restore_ticket'  => [
125
-                    'func'       => '_trash_or_restore_ticket',
126
-                    'capability' => 'ee_delete_default_ticket',
127
-                    'obj_id'     => $TKT_ID,
128
-                    'noheader'   => true,
129
-                ],
130
-                'restore_tickets' => [
131
-                    'func'       => '_trash_or_restore_ticket',
132
-                    'capability' => 'ee_delete_default_tickets',
133
-                    'noheader'   => true,
134
-                ],
135
-                'delete_ticket'   => [
136
-                    'func'       => '_delete_ticket',
137
-                    'capability' => 'ee_delete_default_ticket',
138
-                    'obj_id'     => $TKT_ID,
139
-                    'noheader'   => true,
140
-                ],
141
-                'delete_tickets'  => [
142
-                    'func'       => '_delete_ticket',
143
-                    'capability' => 'ee_delete_default_tickets',
144
-                    'noheader'   => true,
145
-                ],
146
-            ];
147
-            $new_page_routes           = array_merge($new_page_routes, $legacy_editor_page_routes);
148
-        }
149
-
150
-        $this->_page_routes = array_merge($this->_page_routes, $new_page_routes);
151
-        // partial route/config override
152
-        $this->_page_config['import_events']['metaboxes'] = $this->_default_espresso_metaboxes;
153
-        $this->_page_config['default']['list_table']      = 'Extend_Events_Admin_List_Table';
154
-        // add tickets tab but only if there are more than one default ticket!
155
-        $ticket_count = EEM_Ticket::instance()->count_deleted_and_undeleted(
156
-            [['TKT_is_default' => 1]],
157
-            'TKT_ID',
158
-            true
159
-        );
160
-        if ($ticket_count > 1) {
161
-            $new_page_config = [
162
-                'ticket_list_table' => [
163
-                    'nav'           => [
164
-                        'label' => esc_html__('Default Tickets', 'event_espresso'),
165
-                        'icon'  => 'dashicons-tickets-alt',
166
-                        'order' => 60,
167
-                    ],
168
-                    'list_table'    => 'Tickets_List_Table',
169
-                    'require_nonce' => false,
170
-                ],
171
-            ];
172
-        }
173
-        // template settings
174
-        $new_page_config['template_settings'] = [
175
-            'nav'           => [
176
-                'label' => esc_html__('Templates', 'event_espresso'),
177
-                'icon' => 'dashicons-layout',
178
-                'order' => 30,
179
-            ],
180
-            'metaboxes'     => array_merge(['_publish_post_box'], $this->_default_espresso_metaboxes),
181
-            'help_tabs'     => [
182
-                'general_settings_templates_help_tab' => [
183
-                    'title'    => esc_html__('Templates', 'event_espresso'),
184
-                    'filename' => 'general_settings_templates',
185
-                ],
186
-            ],
187
-            'require_nonce' => false,
188
-        ];
189
-        $this->_page_config                   = array_merge($this->_page_config, $new_page_config);
190
-        // add filters and actions
191
-        // modifying _views
192
-        add_filter(
193
-            'FHEE_event_datetime_metabox_add_additional_date_time_template',
194
-            [$this, 'add_additional_datetime_button'],
195
-            10,
196
-            2
197
-        );
198
-        add_filter(
199
-            'FHEE_event_datetime_metabox_clone_button_template',
200
-            [$this, 'add_datetime_clone_button'],
201
-            10,
202
-            2
203
-        );
204
-        add_filter(
205
-            'FHEE_event_datetime_metabox_timezones_template',
206
-            [$this, 'datetime_timezones_template'],
207
-            10,
208
-            2
209
-        );
210
-        // filters for event list table
211
-        add_filter('FHEE__Extend_Events_Admin_List_Table__filters', [$this, 'list_table_filters'], 10, 2);
212
-        add_filter(
213
-            'FHEE__Events_Admin_List_Table__column_actions__action_links',
214
-            [$this, 'extra_list_table_actions'],
215
-            10,
216
-            2
217
-        );
218
-        // legend item
219
-        add_filter('FHEE__Events_Admin_Page___event_legend_items__items', [$this, 'additional_legend_items']);
220
-        add_action('admin_init', [$this, 'admin_init']);
221
-    }
222
-
223
-
224
-    /**
225
-     * admin_init
226
-     */
227
-    public function admin_init()
228
-    {
229
-        EE_Registry::$i18n_js_strings = array_merge(
230
-            EE_Registry::$i18n_js_strings,
231
-            [
232
-                'image_confirm'          => esc_html__(
233
-                    'Do you really want to delete this image? Please remember to update your event to complete the removal.',
234
-                    'event_espresso'
235
-                ),
236
-                'event_starts_on'        => esc_html__('Event Starts on', 'event_espresso'),
237
-                'event_ends_on'          => esc_html__('Event Ends on', 'event_espresso'),
238
-                'event_datetime_actions' => esc_html__('Actions', 'event_espresso'),
239
-                'event_clone_dt_msg'     => esc_html__('Clone this Event Date and Time', 'event_espresso'),
240
-                'remove_event_dt_msg'    => esc_html__('Remove this Event Time', 'event_espresso'),
241
-            ]
242
-        );
243
-    }
244
-
245
-
246
-    /**
247
-     * Add per page screen options to the default ticket list table view.
248
-     *
249
-     * @throws InvalidArgumentException
250
-     * @throws InvalidDataTypeException
251
-     * @throws InvalidInterfaceException
252
-     */
253
-    protected function _add_screen_options_ticket_list_table()
254
-    {
255
-        $this->_per_page_screen_option();
256
-    }
257
-
258
-
259
-    /**
260
-     * @param string $return
261
-     * @param int    $id
262
-     * @param string $new_title
263
-     * @param string $new_slug
264
-     * @return string
265
-     */
266
-    public function extra_permalink_field_buttons($return, $id, $new_title, $new_slug)
267
-    {
268
-        $return = parent::extra_permalink_field_buttons($return, $id, $new_title, $new_slug);
269
-        // make sure this is only when editing
270
-        if (! empty($id)) {
271
-            $href   = EE_Admin_Page::add_query_args_and_nonce(
272
-                ['action' => 'duplicate_event', 'EVT_ID' => $id],
273
-                $this->_admin_base_url
274
-            );
275
-            $title  = esc_attr__('Duplicate Event', 'event_espresso');
276
-            $return .= '<a href="'
277
-                       . $href
278
-                       . '" title="'
279
-                       . $title
280
-                       . '" id="ee-duplicate-event-button" class="button button--small button--secondary"  value="duplicate_event">'
281
-                       . $title
282
-                       . '</a>';
283
-        }
284
-        return $return;
285
-    }
286
-
287
-
288
-    /**
289
-     * Set the list table views for the default ticket list table view.
290
-     */
291
-    public function _set_list_table_views_ticket_list_table()
292
-    {
293
-        $this->_views = [
294
-            'all'     => [
295
-                'slug'        => 'all',
296
-                'label'       => esc_html__('All', 'event_espresso'),
297
-                'count'       => 0,
298
-                'bulk_action' => [
299
-                    'trash_tickets' => esc_html__('Move to Trash', 'event_espresso'),
300
-                ],
301
-            ],
302
-            'trashed' => [
303
-                'slug'        => 'trashed',
304
-                'label'       => esc_html__('Trash', 'event_espresso'),
305
-                'count'       => 0,
306
-                'bulk_action' => [
307
-                    'restore_tickets' => esc_html__('Restore from Trash', 'event_espresso'),
308
-                    'delete_tickets'  => esc_html__('Delete Permanently', 'event_espresso'),
309
-                ],
310
-            ],
311
-        ];
312
-    }
313
-
314
-
315
-    /**
316
-     * Enqueue scripts and styles for the event editor.
317
-     */
318
-    public function load_scripts_styles_edit()
319
-    {
320
-        if (! $this->admin_config->useAdvancedEditor()) {
321
-            wp_register_script(
322
-                'ee-event-editor-heartbeat',
323
-                EVENTS_CAF_ASSETS_URL . 'event-editor-heartbeat.js',
324
-                ['ee_admin_js', 'heartbeat'],
325
-                EVENT_ESPRESSO_VERSION,
326
-                true
327
-            );
328
-            wp_enqueue_script('ee-accounting');
329
-            wp_enqueue_script('ee-event-editor-heartbeat');
330
-        }
331
-        wp_enqueue_script('event_editor_js');
332
-        // styles
333
-        wp_enqueue_style('espresso-ui-theme');
334
-    }
335
-
336
-
337
-    /**
338
-     * Returns template for the additional datetime.
339
-     *
340
-     * @param string $template
341
-     * @param array  $template_args
342
-     * @return string
343
-     * @throws DomainException
344
-     */
345
-    public function add_additional_datetime_button($template, $template_args)
346
-    {
347
-        return EEH_Template::display_template(
348
-            EVENTS_CAF_TEMPLATE_PATH . 'event_datetime_add_additional_time.template.php',
349
-            $template_args,
350
-            true
351
-        );
352
-    }
353
-
354
-
355
-    /**
356
-     * Returns the template for cloning a datetime.
357
-     *
358
-     * @param $template
359
-     * @param $template_args
360
-     * @return string
361
-     * @throws DomainException
362
-     */
363
-    public function add_datetime_clone_button($template, $template_args)
364
-    {
365
-        return EEH_Template::display_template(
366
-            EVENTS_CAF_TEMPLATE_PATH . 'event_datetime_metabox_clone_button.template.php',
367
-            $template_args,
368
-            true
369
-        );
370
-    }
371
-
372
-
373
-    /**
374
-     * Returns the template for datetime timezones.
375
-     *
376
-     * @param $template
377
-     * @param $template_args
378
-     * @return string
379
-     * @throws DomainException
380
-     */
381
-    public function datetime_timezones_template($template, $template_args)
382
-    {
383
-        return EEH_Template::display_template(
384
-            EVENTS_CAF_TEMPLATE_PATH . 'event_datetime_timezones.template.php',
385
-            $template_args,
386
-            true
387
-        );
388
-    }
389
-
390
-
391
-    /**
392
-     * Sets the views for the default list table view.
393
-     *
394
-     * @throws EE_Error
395
-     */
396
-    protected function _set_list_table_views_default()
397
-    {
398
-        parent::_set_list_table_views_default();
399
-        $new_views    = [
400
-            'today' => [
401
-                'slug'        => 'today',
402
-                'label'       => esc_html__('Today', 'event_espresso'),
403
-                'count'       => $this->total_events_today(),
404
-                'bulk_action' => [
405
-                    'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
406
-                ],
407
-            ],
408
-            'month' => [
409
-                'slug'        => 'month',
410
-                'label'       => esc_html__('This Month', 'event_espresso'),
411
-                'count'       => $this->total_events_this_month(),
412
-                'bulk_action' => [
413
-                    'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
414
-                ],
415
-            ],
416
-        ];
417
-        $this->_views = array_merge($this->_views, $new_views);
418
-    }
419
-
420
-
421
-    /**
422
-     * Returns the extra action links for the default list table view.
423
-     *
424
-     * @param array    $action_links
425
-     * @param EE_Event $event
426
-     * @return array
427
-     * @throws EE_Error
428
-     * @throws ReflectionException
429
-     */
430
-    public function extra_list_table_actions(array $action_links, EE_Event $event)
431
-    {
432
-        if (
433
-            EE_Registry::instance()->CAP->current_user_can(
434
-                'ee_read_registrations',
435
-                'espresso_registrations_reports',
436
-                $event->ID()
437
-            )
438
-        ) {
439
-            $reports_link = EE_Admin_Page::add_query_args_and_nonce(
440
-                [
441
-                    'action' => 'reports',
442
-                    'EVT_ID' => $event->ID(),
443
-                ],
444
-                REG_ADMIN_URL
445
-            );
446
-
447
-            $action_links[]     = '
17
+	/**
18
+	 * @var EE_Admin_Config
19
+	 */
20
+	protected $admin_config;
21
+
22
+
23
+	/**
24
+	 * Extend_Events_Admin_Page constructor.
25
+	 *
26
+	 * @param bool $routing
27
+	 * @throws EE_Error
28
+	 * @throws ReflectionException
29
+	 */
30
+	public function __construct($routing = true)
31
+	{
32
+		if (! defined('EVENTS_CAF_TEMPLATE_PATH')) {
33
+			define('EVENTS_CAF_TEMPLATE_PATH', EE_CORE_CAF_ADMIN_EXTEND . 'events/templates/');
34
+			define('EVENTS_CAF_ASSETS', EE_CORE_CAF_ADMIN_EXTEND . 'events/assets/');
35
+			define('EVENTS_CAF_ASSETS_URL', EE_CORE_CAF_ADMIN_EXTEND_URL . 'events/assets/');
36
+		}
37
+		parent::__construct($routing);
38
+		$this->admin_config = $this->loader->getShared('EE_Admin_Config');
39
+	}
40
+
41
+
42
+	/**
43
+	 * Sets routes.
44
+	 *
45
+	 * @throws EE_Error
46
+	 */
47
+	protected function _extend_page_config()
48
+	{
49
+		$this->_admin_base_path = EE_CORE_CAF_ADMIN_EXTEND . 'events';
50
+		// is there a evt_id in the request?
51
+		$EVT_ID             = $this->request->getRequestParam('EVT_ID', 0, 'int');
52
+		$EVT_ID             = $this->request->getRequestParam('post', $EVT_ID, 'int');
53
+		$TKT_ID             = $this->request->getRequestParam('TKT_ID', 0, 'int');
54
+		$new_page_routes    = [
55
+			'duplicate_event'          => [
56
+				'func'       => '_duplicate_event',
57
+				'capability' => 'ee_edit_event',
58
+				'obj_id'     => $EVT_ID,
59
+				'noheader'   => true,
60
+			],
61
+			'import_page'              => [
62
+				'func'       => '_import_page',
63
+				'capability' => 'import',
64
+			],
65
+			'import'                   => [
66
+				'func'       => '_import_events',
67
+				'capability' => 'import',
68
+				'noheader'   => true,
69
+			],
70
+			'import_events'            => [
71
+				'func'       => '_import_events',
72
+				'capability' => 'import',
73
+				'noheader'   => true,
74
+			],
75
+			'export_events'            => [
76
+				'func'       => '_events_export',
77
+				'capability' => 'export',
78
+				'noheader'   => true,
79
+			],
80
+			'export_categories'        => [
81
+				'func'       => '_categories_export',
82
+				'capability' => 'export',
83
+				'noheader'   => true,
84
+			],
85
+			'sample_export_file'       => [
86
+				'func'       => '_sample_export_file',
87
+				'capability' => 'export',
88
+				'noheader'   => true,
89
+			],
90
+			'update_template_settings' => [
91
+				'func'       => '_update_template_settings',
92
+				'capability' => 'manage_options',
93
+				'noheader'   => true,
94
+			],
95
+			'ticket_list_table'        => [
96
+				'func'       => '_tickets_overview_list_table',
97
+				'capability' => 'ee_read_default_tickets',
98
+			],
99
+		];
100
+		$this->_page_config['create_new']['metaboxes'][] = '_premium_event_editor_meta_boxes';
101
+		$this->_page_config['edit']['metaboxes'][]       = '_premium_event_editor_meta_boxes';
102
+		// don't load these meta boxes if using the advanced editor
103
+		if (
104
+			! $this->admin_config->useAdvancedEditor()
105
+			|| ! $this->feature->allowed('use_default_ticket_manager')
106
+		) {
107
+			$this->_page_config['create_new']['qtips'][] = 'EE_Event_Editor_Tips';
108
+			$this->_page_config['edit']['qtips'][]       = 'EE_Event_Editor_Tips';
109
+
110
+			$legacy_editor_page_routes = [
111
+				'trash_ticket'    => [
112
+					'func'       => '_trash_or_restore_ticket',
113
+					'capability' => 'ee_delete_default_ticket',
114
+					'obj_id'     => $TKT_ID,
115
+					'noheader'   => true,
116
+					'args'       => ['trash' => true],
117
+				],
118
+				'trash_tickets'   => [
119
+					'func'       => '_trash_or_restore_ticket',
120
+					'capability' => 'ee_delete_default_tickets',
121
+					'noheader'   => true,
122
+					'args'       => ['trash' => true],
123
+				],
124
+				'restore_ticket'  => [
125
+					'func'       => '_trash_or_restore_ticket',
126
+					'capability' => 'ee_delete_default_ticket',
127
+					'obj_id'     => $TKT_ID,
128
+					'noheader'   => true,
129
+				],
130
+				'restore_tickets' => [
131
+					'func'       => '_trash_or_restore_ticket',
132
+					'capability' => 'ee_delete_default_tickets',
133
+					'noheader'   => true,
134
+				],
135
+				'delete_ticket'   => [
136
+					'func'       => '_delete_ticket',
137
+					'capability' => 'ee_delete_default_ticket',
138
+					'obj_id'     => $TKT_ID,
139
+					'noheader'   => true,
140
+				],
141
+				'delete_tickets'  => [
142
+					'func'       => '_delete_ticket',
143
+					'capability' => 'ee_delete_default_tickets',
144
+					'noheader'   => true,
145
+				],
146
+			];
147
+			$new_page_routes           = array_merge($new_page_routes, $legacy_editor_page_routes);
148
+		}
149
+
150
+		$this->_page_routes = array_merge($this->_page_routes, $new_page_routes);
151
+		// partial route/config override
152
+		$this->_page_config['import_events']['metaboxes'] = $this->_default_espresso_metaboxes;
153
+		$this->_page_config['default']['list_table']      = 'Extend_Events_Admin_List_Table';
154
+		// add tickets tab but only if there are more than one default ticket!
155
+		$ticket_count = EEM_Ticket::instance()->count_deleted_and_undeleted(
156
+			[['TKT_is_default' => 1]],
157
+			'TKT_ID',
158
+			true
159
+		);
160
+		if ($ticket_count > 1) {
161
+			$new_page_config = [
162
+				'ticket_list_table' => [
163
+					'nav'           => [
164
+						'label' => esc_html__('Default Tickets', 'event_espresso'),
165
+						'icon'  => 'dashicons-tickets-alt',
166
+						'order' => 60,
167
+					],
168
+					'list_table'    => 'Tickets_List_Table',
169
+					'require_nonce' => false,
170
+				],
171
+			];
172
+		}
173
+		// template settings
174
+		$new_page_config['template_settings'] = [
175
+			'nav'           => [
176
+				'label' => esc_html__('Templates', 'event_espresso'),
177
+				'icon' => 'dashicons-layout',
178
+				'order' => 30,
179
+			],
180
+			'metaboxes'     => array_merge(['_publish_post_box'], $this->_default_espresso_metaboxes),
181
+			'help_tabs'     => [
182
+				'general_settings_templates_help_tab' => [
183
+					'title'    => esc_html__('Templates', 'event_espresso'),
184
+					'filename' => 'general_settings_templates',
185
+				],
186
+			],
187
+			'require_nonce' => false,
188
+		];
189
+		$this->_page_config                   = array_merge($this->_page_config, $new_page_config);
190
+		// add filters and actions
191
+		// modifying _views
192
+		add_filter(
193
+			'FHEE_event_datetime_metabox_add_additional_date_time_template',
194
+			[$this, 'add_additional_datetime_button'],
195
+			10,
196
+			2
197
+		);
198
+		add_filter(
199
+			'FHEE_event_datetime_metabox_clone_button_template',
200
+			[$this, 'add_datetime_clone_button'],
201
+			10,
202
+			2
203
+		);
204
+		add_filter(
205
+			'FHEE_event_datetime_metabox_timezones_template',
206
+			[$this, 'datetime_timezones_template'],
207
+			10,
208
+			2
209
+		);
210
+		// filters for event list table
211
+		add_filter('FHEE__Extend_Events_Admin_List_Table__filters', [$this, 'list_table_filters'], 10, 2);
212
+		add_filter(
213
+			'FHEE__Events_Admin_List_Table__column_actions__action_links',
214
+			[$this, 'extra_list_table_actions'],
215
+			10,
216
+			2
217
+		);
218
+		// legend item
219
+		add_filter('FHEE__Events_Admin_Page___event_legend_items__items', [$this, 'additional_legend_items']);
220
+		add_action('admin_init', [$this, 'admin_init']);
221
+	}
222
+
223
+
224
+	/**
225
+	 * admin_init
226
+	 */
227
+	public function admin_init()
228
+	{
229
+		EE_Registry::$i18n_js_strings = array_merge(
230
+			EE_Registry::$i18n_js_strings,
231
+			[
232
+				'image_confirm'          => esc_html__(
233
+					'Do you really want to delete this image? Please remember to update your event to complete the removal.',
234
+					'event_espresso'
235
+				),
236
+				'event_starts_on'        => esc_html__('Event Starts on', 'event_espresso'),
237
+				'event_ends_on'          => esc_html__('Event Ends on', 'event_espresso'),
238
+				'event_datetime_actions' => esc_html__('Actions', 'event_espresso'),
239
+				'event_clone_dt_msg'     => esc_html__('Clone this Event Date and Time', 'event_espresso'),
240
+				'remove_event_dt_msg'    => esc_html__('Remove this Event Time', 'event_espresso'),
241
+			]
242
+		);
243
+	}
244
+
245
+
246
+	/**
247
+	 * Add per page screen options to the default ticket list table view.
248
+	 *
249
+	 * @throws InvalidArgumentException
250
+	 * @throws InvalidDataTypeException
251
+	 * @throws InvalidInterfaceException
252
+	 */
253
+	protected function _add_screen_options_ticket_list_table()
254
+	{
255
+		$this->_per_page_screen_option();
256
+	}
257
+
258
+
259
+	/**
260
+	 * @param string $return
261
+	 * @param int    $id
262
+	 * @param string $new_title
263
+	 * @param string $new_slug
264
+	 * @return string
265
+	 */
266
+	public function extra_permalink_field_buttons($return, $id, $new_title, $new_slug)
267
+	{
268
+		$return = parent::extra_permalink_field_buttons($return, $id, $new_title, $new_slug);
269
+		// make sure this is only when editing
270
+		if (! empty($id)) {
271
+			$href   = EE_Admin_Page::add_query_args_and_nonce(
272
+				['action' => 'duplicate_event', 'EVT_ID' => $id],
273
+				$this->_admin_base_url
274
+			);
275
+			$title  = esc_attr__('Duplicate Event', 'event_espresso');
276
+			$return .= '<a href="'
277
+					   . $href
278
+					   . '" title="'
279
+					   . $title
280
+					   . '" id="ee-duplicate-event-button" class="button button--small button--secondary"  value="duplicate_event">'
281
+					   . $title
282
+					   . '</a>';
283
+		}
284
+		return $return;
285
+	}
286
+
287
+
288
+	/**
289
+	 * Set the list table views for the default ticket list table view.
290
+	 */
291
+	public function _set_list_table_views_ticket_list_table()
292
+	{
293
+		$this->_views = [
294
+			'all'     => [
295
+				'slug'        => 'all',
296
+				'label'       => esc_html__('All', 'event_espresso'),
297
+				'count'       => 0,
298
+				'bulk_action' => [
299
+					'trash_tickets' => esc_html__('Move to Trash', 'event_espresso'),
300
+				],
301
+			],
302
+			'trashed' => [
303
+				'slug'        => 'trashed',
304
+				'label'       => esc_html__('Trash', 'event_espresso'),
305
+				'count'       => 0,
306
+				'bulk_action' => [
307
+					'restore_tickets' => esc_html__('Restore from Trash', 'event_espresso'),
308
+					'delete_tickets'  => esc_html__('Delete Permanently', 'event_espresso'),
309
+				],
310
+			],
311
+		];
312
+	}
313
+
314
+
315
+	/**
316
+	 * Enqueue scripts and styles for the event editor.
317
+	 */
318
+	public function load_scripts_styles_edit()
319
+	{
320
+		if (! $this->admin_config->useAdvancedEditor()) {
321
+			wp_register_script(
322
+				'ee-event-editor-heartbeat',
323
+				EVENTS_CAF_ASSETS_URL . 'event-editor-heartbeat.js',
324
+				['ee_admin_js', 'heartbeat'],
325
+				EVENT_ESPRESSO_VERSION,
326
+				true
327
+			);
328
+			wp_enqueue_script('ee-accounting');
329
+			wp_enqueue_script('ee-event-editor-heartbeat');
330
+		}
331
+		wp_enqueue_script('event_editor_js');
332
+		// styles
333
+		wp_enqueue_style('espresso-ui-theme');
334
+	}
335
+
336
+
337
+	/**
338
+	 * Returns template for the additional datetime.
339
+	 *
340
+	 * @param string $template
341
+	 * @param array  $template_args
342
+	 * @return string
343
+	 * @throws DomainException
344
+	 */
345
+	public function add_additional_datetime_button($template, $template_args)
346
+	{
347
+		return EEH_Template::display_template(
348
+			EVENTS_CAF_TEMPLATE_PATH . 'event_datetime_add_additional_time.template.php',
349
+			$template_args,
350
+			true
351
+		);
352
+	}
353
+
354
+
355
+	/**
356
+	 * Returns the template for cloning a datetime.
357
+	 *
358
+	 * @param $template
359
+	 * @param $template_args
360
+	 * @return string
361
+	 * @throws DomainException
362
+	 */
363
+	public function add_datetime_clone_button($template, $template_args)
364
+	{
365
+		return EEH_Template::display_template(
366
+			EVENTS_CAF_TEMPLATE_PATH . 'event_datetime_metabox_clone_button.template.php',
367
+			$template_args,
368
+			true
369
+		);
370
+	}
371
+
372
+
373
+	/**
374
+	 * Returns the template for datetime timezones.
375
+	 *
376
+	 * @param $template
377
+	 * @param $template_args
378
+	 * @return string
379
+	 * @throws DomainException
380
+	 */
381
+	public function datetime_timezones_template($template, $template_args)
382
+	{
383
+		return EEH_Template::display_template(
384
+			EVENTS_CAF_TEMPLATE_PATH . 'event_datetime_timezones.template.php',
385
+			$template_args,
386
+			true
387
+		);
388
+	}
389
+
390
+
391
+	/**
392
+	 * Sets the views for the default list table view.
393
+	 *
394
+	 * @throws EE_Error
395
+	 */
396
+	protected function _set_list_table_views_default()
397
+	{
398
+		parent::_set_list_table_views_default();
399
+		$new_views    = [
400
+			'today' => [
401
+				'slug'        => 'today',
402
+				'label'       => esc_html__('Today', 'event_espresso'),
403
+				'count'       => $this->total_events_today(),
404
+				'bulk_action' => [
405
+					'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
406
+				],
407
+			],
408
+			'month' => [
409
+				'slug'        => 'month',
410
+				'label'       => esc_html__('This Month', 'event_espresso'),
411
+				'count'       => $this->total_events_this_month(),
412
+				'bulk_action' => [
413
+					'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
414
+				],
415
+			],
416
+		];
417
+		$this->_views = array_merge($this->_views, $new_views);
418
+	}
419
+
420
+
421
+	/**
422
+	 * Returns the extra action links for the default list table view.
423
+	 *
424
+	 * @param array    $action_links
425
+	 * @param EE_Event $event
426
+	 * @return array
427
+	 * @throws EE_Error
428
+	 * @throws ReflectionException
429
+	 */
430
+	public function extra_list_table_actions(array $action_links, EE_Event $event)
431
+	{
432
+		if (
433
+			EE_Registry::instance()->CAP->current_user_can(
434
+				'ee_read_registrations',
435
+				'espresso_registrations_reports',
436
+				$event->ID()
437
+			)
438
+		) {
439
+			$reports_link = EE_Admin_Page::add_query_args_and_nonce(
440
+				[
441
+					'action' => 'reports',
442
+					'EVT_ID' => $event->ID(),
443
+				],
444
+				REG_ADMIN_URL
445
+			);
446
+
447
+			$action_links[]     = '
448 448
                 <a href="' . $reports_link . '" 
449 449
                     aria-label="' . esc_attr__('View Report', 'event_espresso') . '" 
450 450
                     class="ee-aria-tooltip button button--icon-only"
451 451
                 >
452 452
                     <span class="dashicons dashicons-chart-bar"></span>
453 453
                 </a>';
454
-        }
455
-        if (EE_Registry::instance()->CAP->current_user_can('ee_read_global_messages', 'view_filtered_messages')) {
456
-            EE_Registry::instance()->load_helper('MSG_Template');
457
-            $action_links[] = EEH_MSG_Template::get_message_action_link(
458
-                'see_notifications_for',
459
-                null,
460
-                ['EVT_ID' => $event->ID()]
461
-            );
462
-        }
463
-        return $action_links;
464
-    }
465
-
466
-
467
-    /**
468
-     * @param $items
469
-     * @return mixed
470
-     */
471
-    public function additional_legend_items($items)
472
-    {
473
-        if (
474
-            EE_Registry::instance()->CAP->current_user_can(
475
-                'ee_read_registrations',
476
-                'espresso_registrations_reports'
477
-            )
478
-        ) {
479
-            $items['reports'] = [
480
-                'class' => 'dashicons dashicons-chart-bar',
481
-                'desc'  => esc_html__('Event Reports', 'event_espresso'),
482
-            ];
483
-        }
484
-        if (EE_Registry::instance()->CAP->current_user_can('ee_read_global_messages', 'view_filtered_messages')) {
485
-            $related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
486
-            // $related_for_icon can sometimes be a string so 'css_class' would be an illegal offset
487
-            // (can only use numeric offsets when treating strings as arrays)
488
-            if (is_array($related_for_icon) && isset($related_for_icon['css_class'], $related_for_icon['label'])) {
489
-                $items['view_related_messages'] = [
490
-                    'class' => $related_for_icon['css_class'],
491
-                    'desc'  => $related_for_icon['label'],
492
-                ];
493
-            }
494
-        }
495
-        return $items;
496
-    }
497
-
498
-
499
-    /**
500
-     * This is the callback method for the duplicate event route
501
-     * Method looks for 'EVT_ID' in the request and retrieves that event and its details and duplicates them
502
-     * into a new event.  We add a hook so that any plugins that add extra event details can hook into this
503
-     * action.  Note that the dupe will have **DUPLICATE** as its title and slug.
504
-     * After duplication the redirect is to the new event edit page.
505
-     *
506
-     * @return void
507
-     * @throws EE_Error If EE_Event is not available with given ID
508
-     * @throws ReflectionException
509
-     * @access protected
510
-     */
511
-    protected function _duplicate_event()
512
-    {
513
-        // first make sure the ID for the event is in the request.
514
-        //  If it isn't then we need to bail and redirect back to overview list table (cause how did we get here?)
515
-        $EVT_ID = $this->request->getRequestParam('EVT_ID', 0, 'int');
516
-        if (! $EVT_ID) {
517
-            EE_Error::add_error(
518
-                esc_html__(
519
-                    'In order to duplicate an event an Event ID is required.  None was given.',
520
-                    'event_espresso'
521
-                ),
522
-                __FILE__,
523
-                __FUNCTION__,
524
-                __LINE__
525
-            );
526
-            $this->_redirect_after_action(false, '', '', [], true);
527
-            return;
528
-        }
529
-        // k we've got EVT_ID so let's use that to get the event we'll duplicate
530
-        $orig_event = EEM_Event::instance()->get_one_by_ID($EVT_ID);
531
-        if (! $orig_event instanceof EE_Event) {
532
-            throw new EE_Error(
533
-                sprintf(
534
-                    esc_html__('An EE_Event object could not be retrieved for the given ID (%s)', 'event_espresso'),
535
-                    $EVT_ID
536
-                )
537
-            );
538
-        }
539
-        // k now let's clone the $orig_event before getting relations
540
-        $new_event = clone $orig_event;
541
-        // original datetimes
542
-        $orig_datetimes = $orig_event->get_many_related('Datetime');
543
-        // other original relations
544
-        $orig_ven = $orig_event->get_many_related('Venue');
545
-        // reset the ID and modify other details to make it clear this is a dupe
546
-        $new_event->set('EVT_ID', 0);
547
-        $new_name = $new_event->name() . ' ' . esc_html__('**DUPLICATE**', 'event_espresso');
548
-        $new_event->set('EVT_name', $new_name);
549
-        $new_event->set(
550
-            'EVT_slug',
551
-            wp_unique_post_slug(
552
-                sanitize_title($orig_event->name()),
553
-                0,
554
-                'publish',
555
-                'espresso_events',
556
-                0
557
-            )
558
-        );
559
-        $new_event->set('status', 'draft');
560
-        // duplicate discussion settings
561
-        $new_event->set('comment_status', $orig_event->get('comment_status'));
562
-        $new_event->set('ping_status', $orig_event->get('ping_status'));
563
-        // save the new event
564
-        $new_event->save();
565
-        // venues
566
-        foreach ($orig_ven as $ven) {
567
-            $new_event->_add_relation_to($ven, 'Venue');
568
-        }
569
-        $new_event->save();
570
-        // now we need to get the question group relations and handle that
571
-        // first primary question groups
572
-        $orig_primary_qgs = $orig_event->get_many_related(
573
-            'Question_Group',
574
-            [['Event_Question_Group.EQG_primary' => true]]
575
-        );
576
-        if (! empty($orig_primary_qgs)) {
577
-            foreach ($orig_primary_qgs as $obj) {
578
-                if ($obj instanceof EE_Question_Group) {
579
-                    $new_event->_add_relation_to($obj, 'Question_Group', ['EQG_primary' => true]);
580
-                }
581
-            }
582
-        }
583
-        // next additional attendee question groups
584
-        $orig_additional_qgs = $orig_event->get_many_related(
585
-            'Question_Group',
586
-            [['Event_Question_Group.EQG_additional' => true]]
587
-        );
588
-        if (! empty($orig_additional_qgs)) {
589
-            foreach ($orig_additional_qgs as $obj) {
590
-                if ($obj instanceof EE_Question_Group) {
591
-                    $new_event->_add_relation_to($obj, 'Question_Group', ['EQG_additional' => true]);
592
-                }
593
-            }
594
-        }
595
-
596
-        $new_event->save();
597
-
598
-        // k now that we have the new event saved we can loop through the datetimes and start adding relations.
599
-        $cloned_tickets = [];
600
-        foreach ($orig_datetimes as $orig_dtt) {
601
-            if (! $orig_dtt instanceof EE_Datetime) {
602
-                continue;
603
-            }
604
-            $new_dtt      = clone $orig_dtt;
605
-            $orig_tickets = $orig_dtt->tickets();
606
-            // save new dtt then add to event
607
-            $new_dtt->set('DTT_ID', 0);
608
-            $new_dtt->set('DTT_sold', 0);
609
-            $new_dtt->set_reserved(0);
610
-            $new_dtt->save();
611
-            $new_event->_add_relation_to($new_dtt, 'Datetime');
612
-            $new_event->save();
613
-            // now let's get the ticket relations setup.
614
-            foreach ((array) $orig_tickets as $orig_ticket) {
615
-                // it's possible a datetime will have no tickets so let's verify we HAVE a ticket first.
616
-                if (! $orig_ticket instanceof EE_Ticket) {
617
-                    continue;
618
-                }
619
-                // is this ticket archived?  If it is then let's skip
620
-                if ($orig_ticket->get('TKT_deleted')) {
621
-                    continue;
622
-                }
623
-                // does this original ticket already exist in the clone_tickets cache?
624
-                //  If so we'll just use the new ticket from it.
625
-                if (isset($cloned_tickets[ $orig_ticket->ID() ])) {
626
-                    $new_ticket = $cloned_tickets[ $orig_ticket->ID() ];
627
-                } else {
628
-                    $new_ticket = clone $orig_ticket;
629
-                    // get relations on the $orig_ticket that we need to setup.
630
-                    $orig_prices = $orig_ticket->prices();
631
-                    $new_ticket->set('TKT_ID', 0);
632
-                    $new_ticket->set('TKT_sold', 0);
633
-                    $new_ticket->set('TKT_reserved', 0);
634
-                    $new_ticket->save(); // make sure new ticket has ID.
635
-                    // price relations on new ticket need to be setup.
636
-                    foreach ($orig_prices as $orig_price) {
637
-                        $new_price = clone $orig_price;
638
-                        $new_price->set('PRC_ID', 0);
639
-                        $new_price->save();
640
-                        $new_ticket->_add_relation_to($new_price, 'Price');
641
-                        $new_ticket->save();
642
-                    }
643
-
644
-                    do_action(
645
-                        'AHEE__Extend_Events_Admin_Page___duplicate_event__duplicate_ticket__after',
646
-                        $orig_ticket,
647
-                        $new_ticket,
648
-                        $orig_prices,
649
-                        $orig_event,
650
-                        $orig_dtt,
651
-                        $new_dtt
652
-                    );
653
-                }
654
-                // k now we can add the new ticket as a relation to the new datetime
655
-                // and make sure its added to our cached $cloned_tickets array
656
-                // for use with later datetimes that have the same ticket.
657
-                $new_dtt->_add_relation_to($new_ticket, 'Ticket');
658
-                $new_dtt->save();
659
-                $cloned_tickets[ $orig_ticket->ID() ] = $new_ticket;
660
-            }
661
-        }
662
-        // clone taxonomy information
663
-        $taxonomies_to_clone_with = apply_filters(
664
-            'FHEE__Extend_Events_Admin_Page___duplicate_event__taxonomies_to_clone',
665
-            ['espresso_event_categories', 'espresso_event_type', 'post_tag']
666
-        );
667
-        // get terms for original event (notice)
668
-        $orig_terms = wp_get_object_terms($orig_event->ID(), $taxonomies_to_clone_with);
669
-        // loop through terms and add them to new event.
670
-        foreach ($orig_terms as $term) {
671
-            wp_set_object_terms($new_event->ID(), $term->term_id, $term->taxonomy, true);
672
-        }
673
-
674
-        // duplicate other core WP_Post items for this event.
675
-        // post thumbnail (feature image).
676
-        $feature_image_id = get_post_thumbnail_id($orig_event->ID());
677
-        if ($feature_image_id) {
678
-            update_post_meta($new_event->ID(), '_thumbnail_id', $feature_image_id);
679
-        }
680
-
681
-        // duplicate page_template setting
682
-        $page_template = get_post_meta($orig_event->ID(), '_wp_page_template', true);
683
-        if ($page_template) {
684
-            update_post_meta($new_event->ID(), '_wp_page_template', $page_template);
685
-        }
686
-
687
-        do_action('AHEE__Extend_Events_Admin_Page___duplicate_event__after', $new_event, $orig_event);
688
-        // now let's redirect to the edit page for this duplicated event if we have a new event id.
689
-        if ($new_event->ID()) {
690
-            $redirect_args = [
691
-                'post'   => $new_event->ID(),
692
-                'action' => 'edit',
693
-            ];
694
-            EE_Error::add_success(
695
-                esc_html__(
696
-                    'Event successfully duplicated.  Please review the details below and make any necessary edits',
697
-                    'event_espresso'
698
-                )
699
-            );
700
-        } else {
701
-            $redirect_args = [
702
-                'action' => 'default',
703
-            ];
704
-            EE_Error::add_error(
705
-                esc_html__('Not able to duplicate event.  Something went wrong.', 'event_espresso'),
706
-                __FILE__,
707
-                __FUNCTION__,
708
-                __LINE__
709
-            );
710
-        }
711
-        $this->_redirect_after_action(false, '', '', $redirect_args, true);
712
-    }
713
-
714
-
715
-    /**
716
-     * Generates output for the import page.
717
-     *
718
-     * @throws EE_Error
719
-     */
720
-    protected function _import_page()
721
-    {
722
-        $title                                      = esc_html__('Import', 'event_espresso');
723
-        $intro                                      = esc_html__(
724
-            'If you have a previously exported Event Espresso 4 information in a Comma Separated Value (CSV) file format, you can upload the file here: ',
725
-            'event_espresso'
726
-        );
727
-
728
-        $form_url = EVENTS_ADMIN_URL;
729
-        $action   = 'import_events';
730
-        $type     = 'csv';
731
-
732
-        $this->_template_args['form'] = EE_Import::instance()->upload_form(
733
-            $title,
734
-            $intro,
735
-            $form_url,
736
-            $action,
737
-            $type
738
-        );
739
-
740
-        $this->_template_args['sample_file_link']   = EE_Admin_Page::add_query_args_and_nonce(
741
-            ['action' => 'sample_export_file'],
742
-            $this->_admin_base_url
743
-        );
744
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
745
-            EVENTS_CAF_TEMPLATE_PATH . 'import_page.template.php',
746
-            $this->_template_args,
747
-            true
748
-        );
749
-        $this->display_admin_page_with_sidebar();
750
-    }
751
-
752
-
753
-    /**
754
-     * _import_events
755
-     * This handles displaying the screen and running imports for importing events.
756
-     *
757
-     * @return void
758
-     * @throws EE_Error
759
-     */
760
-    protected function _import_events()
761
-    {
762
-        require_once(EE_CLASSES . 'EE_Import.class.php');
763
-        $success = EE_Import::instance()->import();
764
-        $this->_redirect_after_action(
765
-            $success,
766
-            esc_html__('Import File', 'event_espresso'),
767
-            'ran',
768
-            ['action' => 'import_page'],
769
-            true
770
-        );
771
-    }
772
-
773
-
774
-    /**
775
-     * _events_export
776
-     * Will export all (or just the given event) to a Excel compatible file.
777
-     *
778
-     * @access protected
779
-     * @return void
780
-     */
781
-    protected function _events_export()
782
-    {
783
-        $EVT_ID = $this->request->getRequestParam('EVT_ID', 0, 'int');
784
-        $EVT_ID = $this->request->getRequestParam('EVT_IDs', $EVT_ID, 'int');
785
-        $this->request->mergeRequestParams(
786
-            [
787
-                'export' => 'report',
788
-                'action' => 'all_event_data',
789
-                'EVT_ID' => $EVT_ID,
790
-            ]
791
-        );
792
-        if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
793
-            require_once(EE_CLASSES . 'EE_Export.class.php');
794
-            $EE_Export = EE_Export::instance($this->request->requestParams());
795
-            $EE_Export->export();
796
-        }
797
-    }
798
-
799
-
800
-    /**
801
-     * handle category exports()
802
-     *
803
-     * @return void
804
-     */
805
-    protected function _categories_export()
806
-    {
807
-        $EVT_ID = $this->request->getRequestParam('EVT_CAT_ID', 0, 'int');
808
-        $this->request->mergeRequestParams(
809
-            [
810
-                'export' => 'report',
811
-                'action' => 'categories',
812
-                'EVT_ID' => $EVT_ID,
813
-            ]
814
-        );
815
-        if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
816
-            require_once(EE_CLASSES . 'EE_Export.class.php');
817
-            $EE_Export = EE_Export::instance($this->request->requestParams());
818
-            $EE_Export->export();
819
-        }
820
-    }
821
-
822
-
823
-    /**
824
-     * Creates a sample CSV file for importing
825
-     */
826
-    protected function _sample_export_file()
827
-    {
828
-        $EE_Export = EE_Export::instance();
829
-        if ($EE_Export instanceof EE_Export) {
830
-            $EE_Export->export();
831
-        }
832
-    }
833
-
834
-
835
-    /*************        Template Settings        *************/
836
-    /**
837
-     * Generates template settings page output
838
-     *
839
-     * @throws DomainException
840
-     * @throws EE_Error
841
-     * @throws InvalidArgumentException
842
-     * @throws InvalidDataTypeException
843
-     * @throws InvalidInterfaceException
844
-     */
845
-    protected function _template_settings()
846
-    {
847
-        $this->_template_args['values'] = $this->_yes_no_values;
848
-        /**
849
-         * Note leaving this filter in for backward compatibility this was moved in 4.6.x
850
-         * from General_Settings_Admin_Page to here.
851
-         */
852
-        $this->_template_args = apply_filters(
853
-            'FHEE__General_Settings_Admin_Page__template_settings__template_args',
854
-            $this->_template_args
855
-        );
856
-        $this->_set_add_edit_form_tags('update_template_settings');
857
-        $this->_set_publish_post_box_vars(null, false, false, null, false);
858
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
859
-            EVENTS_CAF_TEMPLATE_PATH . 'template_settings.template.php',
860
-            $this->_template_args,
861
-            true
862
-        );
863
-        $this->display_admin_page_with_sidebar();
864
-    }
865
-
866
-
867
-    /**
868
-     * Handler for updating template settings.
869
-     *
870
-     * @throws EE_Error
871
-     */
872
-    protected function _update_template_settings()
873
-    {
874
-        /**
875
-         * Note leaving this filter in for backward compatibility this was moved in 4.6.x
876
-         * from General_Settings_Admin_Page to here.
877
-         */
878
-        EE_Registry::instance()->CFG->template_settings = apply_filters(
879
-            'FHEE__General_Settings_Admin_Page__update_template_settings__data',
880
-            EE_Registry::instance()->CFG->template_settings,
881
-            $this->request->requestParams()
882
-        );
883
-        // update custom post type slugs and detect if we need to flush rewrite rules
884
-        $old_slug = EE_Registry::instance()->CFG->core->event_cpt_slug;
885
-
886
-        $event_cpt_slug = $this->request->getRequestParam('event_cpt_slug');
887
-
888
-        EE_Registry::instance()->CFG->core->event_cpt_slug = $event_cpt_slug
889
-            ? EEH_URL::slugify($event_cpt_slug, 'events')
890
-            : EE_Registry::instance()->CFG->core->event_cpt_slug;
891
-
892
-        $what    = esc_html__('Template Settings', 'event_espresso');
893
-        $success = $this->_update_espresso_configuration(
894
-            $what,
895
-            EE_Registry::instance()->CFG->template_settings,
896
-            __FILE__,
897
-            __FUNCTION__,
898
-            __LINE__
899
-        );
900
-        if (EE_Registry::instance()->CFG->core->event_cpt_slug !== $old_slug) {
901
-            /** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
902
-            $rewrite_rules = LoaderFactory::getLoader()->getShared(
903
-                'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
904
-            );
905
-            $rewrite_rules->flush();
906
-        }
907
-        $this->_redirect_after_action($success, $what, 'updated', ['action' => 'template_settings']);
908
-    }
909
-
910
-
911
-    /**
912
-     * _premium_event_editor_meta_boxes
913
-     * add all metaboxes related to the event_editor
914
-     *
915
-     * @access protected
916
-     * @return void
917
-     * @throws EE_Error
918
-     * @throws ReflectionException
919
-     */
920
-    protected function _premium_event_editor_meta_boxes()
921
-    {
922
-        $this->verify_cpt_object();
923
-        // check if the new EDTR reg options meta box is being used, and if so, don't load the legacy version
924
-        if (
925
-            ! $this->admin_config->useAdvancedEditor()
926
-            || ! $this->feature->allowed('use_reg_options_meta_box')
927
-        ) {
928
-            $this->addMetaBox(
929
-                'espresso_event_editor_event_options',
930
-                esc_html__('Event Registration Options', 'event_espresso'),
931
-                [$this, 'registration_options_meta_box'],
932
-                $this->page_slug,
933
-                'side',
934
-                'core'
935
-            );
936
-        }
937
-    }
938
-
939
-
940
-    /**
941
-     * override caf metabox
942
-     *
943
-     * @return void
944
-     * @throws EE_Error
945
-     * @throws ReflectionException
946
-     */
947
-    public function registration_options_meta_box()
948
-    {
949
-        $yes_no_values = [
950
-            ['id' => true, 'text' => esc_html__('Yes', 'event_espresso')],
951
-            ['id' => false, 'text' => esc_html__('No', 'event_espresso')],
952
-        ];
953
-
954
-        $default_reg_status_values = EEM_Registration::reg_status_array(
955
-            [
956
-                EEM_Registration::status_id_cancelled,
957
-                EEM_Registration::status_id_declined,
958
-                EEM_Registration::status_id_incomplete,
959
-                EEM_Registration::status_id_wait_list,
960
-            ],
961
-            true
962
-        );
963
-
964
-        $template_args['active_status']    = $this->_cpt_model_obj->pretty_active_status(false);
965
-        $template_args['_event']           = $this->_cpt_model_obj;
966
-        $template_args['additional_limit'] = $this->_cpt_model_obj->additional_limit();
967
-
968
-        $template_args['default_registration_status']     = EEH_Form_Fields::select_input(
969
-            'default_reg_status',
970
-            $default_reg_status_values,
971
-            $this->_cpt_model_obj->default_registration_status()
972
-        );
973
-        $template_args['display_description']             = EEH_Form_Fields::select_input(
974
-            'display_desc',
975
-            $yes_no_values,
976
-            $this->_cpt_model_obj->display_description()
977
-        );
978
-        $template_args['display_ticket_selector']         = EEH_Form_Fields::select_input(
979
-            'display_ticket_selector',
980
-            $yes_no_values,
981
-            $this->_cpt_model_obj->display_ticket_selector(),
982
-            '',
983
-            '',
984
-            false
985
-        );
986
-        $template_args['EVT_default_registration_status'] = EEH_Form_Fields::select_input(
987
-            'EVT_default_registration_status',
988
-            $default_reg_status_values,
989
-            $this->_cpt_model_obj->default_registration_status()
990
-        );
991
-        $template_args['additional_registration_options'] = apply_filters(
992
-            'FHEE__Events_Admin_Page__registration_options_meta_box__additional_registration_options',
993
-            '',
994
-            $template_args,
995
-            $yes_no_values,
996
-            $default_reg_status_values
997
-        );
998
-        EEH_Template::display_template(
999
-            EVENTS_CAF_TEMPLATE_PATH . 'event_registration_options.template.php',
1000
-            $template_args
1001
-        );
1002
-    }
1003
-
1004
-
1005
-
1006
-    /**
1007
-     * wp_list_table_mods for caf
1008
-     * ============================
1009
-     */
1010
-    /**
1011
-     * hook into list table filters and provide filters for caffeinated list table
1012
-     *
1013
-     * @param array $old_filters    any existing filters present
1014
-     * @param array $list_table_obj the list table object
1015
-     * @return array                  new filters
1016
-     * @throws EE_Error
1017
-     * @throws ReflectionException
1018
-     */
1019
-    public function list_table_filters($old_filters, $list_table_obj)
1020
-    {
1021
-        $filters = [];
1022
-        // first month/year filters
1023
-        $filters[] = $this->espresso_event_months_dropdown();
1024
-        $status    = $this->request->getRequestParam('status');
1025
-        // active status dropdown
1026
-        if ($status !== 'draft') {
1027
-            $filters[] = $this->active_status_dropdown($this->request->getRequestParam('active_status'));
1028
-            $filters[] = $this->venuesDropdown($this->request->getRequestParam('venue'));
1029
-        }
1030
-        // category filter
1031
-        $filters[] = $this->category_dropdown();
1032
-        return array_merge($old_filters, $filters);
1033
-    }
1034
-
1035
-
1036
-    /**
1037
-     * espresso_event_months_dropdown
1038
-     *
1039
-     * @access public
1040
-     * @return string                dropdown listing month/year selections for events.
1041
-     * @throws EE_Error
1042
-     */
1043
-    public function espresso_event_months_dropdown()
1044
-    {
1045
-        // what we need to do is get all PRIMARY datetimes for all events to filter on.
1046
-        // Note we need to include any other filters that are set!
1047
-        return EEH_Form_Fields::generate_event_months_dropdown(
1048
-            $this->request->getRequestParam('month_range'),
1049
-            $this->request->getRequestParam('status'),
1050
-            $this->request->getRequestParam('EVT_CAT', 0, 'int'),
1051
-            $this->request->getRequestParam('active_status')
1052
-        );
1053
-    }
1054
-
1055
-
1056
-    /**
1057
-     * returns a list of "active" statuses on the event
1058
-     *
1059
-     * @param string $current_value whatever the current active status is
1060
-     * @return string
1061
-     */
1062
-    public function active_status_dropdown($current_value = '')
1063
-    {
1064
-        $select_name = 'active_status';
1065
-        $values      = [
1066
-            'none'     => esc_html__('Show Active/Inactive', 'event_espresso'),
1067
-            'active'   => esc_html__('Active', 'event_espresso'),
1068
-            'upcoming' => esc_html__('Upcoming', 'event_espresso'),
1069
-            'expired'  => esc_html__('Expired', 'event_espresso'),
1070
-            'inactive' => esc_html__('Inactive', 'event_espresso'),
1071
-        ];
1072
-
1073
-        return EEH_Form_Fields::select_input($select_name, $values, $current_value);
1074
-    }
1075
-
1076
-
1077
-    /**
1078
-     * returns a list of "venues"
1079
-     *
1080
-     * @param string $current_value whatever the current active status is
1081
-     * @return string
1082
-     * @throws EE_Error
1083
-     * @throws ReflectionException
1084
-     */
1085
-    protected function venuesDropdown($current_value = '')
1086
-    {
1087
-        $values = ['' => esc_html__('All Venues', 'event_espresso')];
1088
-        // populate the list of venues.
1089
-        $venues = EEM_Venue::instance()->get_all(['order_by' => ['VNU_name' => 'ASC']]);
1090
-
1091
-        foreach ($venues as $venue) {
1092
-            $values[ $venue->ID() ] = $venue->name();
1093
-        }
1094
-
1095
-        return EEH_Form_Fields::select_input('venue', $values, $current_value);
1096
-    }
1097
-
1098
-
1099
-    /**
1100
-     * output a dropdown of the categories for the category filter on the event admin list table
1101
-     *
1102
-     * @access  public
1103
-     * @return string html
1104
-     * @throws EE_Error
1105
-     * @throws ReflectionException
1106
-     */
1107
-    public function category_dropdown()
1108
-    {
1109
-        return EEH_Form_Fields::generate_event_category_dropdown(
1110
-            $this->request->getRequestParam('EVT_CAT', -1, 'int')
1111
-        );
1112
-    }
1113
-
1114
-
1115
-    /**
1116
-     * get total number of events today
1117
-     *
1118
-     * @access public
1119
-     * @return int
1120
-     * @throws EE_Error
1121
-     * @throws InvalidArgumentException
1122
-     * @throws InvalidDataTypeException
1123
-     * @throws InvalidInterfaceException
1124
-     */
1125
-    public function total_events_today()
1126
-    {
1127
-        $start = EEM_Datetime::instance()->convert_datetime_for_query(
1128
-            'DTT_EVT_start',
1129
-            date('Y-m-d') . ' 00:00:00',
1130
-            'Y-m-d H:i:s',
1131
-            'UTC'
1132
-        );
1133
-        $end   = EEM_Datetime::instance()->convert_datetime_for_query(
1134
-            'DTT_EVT_start',
1135
-            date('Y-m-d') . ' 23:59:59',
1136
-            'Y-m-d H:i:s',
1137
-            'UTC'
1138
-        );
1139
-        $where = [
1140
-            'Datetime.DTT_EVT_start' => ['BETWEEN', [$start, $end]],
1141
-        ];
1142
-        return EEM_Event::instance()->count([$where, 'caps' => 'read_admin'], 'EVT_ID', true);
1143
-    }
1144
-
1145
-
1146
-    /**
1147
-     * get total number of events this month
1148
-     *
1149
-     * @access public
1150
-     * @return int
1151
-     * @throws EE_Error
1152
-     * @throws InvalidArgumentException
1153
-     * @throws InvalidDataTypeException
1154
-     * @throws InvalidInterfaceException
1155
-     */
1156
-    public function total_events_this_month()
1157
-    {
1158
-        // Dates
1159
-        $this_year_r     = date('Y');
1160
-        $this_month_r    = date('m');
1161
-        $days_this_month = date('t');
1162
-        $start           = EEM_Datetime::instance()->convert_datetime_for_query(
1163
-            'DTT_EVT_start',
1164
-            $this_year_r . '-' . $this_month_r . '-01 00:00:00',
1165
-            'Y-m-d H:i:s',
1166
-            'UTC'
1167
-        );
1168
-        $end             = EEM_Datetime::instance()->convert_datetime_for_query(
1169
-            'DTT_EVT_start',
1170
-            $this_year_r . '-' . $this_month_r . '-' . $days_this_month . ' 23:59:59',
1171
-            'Y-m-d H:i:s',
1172
-            'UTC'
1173
-        );
1174
-        $where           = [
1175
-            'Datetime.DTT_EVT_start' => ['BETWEEN', [$start, $end]],
1176
-        ];
1177
-        return EEM_Event::instance()->count([$where, 'caps' => 'read_admin'], 'EVT_ID', true);
1178
-    }
1179
-
1180
-
1181
-    /** DEFAULT TICKETS STUFF **/
1182
-
1183
-    /**
1184
-     * Output default tickets list table view.
1185
-     *
1186
-     * @throws EE_Error
1187
-     */
1188
-    public function _tickets_overview_list_table()
1189
-    {
1190
-        if (
1191
-            $this->admin_config->useAdvancedEditor()
1192
-            && $this->feature->allowed('use_default_ticket_manager')
1193
-        ) {
1194
-            // check if the new EDTR reg options meta box is being used, and if so, don't load the legacy version
1195
-            $this->_template_args['admin_page_content'] = EEH_Template::display_template(
1196
-                EVENTS_CAF_TEMPLATE_PATH . 'default_tickets_moved_notice.template.php',
1197
-                [],
1198
-                true
1199
-            );
1200
-            $this->display_admin_page_with_no_sidebar();
1201
-        } else {
1202
-            $this->_search_btn_label = esc_html__('Tickets', 'event_espresso');
1203
-            $this->display_admin_list_table_page_with_no_sidebar();
1204
-        }
1205
-    }
1206
-
1207
-
1208
-    /**
1209
-     * @param int  $per_page
1210
-     * @param bool $count
1211
-     * @param bool $trashed
1212
-     * @return EE_Soft_Delete_Base_Class[]|int
1213
-     * @throws EE_Error
1214
-     */
1215
-    public function get_default_tickets($per_page = 10, $count = false, $trashed = false)
1216
-    {
1217
-        $orderby = $this->request->getRequestParam('orderby', 'TKT_name');
1218
-        $order   = $this->request->getRequestParam('order', 'ASC');
1219
-        switch ($orderby) {
1220
-            case 'TKT_name':
1221
-                $orderby = ['TKT_name' => $order];
1222
-                break;
1223
-            case 'TKT_price':
1224
-                $orderby = ['TKT_price' => $order];
1225
-                break;
1226
-            case 'TKT_uses':
1227
-                $orderby = ['TKT_uses' => $order];
1228
-                break;
1229
-            case 'TKT_min':
1230
-                $orderby = ['TKT_min' => $order];
1231
-                break;
1232
-            case 'TKT_max':
1233
-                $orderby = ['TKT_max' => $order];
1234
-                break;
1235
-            case 'TKT_qty':
1236
-                $orderby = ['TKT_qty' => $order];
1237
-                break;
1238
-        }
1239
-
1240
-        $current_page = $this->request->getRequestParam('paged', 1, 'int');
1241
-        $per_page     = $this->request->getRequestParam('perpage', $per_page, 'int');
1242
-        $offset       = ($current_page - 1) * $per_page;
1243
-
1244
-        $where = [
1245
-            'TKT_is_default' => 1,
1246
-            'TKT_deleted'    => $trashed,
1247
-        ];
1248
-
1249
-        $search_term = $this->request->getRequestParam('s');
1250
-        if ($search_term) {
1251
-            $search_term = '%' . $search_term . '%';
1252
-            $where['OR'] = [
1253
-                'TKT_name'        => ['LIKE', $search_term],
1254
-                'TKT_description' => ['LIKE', $search_term],
1255
-            ];
1256
-        }
1257
-
1258
-        return $count
1259
-            ? EEM_Ticket::instance()->count_deleted_and_undeleted([$where])
1260
-            : EEM_Ticket::instance()->get_all_deleted_and_undeleted(
1261
-                [
1262
-                    $where,
1263
-                    'order_by' => $orderby,
1264
-                    'limit'    => [$offset, $per_page],
1265
-                    'group_by' => 'TKT_ID',
1266
-                ]
1267
-            );
1268
-    }
1269
-
1270
-
1271
-    /**
1272
-     * @param bool $trash
1273
-     * @throws EE_Error
1274
-     * @throws InvalidArgumentException
1275
-     * @throws InvalidDataTypeException
1276
-     * @throws InvalidInterfaceException
1277
-     */
1278
-    protected function _trash_or_restore_ticket($trash = false)
1279
-    {
1280
-        $success = 1;
1281
-        $TKT     = EEM_Ticket::instance();
1282
-        // checkboxes?
1283
-        $checkboxes = $this->request->getRequestParam('checkbox', [], 'int', true);
1284
-        if (! empty($checkboxes)) {
1285
-            // if array has more than one element then success message should be plural
1286
-            $success = count($checkboxes) > 1 ? 2 : 1;
1287
-            // cycle thru the boxes
1288
-            while (list($TKT_ID, $value) = each($checkboxes)) {
1289
-                if ($trash) {
1290
-                    if (! $TKT->delete_by_ID($TKT_ID)) {
1291
-                        $success = 0;
1292
-                    }
1293
-                } elseif (! $TKT->restore_by_ID($TKT_ID)) {
1294
-                    $success = 0;
1295
-                }
1296
-            }
1297
-        } else {
1298
-            // grab single id and trash
1299
-            $TKT_ID = $this->request->getRequestParam('TKT_ID', 0, 'int');
1300
-            if ($trash) {
1301
-                if (! $TKT->delete_by_ID($TKT_ID)) {
1302
-                    $success = 0;
1303
-                }
1304
-            } elseif (! $TKT->restore_by_ID($TKT_ID)) {
1305
-                $success = 0;
1306
-            }
1307
-        }
1308
-        $action_desc = $trash ? 'moved to the trash' : 'restored';
1309
-        $query_args  = [
1310
-            'action' => 'ticket_list_table',
1311
-            'status' => $trash ? '' : 'trashed',
1312
-        ];
1313
-        $this->_redirect_after_action($success, esc_html__('Tickets', 'event_espresso'), $action_desc, $query_args);
1314
-    }
1315
-
1316
-
1317
-    /**
1318
-     * Handles trashing default ticket.
1319
-     *
1320
-     * @throws EE_Error
1321
-     * @throws ReflectionException
1322
-     */
1323
-    protected function _delete_ticket()
1324
-    {
1325
-        $success = 1;
1326
-        // checkboxes?
1327
-        $checkboxes = $this->request->getRequestParam('checkbox', [], 'int', true);
1328
-        if (! empty($checkboxes)) {
1329
-            // if array has more than one element then success message should be plural
1330
-            $success = count($checkboxes) > 1 ? 2 : 1;
1331
-            // cycle thru the boxes
1332
-            while (list($TKT_ID, $value) = each($checkboxes)) {
1333
-                // delete
1334
-                if (! $this->_delete_the_ticket($TKT_ID)) {
1335
-                    $success = 0;
1336
-                }
1337
-            }
1338
-        } else {
1339
-            // grab single id and trash
1340
-            $TKT_ID = $this->request->getRequestParam('TKT_ID', 0, 'int');
1341
-            if (! $this->_delete_the_ticket($TKT_ID)) {
1342
-                $success = 0;
1343
-            }
1344
-        }
1345
-        $action_desc = 'deleted';
1346
-        $query_args  = [
1347
-            'action' => 'ticket_list_table',
1348
-            'status' => 'trashed',
1349
-        ];
1350
-        // fail safe.  If the default ticket count === 1 then we need to redirect to event overview.
1351
-        if (
1352
-            EEM_Ticket::instance()->count_deleted_and_undeleted(
1353
-                [['TKT_is_default' => 1]],
1354
-                'TKT_ID',
1355
-                true
1356
-            )
1357
-        ) {
1358
-            $query_args = [];
1359
-        }
1360
-        $this->_redirect_after_action($success, esc_html__('Tickets', 'event_espresso'), $action_desc, $query_args);
1361
-    }
1362
-
1363
-
1364
-    /**
1365
-     * @param int $TKT_ID
1366
-     * @return bool|int
1367
-     * @throws EE_Error
1368
-     * @throws ReflectionException
1369
-     */
1370
-    protected function _delete_the_ticket($TKT_ID)
1371
-    {
1372
-        $ticket = EEM_Ticket::instance()->get_one_by_ID($TKT_ID);
1373
-        if (! $ticket instanceof EE_Ticket) {
1374
-            return false;
1375
-        }
1376
-        $ticket->_remove_relations('Datetime');
1377
-        // delete all related prices first
1378
-        $ticket->delete_related_permanently('Price');
1379
-        return $ticket->delete_permanently();
1380
-    }
454
+		}
455
+		if (EE_Registry::instance()->CAP->current_user_can('ee_read_global_messages', 'view_filtered_messages')) {
456
+			EE_Registry::instance()->load_helper('MSG_Template');
457
+			$action_links[] = EEH_MSG_Template::get_message_action_link(
458
+				'see_notifications_for',
459
+				null,
460
+				['EVT_ID' => $event->ID()]
461
+			);
462
+		}
463
+		return $action_links;
464
+	}
465
+
466
+
467
+	/**
468
+	 * @param $items
469
+	 * @return mixed
470
+	 */
471
+	public function additional_legend_items($items)
472
+	{
473
+		if (
474
+			EE_Registry::instance()->CAP->current_user_can(
475
+				'ee_read_registrations',
476
+				'espresso_registrations_reports'
477
+			)
478
+		) {
479
+			$items['reports'] = [
480
+				'class' => 'dashicons dashicons-chart-bar',
481
+				'desc'  => esc_html__('Event Reports', 'event_espresso'),
482
+			];
483
+		}
484
+		if (EE_Registry::instance()->CAP->current_user_can('ee_read_global_messages', 'view_filtered_messages')) {
485
+			$related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
486
+			// $related_for_icon can sometimes be a string so 'css_class' would be an illegal offset
487
+			// (can only use numeric offsets when treating strings as arrays)
488
+			if (is_array($related_for_icon) && isset($related_for_icon['css_class'], $related_for_icon['label'])) {
489
+				$items['view_related_messages'] = [
490
+					'class' => $related_for_icon['css_class'],
491
+					'desc'  => $related_for_icon['label'],
492
+				];
493
+			}
494
+		}
495
+		return $items;
496
+	}
497
+
498
+
499
+	/**
500
+	 * This is the callback method for the duplicate event route
501
+	 * Method looks for 'EVT_ID' in the request and retrieves that event and its details and duplicates them
502
+	 * into a new event.  We add a hook so that any plugins that add extra event details can hook into this
503
+	 * action.  Note that the dupe will have **DUPLICATE** as its title and slug.
504
+	 * After duplication the redirect is to the new event edit page.
505
+	 *
506
+	 * @return void
507
+	 * @throws EE_Error If EE_Event is not available with given ID
508
+	 * @throws ReflectionException
509
+	 * @access protected
510
+	 */
511
+	protected function _duplicate_event()
512
+	{
513
+		// first make sure the ID for the event is in the request.
514
+		//  If it isn't then we need to bail and redirect back to overview list table (cause how did we get here?)
515
+		$EVT_ID = $this->request->getRequestParam('EVT_ID', 0, 'int');
516
+		if (! $EVT_ID) {
517
+			EE_Error::add_error(
518
+				esc_html__(
519
+					'In order to duplicate an event an Event ID is required.  None was given.',
520
+					'event_espresso'
521
+				),
522
+				__FILE__,
523
+				__FUNCTION__,
524
+				__LINE__
525
+			);
526
+			$this->_redirect_after_action(false, '', '', [], true);
527
+			return;
528
+		}
529
+		// k we've got EVT_ID so let's use that to get the event we'll duplicate
530
+		$orig_event = EEM_Event::instance()->get_one_by_ID($EVT_ID);
531
+		if (! $orig_event instanceof EE_Event) {
532
+			throw new EE_Error(
533
+				sprintf(
534
+					esc_html__('An EE_Event object could not be retrieved for the given ID (%s)', 'event_espresso'),
535
+					$EVT_ID
536
+				)
537
+			);
538
+		}
539
+		// k now let's clone the $orig_event before getting relations
540
+		$new_event = clone $orig_event;
541
+		// original datetimes
542
+		$orig_datetimes = $orig_event->get_many_related('Datetime');
543
+		// other original relations
544
+		$orig_ven = $orig_event->get_many_related('Venue');
545
+		// reset the ID and modify other details to make it clear this is a dupe
546
+		$new_event->set('EVT_ID', 0);
547
+		$new_name = $new_event->name() . ' ' . esc_html__('**DUPLICATE**', 'event_espresso');
548
+		$new_event->set('EVT_name', $new_name);
549
+		$new_event->set(
550
+			'EVT_slug',
551
+			wp_unique_post_slug(
552
+				sanitize_title($orig_event->name()),
553
+				0,
554
+				'publish',
555
+				'espresso_events',
556
+				0
557
+			)
558
+		);
559
+		$new_event->set('status', 'draft');
560
+		// duplicate discussion settings
561
+		$new_event->set('comment_status', $orig_event->get('comment_status'));
562
+		$new_event->set('ping_status', $orig_event->get('ping_status'));
563
+		// save the new event
564
+		$new_event->save();
565
+		// venues
566
+		foreach ($orig_ven as $ven) {
567
+			$new_event->_add_relation_to($ven, 'Venue');
568
+		}
569
+		$new_event->save();
570
+		// now we need to get the question group relations and handle that
571
+		// first primary question groups
572
+		$orig_primary_qgs = $orig_event->get_many_related(
573
+			'Question_Group',
574
+			[['Event_Question_Group.EQG_primary' => true]]
575
+		);
576
+		if (! empty($orig_primary_qgs)) {
577
+			foreach ($orig_primary_qgs as $obj) {
578
+				if ($obj instanceof EE_Question_Group) {
579
+					$new_event->_add_relation_to($obj, 'Question_Group', ['EQG_primary' => true]);
580
+				}
581
+			}
582
+		}
583
+		// next additional attendee question groups
584
+		$orig_additional_qgs = $orig_event->get_many_related(
585
+			'Question_Group',
586
+			[['Event_Question_Group.EQG_additional' => true]]
587
+		);
588
+		if (! empty($orig_additional_qgs)) {
589
+			foreach ($orig_additional_qgs as $obj) {
590
+				if ($obj instanceof EE_Question_Group) {
591
+					$new_event->_add_relation_to($obj, 'Question_Group', ['EQG_additional' => true]);
592
+				}
593
+			}
594
+		}
595
+
596
+		$new_event->save();
597
+
598
+		// k now that we have the new event saved we can loop through the datetimes and start adding relations.
599
+		$cloned_tickets = [];
600
+		foreach ($orig_datetimes as $orig_dtt) {
601
+			if (! $orig_dtt instanceof EE_Datetime) {
602
+				continue;
603
+			}
604
+			$new_dtt      = clone $orig_dtt;
605
+			$orig_tickets = $orig_dtt->tickets();
606
+			// save new dtt then add to event
607
+			$new_dtt->set('DTT_ID', 0);
608
+			$new_dtt->set('DTT_sold', 0);
609
+			$new_dtt->set_reserved(0);
610
+			$new_dtt->save();
611
+			$new_event->_add_relation_to($new_dtt, 'Datetime');
612
+			$new_event->save();
613
+			// now let's get the ticket relations setup.
614
+			foreach ((array) $orig_tickets as $orig_ticket) {
615
+				// it's possible a datetime will have no tickets so let's verify we HAVE a ticket first.
616
+				if (! $orig_ticket instanceof EE_Ticket) {
617
+					continue;
618
+				}
619
+				// is this ticket archived?  If it is then let's skip
620
+				if ($orig_ticket->get('TKT_deleted')) {
621
+					continue;
622
+				}
623
+				// does this original ticket already exist in the clone_tickets cache?
624
+				//  If so we'll just use the new ticket from it.
625
+				if (isset($cloned_tickets[ $orig_ticket->ID() ])) {
626
+					$new_ticket = $cloned_tickets[ $orig_ticket->ID() ];
627
+				} else {
628
+					$new_ticket = clone $orig_ticket;
629
+					// get relations on the $orig_ticket that we need to setup.
630
+					$orig_prices = $orig_ticket->prices();
631
+					$new_ticket->set('TKT_ID', 0);
632
+					$new_ticket->set('TKT_sold', 0);
633
+					$new_ticket->set('TKT_reserved', 0);
634
+					$new_ticket->save(); // make sure new ticket has ID.
635
+					// price relations on new ticket need to be setup.
636
+					foreach ($orig_prices as $orig_price) {
637
+						$new_price = clone $orig_price;
638
+						$new_price->set('PRC_ID', 0);
639
+						$new_price->save();
640
+						$new_ticket->_add_relation_to($new_price, 'Price');
641
+						$new_ticket->save();
642
+					}
643
+
644
+					do_action(
645
+						'AHEE__Extend_Events_Admin_Page___duplicate_event__duplicate_ticket__after',
646
+						$orig_ticket,
647
+						$new_ticket,
648
+						$orig_prices,
649
+						$orig_event,
650
+						$orig_dtt,
651
+						$new_dtt
652
+					);
653
+				}
654
+				// k now we can add the new ticket as a relation to the new datetime
655
+				// and make sure its added to our cached $cloned_tickets array
656
+				// for use with later datetimes that have the same ticket.
657
+				$new_dtt->_add_relation_to($new_ticket, 'Ticket');
658
+				$new_dtt->save();
659
+				$cloned_tickets[ $orig_ticket->ID() ] = $new_ticket;
660
+			}
661
+		}
662
+		// clone taxonomy information
663
+		$taxonomies_to_clone_with = apply_filters(
664
+			'FHEE__Extend_Events_Admin_Page___duplicate_event__taxonomies_to_clone',
665
+			['espresso_event_categories', 'espresso_event_type', 'post_tag']
666
+		);
667
+		// get terms for original event (notice)
668
+		$orig_terms = wp_get_object_terms($orig_event->ID(), $taxonomies_to_clone_with);
669
+		// loop through terms and add them to new event.
670
+		foreach ($orig_terms as $term) {
671
+			wp_set_object_terms($new_event->ID(), $term->term_id, $term->taxonomy, true);
672
+		}
673
+
674
+		// duplicate other core WP_Post items for this event.
675
+		// post thumbnail (feature image).
676
+		$feature_image_id = get_post_thumbnail_id($orig_event->ID());
677
+		if ($feature_image_id) {
678
+			update_post_meta($new_event->ID(), '_thumbnail_id', $feature_image_id);
679
+		}
680
+
681
+		// duplicate page_template setting
682
+		$page_template = get_post_meta($orig_event->ID(), '_wp_page_template', true);
683
+		if ($page_template) {
684
+			update_post_meta($new_event->ID(), '_wp_page_template', $page_template);
685
+		}
686
+
687
+		do_action('AHEE__Extend_Events_Admin_Page___duplicate_event__after', $new_event, $orig_event);
688
+		// now let's redirect to the edit page for this duplicated event if we have a new event id.
689
+		if ($new_event->ID()) {
690
+			$redirect_args = [
691
+				'post'   => $new_event->ID(),
692
+				'action' => 'edit',
693
+			];
694
+			EE_Error::add_success(
695
+				esc_html__(
696
+					'Event successfully duplicated.  Please review the details below and make any necessary edits',
697
+					'event_espresso'
698
+				)
699
+			);
700
+		} else {
701
+			$redirect_args = [
702
+				'action' => 'default',
703
+			];
704
+			EE_Error::add_error(
705
+				esc_html__('Not able to duplicate event.  Something went wrong.', 'event_espresso'),
706
+				__FILE__,
707
+				__FUNCTION__,
708
+				__LINE__
709
+			);
710
+		}
711
+		$this->_redirect_after_action(false, '', '', $redirect_args, true);
712
+	}
713
+
714
+
715
+	/**
716
+	 * Generates output for the import page.
717
+	 *
718
+	 * @throws EE_Error
719
+	 */
720
+	protected function _import_page()
721
+	{
722
+		$title                                      = esc_html__('Import', 'event_espresso');
723
+		$intro                                      = esc_html__(
724
+			'If you have a previously exported Event Espresso 4 information in a Comma Separated Value (CSV) file format, you can upload the file here: ',
725
+			'event_espresso'
726
+		);
727
+
728
+		$form_url = EVENTS_ADMIN_URL;
729
+		$action   = 'import_events';
730
+		$type     = 'csv';
731
+
732
+		$this->_template_args['form'] = EE_Import::instance()->upload_form(
733
+			$title,
734
+			$intro,
735
+			$form_url,
736
+			$action,
737
+			$type
738
+		);
739
+
740
+		$this->_template_args['sample_file_link']   = EE_Admin_Page::add_query_args_and_nonce(
741
+			['action' => 'sample_export_file'],
742
+			$this->_admin_base_url
743
+		);
744
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
745
+			EVENTS_CAF_TEMPLATE_PATH . 'import_page.template.php',
746
+			$this->_template_args,
747
+			true
748
+		);
749
+		$this->display_admin_page_with_sidebar();
750
+	}
751
+
752
+
753
+	/**
754
+	 * _import_events
755
+	 * This handles displaying the screen and running imports for importing events.
756
+	 *
757
+	 * @return void
758
+	 * @throws EE_Error
759
+	 */
760
+	protected function _import_events()
761
+	{
762
+		require_once(EE_CLASSES . 'EE_Import.class.php');
763
+		$success = EE_Import::instance()->import();
764
+		$this->_redirect_after_action(
765
+			$success,
766
+			esc_html__('Import File', 'event_espresso'),
767
+			'ran',
768
+			['action' => 'import_page'],
769
+			true
770
+		);
771
+	}
772
+
773
+
774
+	/**
775
+	 * _events_export
776
+	 * Will export all (or just the given event) to a Excel compatible file.
777
+	 *
778
+	 * @access protected
779
+	 * @return void
780
+	 */
781
+	protected function _events_export()
782
+	{
783
+		$EVT_ID = $this->request->getRequestParam('EVT_ID', 0, 'int');
784
+		$EVT_ID = $this->request->getRequestParam('EVT_IDs', $EVT_ID, 'int');
785
+		$this->request->mergeRequestParams(
786
+			[
787
+				'export' => 'report',
788
+				'action' => 'all_event_data',
789
+				'EVT_ID' => $EVT_ID,
790
+			]
791
+		);
792
+		if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
793
+			require_once(EE_CLASSES . 'EE_Export.class.php');
794
+			$EE_Export = EE_Export::instance($this->request->requestParams());
795
+			$EE_Export->export();
796
+		}
797
+	}
798
+
799
+
800
+	/**
801
+	 * handle category exports()
802
+	 *
803
+	 * @return void
804
+	 */
805
+	protected function _categories_export()
806
+	{
807
+		$EVT_ID = $this->request->getRequestParam('EVT_CAT_ID', 0, 'int');
808
+		$this->request->mergeRequestParams(
809
+			[
810
+				'export' => 'report',
811
+				'action' => 'categories',
812
+				'EVT_ID' => $EVT_ID,
813
+			]
814
+		);
815
+		if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
816
+			require_once(EE_CLASSES . 'EE_Export.class.php');
817
+			$EE_Export = EE_Export::instance($this->request->requestParams());
818
+			$EE_Export->export();
819
+		}
820
+	}
821
+
822
+
823
+	/**
824
+	 * Creates a sample CSV file for importing
825
+	 */
826
+	protected function _sample_export_file()
827
+	{
828
+		$EE_Export = EE_Export::instance();
829
+		if ($EE_Export instanceof EE_Export) {
830
+			$EE_Export->export();
831
+		}
832
+	}
833
+
834
+
835
+	/*************        Template Settings        *************/
836
+	/**
837
+	 * Generates template settings page output
838
+	 *
839
+	 * @throws DomainException
840
+	 * @throws EE_Error
841
+	 * @throws InvalidArgumentException
842
+	 * @throws InvalidDataTypeException
843
+	 * @throws InvalidInterfaceException
844
+	 */
845
+	protected function _template_settings()
846
+	{
847
+		$this->_template_args['values'] = $this->_yes_no_values;
848
+		/**
849
+		 * Note leaving this filter in for backward compatibility this was moved in 4.6.x
850
+		 * from General_Settings_Admin_Page to here.
851
+		 */
852
+		$this->_template_args = apply_filters(
853
+			'FHEE__General_Settings_Admin_Page__template_settings__template_args',
854
+			$this->_template_args
855
+		);
856
+		$this->_set_add_edit_form_tags('update_template_settings');
857
+		$this->_set_publish_post_box_vars(null, false, false, null, false);
858
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
859
+			EVENTS_CAF_TEMPLATE_PATH . 'template_settings.template.php',
860
+			$this->_template_args,
861
+			true
862
+		);
863
+		$this->display_admin_page_with_sidebar();
864
+	}
865
+
866
+
867
+	/**
868
+	 * Handler for updating template settings.
869
+	 *
870
+	 * @throws EE_Error
871
+	 */
872
+	protected function _update_template_settings()
873
+	{
874
+		/**
875
+		 * Note leaving this filter in for backward compatibility this was moved in 4.6.x
876
+		 * from General_Settings_Admin_Page to here.
877
+		 */
878
+		EE_Registry::instance()->CFG->template_settings = apply_filters(
879
+			'FHEE__General_Settings_Admin_Page__update_template_settings__data',
880
+			EE_Registry::instance()->CFG->template_settings,
881
+			$this->request->requestParams()
882
+		);
883
+		// update custom post type slugs and detect if we need to flush rewrite rules
884
+		$old_slug = EE_Registry::instance()->CFG->core->event_cpt_slug;
885
+
886
+		$event_cpt_slug = $this->request->getRequestParam('event_cpt_slug');
887
+
888
+		EE_Registry::instance()->CFG->core->event_cpt_slug = $event_cpt_slug
889
+			? EEH_URL::slugify($event_cpt_slug, 'events')
890
+			: EE_Registry::instance()->CFG->core->event_cpt_slug;
891
+
892
+		$what    = esc_html__('Template Settings', 'event_espresso');
893
+		$success = $this->_update_espresso_configuration(
894
+			$what,
895
+			EE_Registry::instance()->CFG->template_settings,
896
+			__FILE__,
897
+			__FUNCTION__,
898
+			__LINE__
899
+		);
900
+		if (EE_Registry::instance()->CFG->core->event_cpt_slug !== $old_slug) {
901
+			/** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
902
+			$rewrite_rules = LoaderFactory::getLoader()->getShared(
903
+				'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
904
+			);
905
+			$rewrite_rules->flush();
906
+		}
907
+		$this->_redirect_after_action($success, $what, 'updated', ['action' => 'template_settings']);
908
+	}
909
+
910
+
911
+	/**
912
+	 * _premium_event_editor_meta_boxes
913
+	 * add all metaboxes related to the event_editor
914
+	 *
915
+	 * @access protected
916
+	 * @return void
917
+	 * @throws EE_Error
918
+	 * @throws ReflectionException
919
+	 */
920
+	protected function _premium_event_editor_meta_boxes()
921
+	{
922
+		$this->verify_cpt_object();
923
+		// check if the new EDTR reg options meta box is being used, and if so, don't load the legacy version
924
+		if (
925
+			! $this->admin_config->useAdvancedEditor()
926
+			|| ! $this->feature->allowed('use_reg_options_meta_box')
927
+		) {
928
+			$this->addMetaBox(
929
+				'espresso_event_editor_event_options',
930
+				esc_html__('Event Registration Options', 'event_espresso'),
931
+				[$this, 'registration_options_meta_box'],
932
+				$this->page_slug,
933
+				'side',
934
+				'core'
935
+			);
936
+		}
937
+	}
938
+
939
+
940
+	/**
941
+	 * override caf metabox
942
+	 *
943
+	 * @return void
944
+	 * @throws EE_Error
945
+	 * @throws ReflectionException
946
+	 */
947
+	public function registration_options_meta_box()
948
+	{
949
+		$yes_no_values = [
950
+			['id' => true, 'text' => esc_html__('Yes', 'event_espresso')],
951
+			['id' => false, 'text' => esc_html__('No', 'event_espresso')],
952
+		];
953
+
954
+		$default_reg_status_values = EEM_Registration::reg_status_array(
955
+			[
956
+				EEM_Registration::status_id_cancelled,
957
+				EEM_Registration::status_id_declined,
958
+				EEM_Registration::status_id_incomplete,
959
+				EEM_Registration::status_id_wait_list,
960
+			],
961
+			true
962
+		);
963
+
964
+		$template_args['active_status']    = $this->_cpt_model_obj->pretty_active_status(false);
965
+		$template_args['_event']           = $this->_cpt_model_obj;
966
+		$template_args['additional_limit'] = $this->_cpt_model_obj->additional_limit();
967
+
968
+		$template_args['default_registration_status']     = EEH_Form_Fields::select_input(
969
+			'default_reg_status',
970
+			$default_reg_status_values,
971
+			$this->_cpt_model_obj->default_registration_status()
972
+		);
973
+		$template_args['display_description']             = EEH_Form_Fields::select_input(
974
+			'display_desc',
975
+			$yes_no_values,
976
+			$this->_cpt_model_obj->display_description()
977
+		);
978
+		$template_args['display_ticket_selector']         = EEH_Form_Fields::select_input(
979
+			'display_ticket_selector',
980
+			$yes_no_values,
981
+			$this->_cpt_model_obj->display_ticket_selector(),
982
+			'',
983
+			'',
984
+			false
985
+		);
986
+		$template_args['EVT_default_registration_status'] = EEH_Form_Fields::select_input(
987
+			'EVT_default_registration_status',
988
+			$default_reg_status_values,
989
+			$this->_cpt_model_obj->default_registration_status()
990
+		);
991
+		$template_args['additional_registration_options'] = apply_filters(
992
+			'FHEE__Events_Admin_Page__registration_options_meta_box__additional_registration_options',
993
+			'',
994
+			$template_args,
995
+			$yes_no_values,
996
+			$default_reg_status_values
997
+		);
998
+		EEH_Template::display_template(
999
+			EVENTS_CAF_TEMPLATE_PATH . 'event_registration_options.template.php',
1000
+			$template_args
1001
+		);
1002
+	}
1003
+
1004
+
1005
+
1006
+	/**
1007
+	 * wp_list_table_mods for caf
1008
+	 * ============================
1009
+	 */
1010
+	/**
1011
+	 * hook into list table filters and provide filters for caffeinated list table
1012
+	 *
1013
+	 * @param array $old_filters    any existing filters present
1014
+	 * @param array $list_table_obj the list table object
1015
+	 * @return array                  new filters
1016
+	 * @throws EE_Error
1017
+	 * @throws ReflectionException
1018
+	 */
1019
+	public function list_table_filters($old_filters, $list_table_obj)
1020
+	{
1021
+		$filters = [];
1022
+		// first month/year filters
1023
+		$filters[] = $this->espresso_event_months_dropdown();
1024
+		$status    = $this->request->getRequestParam('status');
1025
+		// active status dropdown
1026
+		if ($status !== 'draft') {
1027
+			$filters[] = $this->active_status_dropdown($this->request->getRequestParam('active_status'));
1028
+			$filters[] = $this->venuesDropdown($this->request->getRequestParam('venue'));
1029
+		}
1030
+		// category filter
1031
+		$filters[] = $this->category_dropdown();
1032
+		return array_merge($old_filters, $filters);
1033
+	}
1034
+
1035
+
1036
+	/**
1037
+	 * espresso_event_months_dropdown
1038
+	 *
1039
+	 * @access public
1040
+	 * @return string                dropdown listing month/year selections for events.
1041
+	 * @throws EE_Error
1042
+	 */
1043
+	public function espresso_event_months_dropdown()
1044
+	{
1045
+		// what we need to do is get all PRIMARY datetimes for all events to filter on.
1046
+		// Note we need to include any other filters that are set!
1047
+		return EEH_Form_Fields::generate_event_months_dropdown(
1048
+			$this->request->getRequestParam('month_range'),
1049
+			$this->request->getRequestParam('status'),
1050
+			$this->request->getRequestParam('EVT_CAT', 0, 'int'),
1051
+			$this->request->getRequestParam('active_status')
1052
+		);
1053
+	}
1054
+
1055
+
1056
+	/**
1057
+	 * returns a list of "active" statuses on the event
1058
+	 *
1059
+	 * @param string $current_value whatever the current active status is
1060
+	 * @return string
1061
+	 */
1062
+	public function active_status_dropdown($current_value = '')
1063
+	{
1064
+		$select_name = 'active_status';
1065
+		$values      = [
1066
+			'none'     => esc_html__('Show Active/Inactive', 'event_espresso'),
1067
+			'active'   => esc_html__('Active', 'event_espresso'),
1068
+			'upcoming' => esc_html__('Upcoming', 'event_espresso'),
1069
+			'expired'  => esc_html__('Expired', 'event_espresso'),
1070
+			'inactive' => esc_html__('Inactive', 'event_espresso'),
1071
+		];
1072
+
1073
+		return EEH_Form_Fields::select_input($select_name, $values, $current_value);
1074
+	}
1075
+
1076
+
1077
+	/**
1078
+	 * returns a list of "venues"
1079
+	 *
1080
+	 * @param string $current_value whatever the current active status is
1081
+	 * @return string
1082
+	 * @throws EE_Error
1083
+	 * @throws ReflectionException
1084
+	 */
1085
+	protected function venuesDropdown($current_value = '')
1086
+	{
1087
+		$values = ['' => esc_html__('All Venues', 'event_espresso')];
1088
+		// populate the list of venues.
1089
+		$venues = EEM_Venue::instance()->get_all(['order_by' => ['VNU_name' => 'ASC']]);
1090
+
1091
+		foreach ($venues as $venue) {
1092
+			$values[ $venue->ID() ] = $venue->name();
1093
+		}
1094
+
1095
+		return EEH_Form_Fields::select_input('venue', $values, $current_value);
1096
+	}
1097
+
1098
+
1099
+	/**
1100
+	 * output a dropdown of the categories for the category filter on the event admin list table
1101
+	 *
1102
+	 * @access  public
1103
+	 * @return string html
1104
+	 * @throws EE_Error
1105
+	 * @throws ReflectionException
1106
+	 */
1107
+	public function category_dropdown()
1108
+	{
1109
+		return EEH_Form_Fields::generate_event_category_dropdown(
1110
+			$this->request->getRequestParam('EVT_CAT', -1, 'int')
1111
+		);
1112
+	}
1113
+
1114
+
1115
+	/**
1116
+	 * get total number of events today
1117
+	 *
1118
+	 * @access public
1119
+	 * @return int
1120
+	 * @throws EE_Error
1121
+	 * @throws InvalidArgumentException
1122
+	 * @throws InvalidDataTypeException
1123
+	 * @throws InvalidInterfaceException
1124
+	 */
1125
+	public function total_events_today()
1126
+	{
1127
+		$start = EEM_Datetime::instance()->convert_datetime_for_query(
1128
+			'DTT_EVT_start',
1129
+			date('Y-m-d') . ' 00:00:00',
1130
+			'Y-m-d H:i:s',
1131
+			'UTC'
1132
+		);
1133
+		$end   = EEM_Datetime::instance()->convert_datetime_for_query(
1134
+			'DTT_EVT_start',
1135
+			date('Y-m-d') . ' 23:59:59',
1136
+			'Y-m-d H:i:s',
1137
+			'UTC'
1138
+		);
1139
+		$where = [
1140
+			'Datetime.DTT_EVT_start' => ['BETWEEN', [$start, $end]],
1141
+		];
1142
+		return EEM_Event::instance()->count([$where, 'caps' => 'read_admin'], 'EVT_ID', true);
1143
+	}
1144
+
1145
+
1146
+	/**
1147
+	 * get total number of events this month
1148
+	 *
1149
+	 * @access public
1150
+	 * @return int
1151
+	 * @throws EE_Error
1152
+	 * @throws InvalidArgumentException
1153
+	 * @throws InvalidDataTypeException
1154
+	 * @throws InvalidInterfaceException
1155
+	 */
1156
+	public function total_events_this_month()
1157
+	{
1158
+		// Dates
1159
+		$this_year_r     = date('Y');
1160
+		$this_month_r    = date('m');
1161
+		$days_this_month = date('t');
1162
+		$start           = EEM_Datetime::instance()->convert_datetime_for_query(
1163
+			'DTT_EVT_start',
1164
+			$this_year_r . '-' . $this_month_r . '-01 00:00:00',
1165
+			'Y-m-d H:i:s',
1166
+			'UTC'
1167
+		);
1168
+		$end             = EEM_Datetime::instance()->convert_datetime_for_query(
1169
+			'DTT_EVT_start',
1170
+			$this_year_r . '-' . $this_month_r . '-' . $days_this_month . ' 23:59:59',
1171
+			'Y-m-d H:i:s',
1172
+			'UTC'
1173
+		);
1174
+		$where           = [
1175
+			'Datetime.DTT_EVT_start' => ['BETWEEN', [$start, $end]],
1176
+		];
1177
+		return EEM_Event::instance()->count([$where, 'caps' => 'read_admin'], 'EVT_ID', true);
1178
+	}
1179
+
1180
+
1181
+	/** DEFAULT TICKETS STUFF **/
1182
+
1183
+	/**
1184
+	 * Output default tickets list table view.
1185
+	 *
1186
+	 * @throws EE_Error
1187
+	 */
1188
+	public function _tickets_overview_list_table()
1189
+	{
1190
+		if (
1191
+			$this->admin_config->useAdvancedEditor()
1192
+			&& $this->feature->allowed('use_default_ticket_manager')
1193
+		) {
1194
+			// check if the new EDTR reg options meta box is being used, and if so, don't load the legacy version
1195
+			$this->_template_args['admin_page_content'] = EEH_Template::display_template(
1196
+				EVENTS_CAF_TEMPLATE_PATH . 'default_tickets_moved_notice.template.php',
1197
+				[],
1198
+				true
1199
+			);
1200
+			$this->display_admin_page_with_no_sidebar();
1201
+		} else {
1202
+			$this->_search_btn_label = esc_html__('Tickets', 'event_espresso');
1203
+			$this->display_admin_list_table_page_with_no_sidebar();
1204
+		}
1205
+	}
1206
+
1207
+
1208
+	/**
1209
+	 * @param int  $per_page
1210
+	 * @param bool $count
1211
+	 * @param bool $trashed
1212
+	 * @return EE_Soft_Delete_Base_Class[]|int
1213
+	 * @throws EE_Error
1214
+	 */
1215
+	public function get_default_tickets($per_page = 10, $count = false, $trashed = false)
1216
+	{
1217
+		$orderby = $this->request->getRequestParam('orderby', 'TKT_name');
1218
+		$order   = $this->request->getRequestParam('order', 'ASC');
1219
+		switch ($orderby) {
1220
+			case 'TKT_name':
1221
+				$orderby = ['TKT_name' => $order];
1222
+				break;
1223
+			case 'TKT_price':
1224
+				$orderby = ['TKT_price' => $order];
1225
+				break;
1226
+			case 'TKT_uses':
1227
+				$orderby = ['TKT_uses' => $order];
1228
+				break;
1229
+			case 'TKT_min':
1230
+				$orderby = ['TKT_min' => $order];
1231
+				break;
1232
+			case 'TKT_max':
1233
+				$orderby = ['TKT_max' => $order];
1234
+				break;
1235
+			case 'TKT_qty':
1236
+				$orderby = ['TKT_qty' => $order];
1237
+				break;
1238
+		}
1239
+
1240
+		$current_page = $this->request->getRequestParam('paged', 1, 'int');
1241
+		$per_page     = $this->request->getRequestParam('perpage', $per_page, 'int');
1242
+		$offset       = ($current_page - 1) * $per_page;
1243
+
1244
+		$where = [
1245
+			'TKT_is_default' => 1,
1246
+			'TKT_deleted'    => $trashed,
1247
+		];
1248
+
1249
+		$search_term = $this->request->getRequestParam('s');
1250
+		if ($search_term) {
1251
+			$search_term = '%' . $search_term . '%';
1252
+			$where['OR'] = [
1253
+				'TKT_name'        => ['LIKE', $search_term],
1254
+				'TKT_description' => ['LIKE', $search_term],
1255
+			];
1256
+		}
1257
+
1258
+		return $count
1259
+			? EEM_Ticket::instance()->count_deleted_and_undeleted([$where])
1260
+			: EEM_Ticket::instance()->get_all_deleted_and_undeleted(
1261
+				[
1262
+					$where,
1263
+					'order_by' => $orderby,
1264
+					'limit'    => [$offset, $per_page],
1265
+					'group_by' => 'TKT_ID',
1266
+				]
1267
+			);
1268
+	}
1269
+
1270
+
1271
+	/**
1272
+	 * @param bool $trash
1273
+	 * @throws EE_Error
1274
+	 * @throws InvalidArgumentException
1275
+	 * @throws InvalidDataTypeException
1276
+	 * @throws InvalidInterfaceException
1277
+	 */
1278
+	protected function _trash_or_restore_ticket($trash = false)
1279
+	{
1280
+		$success = 1;
1281
+		$TKT     = EEM_Ticket::instance();
1282
+		// checkboxes?
1283
+		$checkboxes = $this->request->getRequestParam('checkbox', [], 'int', true);
1284
+		if (! empty($checkboxes)) {
1285
+			// if array has more than one element then success message should be plural
1286
+			$success = count($checkboxes) > 1 ? 2 : 1;
1287
+			// cycle thru the boxes
1288
+			while (list($TKT_ID, $value) = each($checkboxes)) {
1289
+				if ($trash) {
1290
+					if (! $TKT->delete_by_ID($TKT_ID)) {
1291
+						$success = 0;
1292
+					}
1293
+				} elseif (! $TKT->restore_by_ID($TKT_ID)) {
1294
+					$success = 0;
1295
+				}
1296
+			}
1297
+		} else {
1298
+			// grab single id and trash
1299
+			$TKT_ID = $this->request->getRequestParam('TKT_ID', 0, 'int');
1300
+			if ($trash) {
1301
+				if (! $TKT->delete_by_ID($TKT_ID)) {
1302
+					$success = 0;
1303
+				}
1304
+			} elseif (! $TKT->restore_by_ID($TKT_ID)) {
1305
+				$success = 0;
1306
+			}
1307
+		}
1308
+		$action_desc = $trash ? 'moved to the trash' : 'restored';
1309
+		$query_args  = [
1310
+			'action' => 'ticket_list_table',
1311
+			'status' => $trash ? '' : 'trashed',
1312
+		];
1313
+		$this->_redirect_after_action($success, esc_html__('Tickets', 'event_espresso'), $action_desc, $query_args);
1314
+	}
1315
+
1316
+
1317
+	/**
1318
+	 * Handles trashing default ticket.
1319
+	 *
1320
+	 * @throws EE_Error
1321
+	 * @throws ReflectionException
1322
+	 */
1323
+	protected function _delete_ticket()
1324
+	{
1325
+		$success = 1;
1326
+		// checkboxes?
1327
+		$checkboxes = $this->request->getRequestParam('checkbox', [], 'int', true);
1328
+		if (! empty($checkboxes)) {
1329
+			// if array has more than one element then success message should be plural
1330
+			$success = count($checkboxes) > 1 ? 2 : 1;
1331
+			// cycle thru the boxes
1332
+			while (list($TKT_ID, $value) = each($checkboxes)) {
1333
+				// delete
1334
+				if (! $this->_delete_the_ticket($TKT_ID)) {
1335
+					$success = 0;
1336
+				}
1337
+			}
1338
+		} else {
1339
+			// grab single id and trash
1340
+			$TKT_ID = $this->request->getRequestParam('TKT_ID', 0, 'int');
1341
+			if (! $this->_delete_the_ticket($TKT_ID)) {
1342
+				$success = 0;
1343
+			}
1344
+		}
1345
+		$action_desc = 'deleted';
1346
+		$query_args  = [
1347
+			'action' => 'ticket_list_table',
1348
+			'status' => 'trashed',
1349
+		];
1350
+		// fail safe.  If the default ticket count === 1 then we need to redirect to event overview.
1351
+		if (
1352
+			EEM_Ticket::instance()->count_deleted_and_undeleted(
1353
+				[['TKT_is_default' => 1]],
1354
+				'TKT_ID',
1355
+				true
1356
+			)
1357
+		) {
1358
+			$query_args = [];
1359
+		}
1360
+		$this->_redirect_after_action($success, esc_html__('Tickets', 'event_espresso'), $action_desc, $query_args);
1361
+	}
1362
+
1363
+
1364
+	/**
1365
+	 * @param int $TKT_ID
1366
+	 * @return bool|int
1367
+	 * @throws EE_Error
1368
+	 * @throws ReflectionException
1369
+	 */
1370
+	protected function _delete_the_ticket($TKT_ID)
1371
+	{
1372
+		$ticket = EEM_Ticket::instance()->get_one_by_ID($TKT_ID);
1373
+		if (! $ticket instanceof EE_Ticket) {
1374
+			return false;
1375
+		}
1376
+		$ticket->_remove_relations('Datetime');
1377
+		// delete all related prices first
1378
+		$ticket->delete_related_permanently('Price');
1379
+		return $ticket->delete_permanently();
1380
+	}
1381 1381
 }
Please login to merge, or discard this patch.