Completed
Branch dev (fc935c)
by
unknown
22:17 queued 15:01
created
admin_pages/events/Events_Admin_Page.core.php 1 patch
Indentation   +2907 added lines, -2907 removed lines patch added patch discarded remove patch
@@ -16,2914 +16,2914 @@
 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
+					'order' => 10,
270
+				],
271
+				'list_table'    => 'Events_Admin_List_Table',
272
+				'help_tabs'     => [
273
+					'events_overview_help_tab'                       => [
274
+						'title'    => esc_html__('Events Overview', 'event_espresso'),
275
+						'filename' => 'events_overview',
276
+					],
277
+					'events_overview_table_column_headings_help_tab' => [
278
+						'title'    => esc_html__('Events Overview Table Column Headings', 'event_espresso'),
279
+						'filename' => 'events_overview_table_column_headings',
280
+					],
281
+					'events_overview_filters_help_tab'               => [
282
+						'title'    => esc_html__('Events Overview Filters', 'event_espresso'),
283
+						'filename' => 'events_overview_filters',
284
+					],
285
+					'events_overview_view_help_tab'                  => [
286
+						'title'    => esc_html__('Events Overview Views', 'event_espresso'),
287
+						'filename' => 'events_overview_views',
288
+					],
289
+					'events_overview_other_help_tab'                 => [
290
+						'title'    => esc_html__('Events Overview Other', 'event_espresso'),
291
+						'filename' => 'events_overview_other',
292
+					],
293
+				],
294
+				'require_nonce' => false,
295
+			],
296
+			'create_new'             => [
297
+				'nav'           => [
298
+					'label'      => esc_html__('Add New Event', 'event_espresso'),
299
+					'order'      => 5,
300
+					'persistent' => false,
301
+				],
302
+				'metaboxes'     => ['_register_event_editor_meta_boxes'],
303
+				'help_tabs'     => [
304
+					'event_editor_help_tab'                            => [
305
+						'title'    => esc_html__('Event Editor', 'event_espresso'),
306
+						'filename' => 'event_editor',
307
+					],
308
+					'event_editor_title_richtexteditor_help_tab'       => [
309
+						'title'    => esc_html__('Event Title & Rich Text Editor', 'event_espresso'),
310
+						'filename' => 'event_editor_title_richtexteditor',
311
+					],
312
+					'event_editor_venue_details_help_tab'              => [
313
+						'title'    => esc_html__('Event Venue Details', 'event_espresso'),
314
+						'filename' => 'event_editor_venue_details',
315
+					],
316
+					'event_editor_event_datetimes_help_tab'            => [
317
+						'title'    => esc_html__('Event Datetimes', 'event_espresso'),
318
+						'filename' => 'event_editor_event_datetimes',
319
+					],
320
+					'event_editor_event_tickets_help_tab'              => [
321
+						'title'    => esc_html__('Event Tickets', 'event_espresso'),
322
+						'filename' => 'event_editor_event_tickets',
323
+					],
324
+					'event_editor_event_registration_options_help_tab' => [
325
+						'title'    => esc_html__('Event Registration Options', 'event_espresso'),
326
+						'filename' => 'event_editor_event_registration_options',
327
+					],
328
+					'event_editor_tags_categories_help_tab'            => [
329
+						'title'    => esc_html__('Event Tags & Categories', 'event_espresso'),
330
+						'filename' => 'event_editor_tags_categories',
331
+					],
332
+					'event_editor_questions_registrants_help_tab'      => [
333
+						'title'    => esc_html__('Questions for Registrants', 'event_espresso'),
334
+						'filename' => 'event_editor_questions_registrants',
335
+					],
336
+					'event_editor_save_new_event_help_tab'             => [
337
+						'title'    => esc_html__('Save New Event', 'event_espresso'),
338
+						'filename' => 'event_editor_save_new_event',
339
+					],
340
+					'event_editor_other_help_tab'                      => [
341
+						'title'    => esc_html__('Event Other', 'event_espresso'),
342
+						'filename' => 'event_editor_other',
343
+					],
344
+				],
345
+				'qtips'         => ['EE_Event_Editor_Decaf_Tips'],
346
+				'require_nonce' => false,
347
+			],
348
+			'edit'                   => [
349
+				'nav'           => [
350
+					'label'      => esc_html__('Edit Event', 'event_espresso'),
351
+					'order'      => 5,
352
+					'persistent' => false,
353
+					'url'        => $post_id
354
+						? EE_Admin_Page::add_query_args_and_nonce(
355
+							['post' => $post_id, 'action' => 'edit'],
356
+							$this->_current_page_view_url
357
+						)
358
+						: $this->_admin_base_url,
359
+				],
360
+				'metaboxes'     => ['_register_event_editor_meta_boxes'],
361
+				'help_tabs'     => [
362
+					'event_editor_help_tab'                            => [
363
+						'title'    => esc_html__('Event Editor', 'event_espresso'),
364
+						'filename' => 'event_editor',
365
+					],
366
+					'event_editor_title_richtexteditor_help_tab'       => [
367
+						'title'    => esc_html__('Event Title & Rich Text Editor', 'event_espresso'),
368
+						'filename' => 'event_editor_title_richtexteditor',
369
+					],
370
+					'event_editor_venue_details_help_tab'              => [
371
+						'title'    => esc_html__('Event Venue Details', 'event_espresso'),
372
+						'filename' => 'event_editor_venue_details',
373
+					],
374
+					'event_editor_event_datetimes_help_tab'            => [
375
+						'title'    => esc_html__('Event Datetimes', 'event_espresso'),
376
+						'filename' => 'event_editor_event_datetimes',
377
+					],
378
+					'event_editor_event_tickets_help_tab'              => [
379
+						'title'    => esc_html__('Event Tickets', 'event_espresso'),
380
+						'filename' => 'event_editor_event_tickets',
381
+					],
382
+					'event_editor_event_registration_options_help_tab' => [
383
+						'title'    => esc_html__('Event Registration Options', 'event_espresso'),
384
+						'filename' => 'event_editor_event_registration_options',
385
+					],
386
+					'event_editor_tags_categories_help_tab'            => [
387
+						'title'    => esc_html__('Event Tags & Categories', 'event_espresso'),
388
+						'filename' => 'event_editor_tags_categories',
389
+					],
390
+					'event_editor_questions_registrants_help_tab'      => [
391
+						'title'    => esc_html__('Questions for Registrants', 'event_espresso'),
392
+						'filename' => 'event_editor_questions_registrants',
393
+					],
394
+					'event_editor_save_new_event_help_tab'             => [
395
+						'title'    => esc_html__('Save New Event', 'event_espresso'),
396
+						'filename' => 'event_editor_save_new_event',
397
+					],
398
+					'event_editor_other_help_tab'                      => [
399
+						'title'    => esc_html__('Event Other', 'event_espresso'),
400
+						'filename' => 'event_editor_other',
401
+					],
402
+				],
403
+				'require_nonce' => false,
404
+			],
405
+			'default_event_settings' => [
406
+				'nav'           => [
407
+					'label' => esc_html__('Default Settings', 'event_espresso'),
408
+					'order' => 40,
409
+				],
410
+				'metaboxes'     => array_merge($this->_default_espresso_metaboxes, ['_publish_post_box']),
411
+				'labels'        => [
412
+					'publishbox' => esc_html__('Update Settings', 'event_espresso'),
413
+				],
414
+				'help_tabs'     => [
415
+					'default_settings_help_tab'        => [
416
+						'title'    => esc_html__('Default Event Settings', 'event_espresso'),
417
+						'filename' => 'events_default_settings',
418
+					],
419
+					'default_settings_status_help_tab' => [
420
+						'title'    => esc_html__('Default Registration Status', 'event_espresso'),
421
+						'filename' => 'events_default_settings_status',
422
+					],
423
+					'default_maximum_tickets_help_tab' => [
424
+						'title'    => esc_html__('Default Maximum Tickets Per Order', 'event_espresso'),
425
+						'filename' => 'events_default_settings_max_tickets',
426
+					],
427
+				],
428
+				'require_nonce' => false,
429
+			],
430
+			// template settings
431
+			'template_settings'      => [
432
+				'nav'           => [
433
+					'label' => esc_html__('Templates', 'event_espresso'),
434
+					'order' => 30,
435
+				],
436
+				'metaboxes'     => $this->_default_espresso_metaboxes,
437
+				'help_tabs'     => [
438
+					'general_settings_templates_help_tab' => [
439
+						'title'    => esc_html__('Templates', 'event_espresso'),
440
+						'filename' => 'general_settings_templates',
441
+					],
442
+				],
443
+				'require_nonce' => false,
444
+			],
445
+			// event category stuff
446
+			'add_category'           => [
447
+				'nav'           => [
448
+					'label'      => esc_html__('Add Category', 'event_espresso'),
449
+					'order'      => 15,
450
+					'persistent' => false,
451
+				],
452
+				'help_tabs'     => [
453
+					'add_category_help_tab' => [
454
+						'title'    => esc_html__('Add New Event Category', 'event_espresso'),
455
+						'filename' => 'events_add_category',
456
+					],
457
+				],
458
+				'metaboxes'     => ['_publish_post_box'],
459
+				'require_nonce' => false,
460
+			],
461
+			'edit_category'          => [
462
+				'nav'           => [
463
+					'label'      => esc_html__('Edit Category', 'event_espresso'),
464
+					'order'      => 15,
465
+					'persistent' => false,
466
+					'url'        => $EVT_CAT_ID
467
+						? add_query_arg(
468
+							['EVT_CAT_ID' => $EVT_CAT_ID],
469
+							$this->_current_page_view_url
470
+						)
471
+						: $this->_admin_base_url,
472
+				],
473
+				'help_tabs'     => [
474
+					'edit_category_help_tab' => [
475
+						'title'    => esc_html__('Edit Event Category', 'event_espresso'),
476
+						'filename' => 'events_edit_category',
477
+					],
478
+				],
479
+				'metaboxes'     => ['_publish_post_box'],
480
+				'require_nonce' => false,
481
+			],
482
+			'category_list'          => [
483
+				'nav'           => [
484
+					'label' => esc_html__('Categories', 'event_espresso'),
485
+					'order' => 20,
486
+				],
487
+				'list_table'    => 'Event_Categories_Admin_List_Table',
488
+				'help_tabs'     => [
489
+					'events_categories_help_tab'                       => [
490
+						'title'    => esc_html__('Event Categories', 'event_espresso'),
491
+						'filename' => 'events_categories',
492
+					],
493
+					'events_categories_table_column_headings_help_tab' => [
494
+						'title'    => esc_html__('Event Categories Table Column Headings', 'event_espresso'),
495
+						'filename' => 'events_categories_table_column_headings',
496
+					],
497
+					'events_categories_view_help_tab'                  => [
498
+						'title'    => esc_html__('Event Categories Views', 'event_espresso'),
499
+						'filename' => 'events_categories_views',
500
+					],
501
+					'events_categories_other_help_tab'                 => [
502
+						'title'    => esc_html__('Event Categories Other', 'event_espresso'),
503
+						'filename' => 'events_categories_other',
504
+					],
505
+				],
506
+				'metaboxes'     => $this->_default_espresso_metaboxes,
507
+				'require_nonce' => false,
508
+			],
509
+			'preview_deletion'       => [
510
+				'nav'           => [
511
+					'label'      => esc_html__('Preview Deletion', 'event_espresso'),
512
+					'order'      => 15,
513
+					'persistent' => false,
514
+					'url'        => '',
515
+				],
516
+				'require_nonce' => false,
517
+			],
518
+		];
519
+	}
520
+
521
+
522
+	/**
523
+	 * Used to register any global screen options if necessary for every route in this admin page group.
524
+	 */
525
+	protected function _add_screen_options()
526
+	{
527
+	}
528
+
529
+
530
+	/**
531
+	 * Implementing the screen options for the 'default' route.
532
+	 *
533
+	 * @throws InvalidArgumentException
534
+	 * @throws InvalidDataTypeException
535
+	 * @throws InvalidInterfaceException
536
+	 */
537
+	protected function _add_screen_options_default()
538
+	{
539
+		$this->_per_page_screen_option();
540
+	}
541
+
542
+
543
+	/**
544
+	 * Implementing screen options for the category list route.
545
+	 *
546
+	 * @throws InvalidArgumentException
547
+	 * @throws InvalidDataTypeException
548
+	 * @throws InvalidInterfaceException
549
+	 */
550
+	protected function _add_screen_options_category_list()
551
+	{
552
+		$page_title              = $this->_admin_page_title;
553
+		$this->_admin_page_title = esc_html__('Categories', 'event_espresso');
554
+		$this->_per_page_screen_option();
555
+		$this->_admin_page_title = $page_title;
556
+	}
557
+
558
+
559
+	/**
560
+	 * Used to register any global feature pointers for the admin page group.
561
+	 */
562
+	protected function _add_feature_pointers()
563
+	{
564
+	}
565
+
566
+
567
+	/**
568
+	 * Registers and enqueues any global scripts and styles for the entire admin page group.
569
+	 */
570
+	public function load_scripts_styles()
571
+	{
572
+		wp_register_style(
573
+			'events-admin-css',
574
+			EVENTS_ASSETS_URL . 'events-admin-page.css',
575
+			[],
576
+			EVENT_ESPRESSO_VERSION
577
+		);
578
+		wp_register_style(
579
+			'ee-cat-admin',
580
+			EVENTS_ASSETS_URL . 'ee-cat-admin.css',
581
+			[],
582
+			EVENT_ESPRESSO_VERSION
583
+		);
584
+		wp_enqueue_style('events-admin-css');
585
+		wp_enqueue_style('ee-cat-admin');
586
+		// scripts
587
+		wp_register_script(
588
+			'event_editor_js',
589
+			EVENTS_ASSETS_URL . 'event_editor.js',
590
+			['ee_admin_js', 'jquery-ui-slider', 'jquery-ui-timepicker-addon'],
591
+			EVENT_ESPRESSO_VERSION,
592
+			true
593
+		);
594
+	}
595
+
596
+
597
+	/**
598
+	 * Enqueuing scripts and styles specific to this view
599
+	 */
600
+	public function load_scripts_styles_create_new()
601
+	{
602
+		$this->load_scripts_styles_edit();
603
+	}
604
+
605
+
606
+	/**
607
+	 * Enqueuing scripts and styles specific to this view
608
+	 */
609
+	public function load_scripts_styles_edit()
610
+	{
611
+		// styles
612
+		wp_enqueue_style('espresso-ui-theme');
613
+		wp_register_style(
614
+			'event-editor-css',
615
+			EVENTS_ASSETS_URL . 'event-editor.css',
616
+			['ee-admin-css'],
617
+			EVENT_ESPRESSO_VERSION
618
+		);
619
+		wp_enqueue_style('event-editor-css');
620
+		// scripts
621
+		if (! $this->admin_config->useAdvancedEditor()) {
622
+			wp_register_script(
623
+				'event-datetime-metabox',
624
+				EVENTS_ASSETS_URL . 'event-datetime-metabox.js',
625
+				['event_editor_js', 'ee-datepicker'],
626
+				EVENT_ESPRESSO_VERSION
627
+			);
628
+			wp_enqueue_script('event-datetime-metabox');
629
+		}
630
+	}
631
+
632
+
633
+	/**
634
+	 * Populating the _views property for the category list table view.
635
+	 */
636
+	protected function _set_list_table_views_category_list()
637
+	{
638
+		$this->_views = [
639
+			'all' => [
640
+				'slug'        => 'all',
641
+				'label'       => esc_html__('All', 'event_espresso'),
642
+				'count'       => 0,
643
+				'bulk_action' => [
644
+					'delete_categories' => esc_html__('Delete Permanently', 'event_espresso'),
645
+				],
646
+			],
647
+		];
648
+	}
649
+
650
+
651
+	/**
652
+	 * For adding anything that fires on the admin_init hook for any route within this admin page group.
653
+	 */
654
+	public function admin_init()
655
+	{
656
+		EE_Registry::$i18n_js_strings['image_confirm'] = esc_html__(
657
+			'Do you really want to delete this image? Please remember to update your event to complete the removal.',
658
+			'event_espresso'
659
+		);
660
+	}
661
+
662
+
663
+	/**
664
+	 * For adding anything that should be triggered on the admin_notices hook for any route within this admin page
665
+	 * group.
666
+	 */
667
+	public function admin_notices()
668
+	{
669
+	}
670
+
671
+
672
+	/**
673
+	 * For adding anything that should be triggered on the `admin_print_footer_scripts` hook for any route within
674
+	 * this admin page group.
675
+	 */
676
+	public function admin_footer_scripts()
677
+	{
678
+	}
679
+
680
+
681
+	/**
682
+	 * Call this function to verify if an event is public and has tickets for sale.  If it does, then we need to show a
683
+	 * warning (via EE_Error::add_error());
684
+	 *
685
+	 * @param EE_Event $event Event object
686
+	 * @param string   $req_type
687
+	 * @return void
688
+	 * @throws EE_Error
689
+	 * @throws ReflectionException
690
+	 */
691
+	public function verify_event_edit($event = null, $req_type = '')
692
+	{
693
+		// don't need to do this when processing
694
+		if (! empty($req_type)) {
695
+			return;
696
+		}
697
+		// no event?
698
+		if (! $event instanceof EE_Event) {
699
+			$event = $this->_cpt_model_obj;
700
+		}
701
+		// STILL no event?
702
+		if (! $event instanceof EE_Event) {
703
+			return;
704
+		}
705
+		$orig_status = $event->status();
706
+		// first check if event is active.
707
+		if (
708
+			$orig_status === EEM_Event::cancelled
709
+			|| $orig_status === EEM_Event::postponed
710
+			|| $event->is_expired()
711
+			|| $event->is_inactive()
712
+		) {
713
+			return;
714
+		}
715
+		// made it here so it IS active... next check that any of the tickets are sold.
716
+		if ($event->is_sold_out(true)) {
717
+			if ($orig_status !== EEM_Event::sold_out && $event->status() !== $orig_status) {
718
+				EE_Error::add_attention(
719
+					sprintf(
720
+						esc_html__(
721
+							'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.',
722
+							'event_espresso'
723
+						),
724
+						EEH_Template::pretty_status(EEM_Event::sold_out, false, 'sentence')
725
+					)
726
+				);
727
+			}
728
+			return;
729
+		}
730
+		if ($orig_status === EEM_Event::sold_out) {
731
+			EE_Error::add_attention(
732
+				sprintf(
733
+					esc_html__(
734
+						'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.',
735
+						'event_espresso'
736
+					),
737
+					EEH_Template::pretty_status($event->status(), false, 'sentence')
738
+				)
739
+			);
740
+		}
741
+		// now we need to determine if the event has any tickets on sale.  If not then we dont' show the error
742
+		if (! $event->tickets_on_sale()) {
743
+			return;
744
+		}
745
+		// made it here so show warning
746
+		$this->_edit_event_warning();
747
+	}
748
+
749
+
750
+	/**
751
+	 * This is the text used for when an event is being edited that is public and has tickets for sale.
752
+	 * When needed, hook this into a EE_Error::add_error() notice.
753
+	 *
754
+	 * @access protected
755
+	 * @return void
756
+	 */
757
+	protected function _edit_event_warning()
758
+	{
759
+		// we don't want to add warnings during these requests
760
+		if ($this->request->getRequestParam('action') === 'editpost') {
761
+			return;
762
+		}
763
+		EE_Error::add_attention(
764
+			sprintf(
765
+				esc_html__(
766
+					'Your event is open for registration. Making changes may disrupt any transactions in progress. %sLearn more%s',
767
+					'event_espresso'
768
+				),
769
+				'<a class="espresso-help-tab-lnk ee-help-tab-link">',
770
+				'</a>'
771
+			)
772
+		);
773
+	}
774
+
775
+
776
+	/**
777
+	 * When a user is creating a new event, notify them if they haven't set their timezone.
778
+	 * Otherwise, do the normal logic
779
+	 *
780
+	 * @return void
781
+	 * @throws EE_Error
782
+	 * @throws InvalidArgumentException
783
+	 * @throws InvalidDataTypeException
784
+	 * @throws InvalidInterfaceException
785
+	 */
786
+	protected function _create_new_cpt_item()
787
+	{
788
+		$has_timezone_string = get_option('timezone_string');
789
+		// only nag them about setting their timezone if it's their first event, and they haven't already done it
790
+		if (! $has_timezone_string && ! EEM_Event::instance()->exists([])) {
791
+			EE_Error::add_attention(
792
+				sprintf(
793
+					esc_html__(
794
+						'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',
795
+						'event_espresso'
796
+					),
797
+					'<br>',
798
+					'<select id="timezone_string" name="timezone_string" aria-describedby="timezone-description">'
799
+					. EEH_DTT_Helper::wp_timezone_choice('', EEH_DTT_Helper::get_user_locale())
800
+					. '</select>',
801
+					'<button class="button button--secondary timezone-submit">',
802
+					'</button><span class="spinner"></span>'
803
+				),
804
+				__FILE__,
805
+				__FUNCTION__,
806
+				__LINE__
807
+			);
808
+		}
809
+		parent::_create_new_cpt_item();
810
+	}
811
+
812
+
813
+	/**
814
+	 * Sets the _views property for the default route in this admin page group.
815
+	 */
816
+	protected function _set_list_table_views_default()
817
+	{
818
+		$this->_views = [
819
+			'all'   => [
820
+				'slug'        => 'all',
821
+				'label'       => esc_html__('View All Events', 'event_espresso'),
822
+				'count'       => 0,
823
+				'bulk_action' => [
824
+					'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
825
+				],
826
+			],
827
+			'draft' => [
828
+				'slug'        => 'draft',
829
+				'label'       => esc_html__('Draft', 'event_espresso'),
830
+				'count'       => 0,
831
+				'bulk_action' => [
832
+					'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
833
+				],
834
+			],
835
+		];
836
+		if (EE_Registry::instance()->CAP->current_user_can('ee_delete_events', 'espresso_events_trash_events')) {
837
+			$this->_views['trash'] = [
838
+				'slug'        => 'trash',
839
+				'label'       => esc_html__('Trash', 'event_espresso'),
840
+				'count'       => 0,
841
+				'bulk_action' => [
842
+					'restore_events' => esc_html__('Restore From Trash', 'event_espresso'),
843
+					'delete_events'  => esc_html__('Delete Permanently', 'event_espresso'),
844
+				],
845
+			];
846
+		}
847
+	}
848
+
849
+
850
+	/**
851
+	 * Provides the legend item array for the default list table view.
852
+	 *
853
+	 * @return array
854
+	 * @throws EE_Error
855
+	 * @throws EE_Error
856
+	 */
857
+	protected function _event_legend_items()
858
+	{
859
+		$items    = [
860
+			'view_details'   => [
861
+				'class' => 'dashicons dashicons-visibility',
862
+				'desc'  => esc_html__('View Event', 'event_espresso'),
863
+			],
864
+			'edit_event'     => [
865
+				'class' => 'dashicons dashicons-calendar-alt',
866
+				'desc'  => esc_html__('Edit Event Details', 'event_espresso'),
867
+			],
868
+			'view_attendees' => [
869
+				'class' => 'dashicons dashicons-groups',
870
+				'desc'  => esc_html__('View Registrations for Event', 'event_espresso'),
871
+			],
872
+		];
873
+		$items    = apply_filters('FHEE__Events_Admin_Page___event_legend_items__items', $items);
874
+		$statuses = [
875
+			'sold_out_status'  => [
876
+				'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::sold_out,
877
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::sold_out, false, 'sentence'),
878
+			],
879
+			'active_status'    => [
880
+				'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::active,
881
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::active, false, 'sentence'),
882
+			],
883
+			'upcoming_status'  => [
884
+				'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::upcoming,
885
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::upcoming, false, 'sentence'),
886
+			],
887
+			'postponed_status' => [
888
+				'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::postponed,
889
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::postponed, false, 'sentence'),
890
+			],
891
+			'cancelled_status' => [
892
+				'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::cancelled,
893
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::cancelled, false, 'sentence'),
894
+			],
895
+			'expired_status'   => [
896
+				'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::expired,
897
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::expired, false, 'sentence'),
898
+			],
899
+			'inactive_status'  => [
900
+				'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::inactive,
901
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::inactive, false, 'sentence'),
902
+			],
903
+		];
904
+		$statuses = apply_filters('FHEE__Events_Admin_Page__event_legend_items__statuses', $statuses);
905
+		return array_merge($items, $statuses);
906
+	}
907
+
908
+
909
+	/**
910
+	 * @return EEM_Event
911
+	 * @throws EE_Error
912
+	 * @throws InvalidArgumentException
913
+	 * @throws InvalidDataTypeException
914
+	 * @throws InvalidInterfaceException
915
+	 * @throws ReflectionException
916
+	 */
917
+	private function _event_model()
918
+	{
919
+		if (! $this->_event_model instanceof EEM_Event) {
920
+			$this->_event_model = EE_Registry::instance()->load_model('Event');
921
+		}
922
+		return $this->_event_model;
923
+	}
924
+
925
+
926
+	/**
927
+	 * Adds extra buttons to the WP CPT permalink field row.
928
+	 * Method is called from parent and is hooked into the wp 'get_sample_permalink_html' filter.
929
+	 *
930
+	 * @param string $return    the current html
931
+	 * @param int    $id        the post id for the page
932
+	 * @param string $new_title What the title is
933
+	 * @param string $new_slug  what the slug is
934
+	 * @return string            The new html string for the permalink area
935
+	 */
936
+	public function extra_permalink_field_buttons($return, $id, $new_title, $new_slug)
937
+	{
938
+		// make sure this is only when editing
939
+		if (! empty($id)) {
940
+			$post = get_post($id);
941
+			$return .= '<a class="button button--small button--secondary" onclick="prompt(\'Shortcode:\', jQuery(\'#shortcode\').val()); return false;" href="#"  tabindex="-1">'
942
+					   . esc_html__('Shortcode', 'event_espresso')
943
+					   . '</a> ';
944
+			$return .= '<input id="shortcode" type="hidden" value="[ESPRESSO_TICKET_SELECTOR event_id='
945
+					   . $post->ID
946
+					   . ']">';
947
+		}
948
+		return $return;
949
+	}
950
+
951
+
952
+	/**
953
+	 * _events_overview_list_table
954
+	 * This contains the logic for showing the events_overview list
955
+	 *
956
+	 * @access protected
957
+	 * @return void
958
+	 * @throws DomainException
959
+	 * @throws EE_Error
960
+	 * @throws InvalidArgumentException
961
+	 * @throws InvalidDataTypeException
962
+	 * @throws InvalidInterfaceException
963
+	 */
964
+	protected function _events_overview_list_table()
965
+	{
966
+		$after_list_table                           = [];
967
+		$links_html = EEH_HTML::div('', '', 'ee-admin-section ee-layout-stack');
968
+		$links_html .= EEH_HTML::h3(esc_html__('Links', 'event_espresso'));
969
+		$links_html .= EEH_HTML::div(
970
+			EEH_Template::get_button_or_link(
971
+				get_post_type_archive_link('espresso_events'),
972
+				esc_html__('View Event Archive Page', 'event_espresso'),
973
+				'button button--small button--secondary'
974
+			),
975
+			'',
976
+			'ee-admin-button-row ee-admin-button-row--align-start'
977
+		);
978
+		$links_html .= EEH_HTML::divx();
979
+
980
+		$after_list_table['view_event_list_button'] = $links_html;
981
+
982
+		$after_list_table['legend'] = $this->_display_legend($this->_event_legend_items());
983
+		$this->_admin_page_title                    .= ' ' . $this->get_action_link_or_button(
984
+			'create_new',
985
+			'add',
986
+			[],
987
+			'add-new-h2'
988
+		);
989
+
990
+		$this->_template_args['after_list_table']   = array_merge(
991
+			(array) $this->_template_args['after_list_table'],
992
+			$after_list_table
993
+		);
994
+		$this->display_admin_list_table_page_with_no_sidebar();
995
+	}
996
+
997
+
998
+	/**
999
+	 * this allows for extra misc actions in the default WP publish box
1000
+	 *
1001
+	 * @return void
1002
+	 * @throws DomainException
1003
+	 * @throws EE_Error
1004
+	 * @throws InvalidArgumentException
1005
+	 * @throws InvalidDataTypeException
1006
+	 * @throws InvalidInterfaceException
1007
+	 * @throws ReflectionException
1008
+	 */
1009
+	public function extra_misc_actions_publish_box()
1010
+	{
1011
+		$this->_generate_publish_box_extra_content();
1012
+	}
1013
+
1014
+
1015
+	/**
1016
+	 * This is hooked into the WordPress do_action('save_post') hook and runs after the custom post type has been
1017
+	 * saved.
1018
+	 * Typically you would use this to save any additional data.
1019
+	 * Keep in mind also that "save_post" runs on EVERY post update to the database.
1020
+	 * ALSO very important.  When a post transitions from scheduled to published,
1021
+	 * the save_post action is fired but you will NOT have any _POST data containing any extra info you may have from
1022
+	 * other meta saves. So MAKE sure that you handle this accordingly.
1023
+	 *
1024
+	 * @access protected
1025
+	 * @abstract
1026
+	 * @param string $post_id The ID of the cpt that was saved (so you can link relationally)
1027
+	 * @param WP_Post $post    The post object of the cpt that was saved.
1028
+	 * @return void
1029
+	 * @throws EE_Error
1030
+	 * @throws InvalidArgumentException
1031
+	 * @throws InvalidDataTypeException
1032
+	 * @throws InvalidInterfaceException
1033
+	 * @throws ReflectionException
1034
+	 */
1035
+	protected function _insert_update_cpt_item($post_id, $post)
1036
+	{
1037
+		if ($post instanceof WP_Post && $post->post_type !== 'espresso_events') {
1038
+			// get out we're not processing an event save.
1039
+			return;
1040
+		}
1041
+		$event_values = [
1042
+			'EVT_member_only'     => $this->request->getRequestParam('member_only', false, 'bool'),
1043
+			'EVT_allow_overflow'  => $this->request->getRequestParam('EVT_allow_overflow', false, 'bool'),
1044
+			'EVT_timezone_string' => $this->request->getRequestParam('timezone_string'),
1045
+		];
1046
+		// check if the new EDTR reg options meta box is being used, and if so, don't run updates for legacy version
1047
+		if (! $this->admin_config->useAdvancedEditor() || ! $this->feature->allowed('use_reg_options_meta_box')) {
1048
+			$event_values['EVT_display_ticket_selector']     = $this->request->getRequestParam(
1049
+				'display_ticket_selector',
1050
+				false,
1051
+				'bool'
1052
+			);
1053
+			$event_values['EVT_additional_limit']            = min(
1054
+				apply_filters('FHEE__EE_Events_Admin__insert_update_cpt_item__EVT_additional_limit_max', 255),
1055
+				$this->request->getRequestParam('additional_limit', null, 'int')
1056
+			);
1057
+			$event_values['EVT_default_registration_status'] = $this->request->getRequestParam(
1058
+				'EVT_default_registration_status',
1059
+				EE_Registry::instance()->CFG->registration->default_STS_ID
1060
+			);
1061
+
1062
+			$event_values['EVT_external_URL'] = $this->request->getRequestParam('externalURL');
1063
+			$event_values['EVT_phone']        = $this->request->getRequestParam('event_phone');
1064
+			$event_values['EVT_display_desc'] = $this->request->getRequestParam('display_desc', false, 'bool');
1065
+		}
1066
+		// update event
1067
+		$success = $this->_event_model()->update_by_ID($event_values, $post_id);
1068
+		// get event_object for other metaboxes...
1069
+		// though it would seem to make sense to just use $this->_event_model()->get_one_by_ID( $post_id )..
1070
+		// i have to setup where conditions to override the filters in the model
1071
+		// that filter out autodraft and inherit statuses so we GET the inherit id!
1072
+		$event = $this->_event_model()->get_one(
1073
+			[
1074
+				[
1075
+					$this->_event_model()->primary_key_name() => $post_id,
1076
+					'OR'                                      => [
1077
+						'status'   => $post->post_status,
1078
+						// if trying to "Publish" a sold out event, it's status will get switched back to "sold_out" in the db,
1079
+						// but the returned object here has a status of "publish", so use the original post status as well
1080
+						'status*1' => $this->request->getRequestParam('original_post_status'),
1081
+					],
1082
+				],
1083
+			]
1084
+		);
1085
+
1086
+		// the following are default callbacks for event attachment updates
1087
+		// that can be overridden by caffeinated functionality and/or addons.
1088
+		$event_update_callbacks = [];
1089
+		if (! $this->admin_config->useAdvancedEditor()) {
1090
+			$event_update_callbacks['_default_venue_update']   = [$this, '_default_venue_update'];
1091
+			$event_update_callbacks['_default_tickets_update'] = [$this, '_default_tickets_update'];
1092
+		}
1093
+		$event_update_callbacks = apply_filters(
1094
+			'FHEE__Events_Admin_Page___insert_update_cpt_item__event_update_callbacks',
1095
+			$event_update_callbacks
1096
+		);
1097
+
1098
+		$att_success = true;
1099
+		foreach ($event_update_callbacks as $e_callback) {
1100
+			$_success = is_callable($e_callback)
1101
+				? $e_callback($event, $this->request->requestParams())
1102
+				: false;
1103
+			// if ANY of these updates fail then we want the appropriate global error message
1104
+			$att_success = $_success !== false ? $att_success : false;
1105
+		}
1106
+		// any errors?
1107
+		if ($success && $att_success === false) {
1108
+			EE_Error::add_error(
1109
+				esc_html__(
1110
+					'Event Details saved successfully but something went wrong with saving attachments.',
1111
+					'event_espresso'
1112
+				),
1113
+				__FILE__,
1114
+				__FUNCTION__,
1115
+				__LINE__
1116
+			);
1117
+		} elseif ($success === false) {
1118
+			EE_Error::add_error(
1119
+				esc_html__('Event Details did not save successfully.', 'event_espresso'),
1120
+				__FILE__,
1121
+				__FUNCTION__,
1122
+				__LINE__
1123
+			);
1124
+		}
1125
+	}
1126
+
1127
+
1128
+	/**
1129
+	 * @param int $post_id
1130
+	 * @param int $revision_id
1131
+	 * @throws EE_Error
1132
+	 * @throws EE_Error
1133
+	 * @throws ReflectionException
1134
+	 * @see parent::restore_item()
1135
+	 */
1136
+	protected function _restore_cpt_item($post_id, $revision_id)
1137
+	{
1138
+		// copy existing event meta to new post
1139
+		$post_evt = $this->_event_model()->get_one_by_ID($post_id);
1140
+		if ($post_evt instanceof EE_Event) {
1141
+			// meta revision restore
1142
+			$post_evt->restore_revision($revision_id);
1143
+			// related objs restore
1144
+			$post_evt->restore_revision($revision_id, ['Venue', 'Datetime', 'Price']);
1145
+		}
1146
+	}
1147
+
1148
+
1149
+	/**
1150
+	 * Attach the venue to the Event
1151
+	 *
1152
+	 * @param EE_Event $event Event Object to add the venue to
1153
+	 * @param array    $data  The request data from the form
1154
+	 * @return bool           Success or fail.
1155
+	 * @throws EE_Error
1156
+	 * @throws ReflectionException
1157
+	 */
1158
+	protected function _default_venue_update(EE_Event $event, $data)
1159
+	{
1160
+		require_once(EE_MODELS . 'EEM_Venue.model.php');
1161
+		$venue_model = EE_Registry::instance()->load_model('Venue');
1162
+		$venue_id    = ! empty($data['venue_id']) ? $data['venue_id'] : null;
1163
+		// very important.  If we don't have a venue name...
1164
+		// then we'll get out because not necessary to create empty venue
1165
+		if (empty($data['venue_title'])) {
1166
+			return false;
1167
+		}
1168
+		$venue_array = [
1169
+			'VNU_wp_user'         => $event->get('EVT_wp_user'),
1170
+			'VNU_name'            => ! empty($data['venue_title']) ? $data['venue_title'] : null,
1171
+			'VNU_desc'            => ! empty($data['venue_description']) ? $data['venue_description'] : null,
1172
+			'VNU_identifier'      => ! empty($data['venue_identifier']) ? $data['venue_identifier'] : null,
1173
+			'VNU_short_desc'      => ! empty($data['venue_short_description'])
1174
+				? $data['venue_short_description']
1175
+				: null,
1176
+			'VNU_address'         => ! empty($data['address']) ? $data['address'] : null,
1177
+			'VNU_address2'        => ! empty($data['address2']) ? $data['address2'] : null,
1178
+			'VNU_city'            => ! empty($data['city']) ? $data['city'] : null,
1179
+			'STA_ID'              => ! empty($data['state']) ? $data['state'] : null,
1180
+			'CNT_ISO'             => ! empty($data['countries']) ? $data['countries'] : null,
1181
+			'VNU_zip'             => ! empty($data['zip']) ? $data['zip'] : null,
1182
+			'VNU_phone'           => ! empty($data['venue_phone']) ? $data['venue_phone'] : null,
1183
+			'VNU_capacity'        => ! empty($data['venue_capacity']) ? $data['venue_capacity'] : null,
1184
+			'VNU_url'             => ! empty($data['venue_url']) ? $data['venue_url'] : null,
1185
+			'VNU_virtual_phone'   => ! empty($data['virtual_phone']) ? $data['virtual_phone'] : null,
1186
+			'VNU_virtual_url'     => ! empty($data['virtual_url']) ? $data['virtual_url'] : null,
1187
+			'VNU_enable_for_gmap' => isset($data['enable_for_gmap']) ? 1 : 0,
1188
+			'status'              => 'publish',
1189
+		];
1190
+		// if we've got the venue_id then we're just updating the existing venue so let's do that and then get out.
1191
+		if (! empty($venue_id)) {
1192
+			$update_where  = [$venue_model->primary_key_name() => $venue_id];
1193
+			$rows_affected = $venue_model->update($venue_array, [$update_where]);
1194
+			// we've gotta make sure that the venue is always attached to a revision..
1195
+			// add_relation_to should take care of making sure that the relation is already present.
1196
+			$event->_add_relation_to($venue_id, 'Venue');
1197
+			return $rows_affected > 0;
1198
+		}
1199
+		// we insert the venue
1200
+		$venue_id = $venue_model->insert($venue_array);
1201
+		$event->_add_relation_to($venue_id, 'Venue');
1202
+		return ! empty($venue_id);
1203
+		// when we have the ancestor come in it's already been handled by the revision save.
1204
+	}
1205
+
1206
+
1207
+	/**
1208
+	 * Handles saving everything related to Tickets (datetimes, tickets, prices)
1209
+	 *
1210
+	 * @param EE_Event $event The Event object we're attaching data to
1211
+	 * @param array    $data  The request data from the form
1212
+	 * @return array
1213
+	 * @throws EE_Error
1214
+	 * @throws ReflectionException
1215
+	 * @throws Exception
1216
+	 */
1217
+	protected function _default_tickets_update(EE_Event $event, $data)
1218
+	{
1219
+		if ($this->admin_config->useAdvancedEditor()) {
1220
+			return [];
1221
+		}
1222
+		$datetime       = null;
1223
+		$saved_tickets  = [];
1224
+		$event_timezone = $event->get_timezone();
1225
+		$date_formats   = ['Y-m-d', 'h:i a'];
1226
+		foreach ($data['edit_event_datetimes'] as $row => $datetime_data) {
1227
+			// trim all values to ensure any excess whitespace is removed.
1228
+			$datetime_data                = array_map('trim', $datetime_data);
1229
+			$datetime_data['DTT_EVT_end'] =
1230
+				isset($datetime_data['DTT_EVT_end']) && ! empty($datetime_data['DTT_EVT_end'])
1231
+					? $datetime_data['DTT_EVT_end']
1232
+					: $datetime_data['DTT_EVT_start'];
1233
+			$datetime_values              = [
1234
+				'DTT_ID'        => ! empty($datetime_data['DTT_ID']) ? $datetime_data['DTT_ID'] : null,
1235
+				'DTT_EVT_start' => $datetime_data['DTT_EVT_start'],
1236
+				'DTT_EVT_end'   => $datetime_data['DTT_EVT_end'],
1237
+				'DTT_reg_limit' => empty($datetime_data['DTT_reg_limit']) ? EE_INF : $datetime_data['DTT_reg_limit'],
1238
+				'DTT_order'     => $row,
1239
+			];
1240
+			// if we have an id then let's get existing object first and then set the new values.
1241
+			//  Otherwise we instantiate a new object for save.
1242
+			if (! empty($datetime_data['DTT_ID'])) {
1243
+				$datetime = EEM_Datetime::instance($event_timezone)->get_one_by_ID($datetime_data['DTT_ID']);
1244
+				if (! $datetime instanceof EE_Datetime) {
1245
+					throw new RuntimeException(
1246
+						sprintf(
1247
+							esc_html__(
1248
+								'Something went wrong! A valid Datetime could not be retrieved from the database using the supplied ID: %1$d',
1249
+								'event_espresso'
1250
+							),
1251
+							$datetime_data['DTT_ID']
1252
+						)
1253
+					);
1254
+				}
1255
+				$datetime->set_date_format($date_formats[0]);
1256
+				$datetime->set_time_format($date_formats[1]);
1257
+				foreach ($datetime_values as $field => $value) {
1258
+					$datetime->set($field, $value);
1259
+				}
1260
+			} else {
1261
+				$datetime = EE_Datetime::new_instance($datetime_values, $event_timezone, $date_formats);
1262
+			}
1263
+			if (! $datetime instanceof EE_Datetime) {
1264
+				throw new RuntimeException(
1265
+					sprintf(
1266
+						esc_html__(
1267
+							'Something went wrong! A valid Datetime could not be generated or retrieved using the supplied data: %1$s',
1268
+							'event_espresso'
1269
+						),
1270
+						print_r($datetime_values, true)
1271
+					)
1272
+				);
1273
+			}
1274
+			// before going any further make sure our dates are setup correctly
1275
+			// so that the end date is always equal or greater than the start date.
1276
+			if ($datetime->get_raw('DTT_EVT_start') > $datetime->get_raw('DTT_EVT_end')) {
1277
+				$datetime->set('DTT_EVT_end', $datetime->get('DTT_EVT_start'));
1278
+				$datetime = EEH_DTT_Helper::date_time_add($datetime, 'DTT_EVT_end', 'days');
1279
+			}
1280
+			$datetime->save();
1281
+			$event->_add_relation_to($datetime, 'Datetime');
1282
+		}
1283
+		// no datetimes get deleted so we don't do any of that logic here.
1284
+		// update tickets next
1285
+		$old_tickets = isset($data['ticket_IDs']) ? explode(',', $data['ticket_IDs']) : [];
1286
+
1287
+		// set up some default start and end dates in case those are not present in the incoming data
1288
+		$default_start_date = new DateTime('now', new DateTimeZone($event->get_timezone()));
1289
+		$default_start_date = $default_start_date->format($date_formats[0] . ' ' . $date_formats[1]);
1290
+		// use the start date of the first datetime for the end date
1291
+		$first_datetime   = $event->first_datetime();
1292
+		$default_end_date = $first_datetime->start_date_and_time($date_formats[0], $date_formats[1]);
1293
+
1294
+		// now process the incoming data
1295
+		foreach ($data['edit_tickets'] as $row => $ticket_data) {
1296
+			$update_prices = false;
1297
+			$ticket_price  = isset($data['edit_prices'][ $row ][1]['PRC_amount'])
1298
+				? $data['edit_prices'][ $row ][1]['PRC_amount']
1299
+				: 0;
1300
+			// trim inputs to ensure any excess whitespace is removed.
1301
+			$ticket_data   = array_map('trim', $ticket_data);
1302
+			$ticket_values = [
1303
+				'TKT_ID'          => ! empty($ticket_data['TKT_ID']) ? $ticket_data['TKT_ID'] : null,
1304
+				'TTM_ID'          => ! empty($ticket_data['TTM_ID']) ? $ticket_data['TTM_ID'] : 0,
1305
+				'TKT_name'        => ! empty($ticket_data['TKT_name']) ? $ticket_data['TKT_name'] : '',
1306
+				'TKT_description' => ! empty($ticket_data['TKT_description']) ? $ticket_data['TKT_description'] : '',
1307
+				'TKT_start_date'  => ! empty($ticket_data['TKT_start_date'])
1308
+					? $ticket_data['TKT_start_date']
1309
+					: $default_start_date,
1310
+				'TKT_end_date'    => ! empty($ticket_data['TKT_end_date'])
1311
+					? $ticket_data['TKT_end_date']
1312
+					: $default_end_date,
1313
+				'TKT_qty'         => ! empty($ticket_data['TKT_qty'])
1314
+									 || (isset($ticket_data['TKT_qty']) && (int) $ticket_data['TKT_qty'] === 0)
1315
+					? $ticket_data['TKT_qty']
1316
+					: EE_INF,
1317
+				'TKT_uses'        => ! empty($ticket_data['TKT_uses'])
1318
+									 || (isset($ticket_data['TKT_uses']) && (int) $ticket_data['TKT_uses'] === 0)
1319
+					? $ticket_data['TKT_uses']
1320
+					: EE_INF,
1321
+				'TKT_min'         => ! empty($ticket_data['TKT_min']) ? $ticket_data['TKT_min'] : 0,
1322
+				'TKT_max'         => ! empty($ticket_data['TKT_max']) ? $ticket_data['TKT_max'] : EE_INF,
1323
+				'TKT_order'       => isset($ticket_data['TKT_order']) ? $ticket_data['TKT_order'] : $row,
1324
+				'TKT_price'       => $ticket_price,
1325
+				'TKT_row'         => $row,
1326
+			];
1327
+			// if this is a default ticket, then we need to set the TKT_ID to 0 and update accordingly,
1328
+			// which means in turn that the prices will become new prices as well.
1329
+			if (isset($ticket_data['TKT_is_default']) && $ticket_data['TKT_is_default']) {
1330
+				$ticket_values['TKT_ID']         = 0;
1331
+				$ticket_values['TKT_is_default'] = 0;
1332
+				$update_prices                   = true;
1333
+			}
1334
+			// if we have a TKT_ID then we need to get that existing TKT_obj and update it
1335
+			// we actually do our saves ahead of adding any relations because its entirely possible that this
1336
+			// ticket didn't get removed or added to any datetime in the session but DID have it's items modified.
1337
+			// keep in mind that if the ticket has been sold (and we have changed pricing information),
1338
+			// then we won't be updating the tkt but instead a new tkt will be created and the old one archived.
1339
+			if (! empty($ticket_data['TKT_ID'])) {
1340
+				$existing_ticket = EEM_Ticket::instance($event_timezone)->get_one_by_ID($ticket_data['TKT_ID']);
1341
+				if (! $existing_ticket instanceof EE_Ticket) {
1342
+					throw new RuntimeException(
1343
+						sprintf(
1344
+							esc_html__(
1345
+								'Something went wrong! A valid Ticket could not be retrieved from the database using the supplied ID: %1$d',
1346
+								'event_espresso'
1347
+							),
1348
+							$ticket_data['TKT_ID']
1349
+						)
1350
+					);
1351
+				}
1352
+				$ticket_sold = $existing_ticket->count_related(
1353
+					'Registration',
1354
+					[
1355
+							[
1356
+								'STS_ID' => [
1357
+									'NOT IN',
1358
+									[EEM_Registration::status_id_incomplete],
1359
+								],
1360
+							],
1361
+						]
1362
+				) > 0;
1363
+				// let's just check the total price for the existing ticket and determine if it matches the new total price.
1364
+				// if they are different then we create a new ticket (if $ticket_sold)
1365
+				// if they aren't different then we go ahead and modify existing ticket.
1366
+				$create_new_ticket = $ticket_sold
1367
+									 && $ticket_price !== $existing_ticket->price()
1368
+									 && ! $existing_ticket->deleted();
1369
+				$existing_ticket->set_date_format($date_formats[0]);
1370
+				$existing_ticket->set_time_format($date_formats[1]);
1371
+				// set new values
1372
+				foreach ($ticket_values as $field => $value) {
1373
+					if ($field == 'TKT_qty') {
1374
+						$existing_ticket->set_qty($value);
1375
+					} elseif ($field == 'TKT_price') {
1376
+						$existing_ticket->set('TKT_price', $ticket_price);
1377
+					} else {
1378
+						$existing_ticket->set($field, $value);
1379
+					}
1380
+				}
1381
+				$ticket = $existing_ticket;
1382
+				// if $create_new_ticket is false then we can safely update the existing ticket.
1383
+				//  Otherwise we have to create a new ticket.
1384
+				if ($create_new_ticket) {
1385
+					// archive the old ticket first
1386
+					$existing_ticket->set('TKT_deleted', 1);
1387
+					$existing_ticket->save();
1388
+					// make sure this ticket is still recorded in our $saved_tickets
1389
+					// so we don't run it through the regular trash routine.
1390
+					$saved_tickets[ $existing_ticket->ID() ] = $existing_ticket;
1391
+					// create new ticket that's a copy of the existing except,
1392
+					// (a new id of course and not archived) AND has the new TKT_price associated with it.
1393
+					$new_ticket = clone $existing_ticket;
1394
+					$new_ticket->set('TKT_ID', 0);
1395
+					$new_ticket->set('TKT_deleted', 0);
1396
+					$new_ticket->set('TKT_sold', 0);
1397
+					// now we need to make sure that $new prices are created as well and attached to new ticket.
1398
+					$update_prices = true;
1399
+					$ticket        = $new_ticket;
1400
+				}
1401
+			} else {
1402
+				// no TKT_id so a new ticket
1403
+				$ticket_values['TKT_price'] = $ticket_price;
1404
+				$ticket                     = EE_Ticket::new_instance($ticket_values, $event_timezone, $date_formats);
1405
+				$update_prices              = true;
1406
+			}
1407
+			if (! $ticket instanceof EE_Ticket) {
1408
+				throw new RuntimeException(
1409
+					sprintf(
1410
+						esc_html__(
1411
+							'Something went wrong! A valid Ticket could not be generated or retrieved using the supplied data: %1$s',
1412
+							'event_espresso'
1413
+						),
1414
+						print_r($ticket_values, true)
1415
+					)
1416
+				);
1417
+			}
1418
+			// cap ticket qty by datetime reg limits
1419
+			$ticket->set_qty(min($ticket->qty(), $ticket->qty('reg_limit')));
1420
+			// update ticket.
1421
+			$ticket->save();
1422
+			// before going any further make sure our dates are setup correctly
1423
+			// so that the end date is always equal or greater than the start date.
1424
+			if ($ticket->get_raw('TKT_start_date') > $ticket->get_raw('TKT_end_date')) {
1425
+				$ticket->set('TKT_end_date', $ticket->get('TKT_start_date'));
1426
+				$ticket = EEH_DTT_Helper::date_time_add($ticket, 'TKT_end_date', 'days');
1427
+				$ticket->save();
1428
+			}
1429
+			// initially let's add the ticket to the datetime
1430
+			$datetime->_add_relation_to($ticket, 'Ticket');
1431
+			$saved_tickets[ $ticket->ID() ] = $ticket;
1432
+			// add prices to ticket
1433
+			$prices_data = isset($data['edit_prices'][ $row ]) && is_array($data['edit_prices'][ $row ])
1434
+				? $data['edit_prices'][ $row ]
1435
+				: [];
1436
+			$this->_add_prices_to_ticket($prices_data, $ticket, $update_prices);
1437
+		}
1438
+		// however now we need to handle permanently deleting tickets via the ui.
1439
+		// Keep in mind that the ui does not allow deleting/archiving tickets that have ticket sold.
1440
+		// However, it does allow for deleting tickets that have no tickets sold,
1441
+		// in which case we want to get rid of permanently because there is no need to save in db.
1442
+		$old_tickets     = isset($old_tickets[0]) && $old_tickets[0] === '' ? [] : $old_tickets;
1443
+		$tickets_removed = array_diff($old_tickets, array_keys($saved_tickets));
1444
+		foreach ($tickets_removed as $id) {
1445
+			$id = absint($id);
1446
+			// get the ticket for this id
1447
+			$ticket_to_remove = EEM_Ticket::instance()->get_one_by_ID($id);
1448
+			if (! $ticket_to_remove instanceof EE_Ticket) {
1449
+				continue;
1450
+			}
1451
+			// need to get all the related datetimes on this ticket and remove from every single one of them
1452
+			// (remember this process can ONLY kick off if there are NO tickets sold)
1453
+			$related_datetimes = $ticket_to_remove->get_many_related('Datetime');
1454
+			foreach ($related_datetimes as $related_datetime) {
1455
+				$ticket_to_remove->_remove_relation_to($related_datetime, 'Datetime');
1456
+			}
1457
+			// need to do the same for prices (except these prices can also be deleted because again,
1458
+			// tickets can only be trashed if they don't have any TKTs sold (otherwise they are just archived))
1459
+			$ticket_to_remove->delete_related_permanently('Price');
1460
+			// finally let's delete this ticket
1461
+			// (which should not be blocked at this point b/c we've removed all our relationships)
1462
+			$ticket_to_remove->delete_permanently();
1463
+		}
1464
+		return [$datetime, $saved_tickets];
1465
+	}
1466
+
1467
+
1468
+	/**
1469
+	 * This attaches a list of given prices to a ticket.
1470
+	 * Note we dont' have to worry about ever removing relationships (or archiving prices)
1471
+	 * because if there is a change in price information on a ticket, a new ticket is created anyways
1472
+	 * so the archived ticket will retain the old price info and prices are automatically "archived" via the ticket.
1473
+	 *
1474
+	 * @access  private
1475
+	 * @param array     $prices_data Array of prices from the form.
1476
+	 * @param EE_Ticket $ticket      EE_Ticket object that prices are being attached to.
1477
+	 * @param bool      $new_prices  Whether attach existing incoming prices or create new ones.
1478
+	 * @return  void
1479
+	 * @throws EE_Error
1480
+	 * @throws ReflectionException
1481
+	 */
1482
+	private function _add_prices_to_ticket($prices_data, EE_Ticket $ticket, $new_prices = false)
1483
+	{
1484
+		$timezone = $ticket->get_timezone();
1485
+		foreach ($prices_data as $row => $price_data) {
1486
+			$price_values = [
1487
+				'PRC_ID'         => ! empty($price_data['PRC_ID']) ? $price_data['PRC_ID'] : null,
1488
+				'PRT_ID'         => ! empty($price_data['PRT_ID']) ? $price_data['PRT_ID'] : null,
1489
+				'PRC_amount'     => ! empty($price_data['PRC_amount']) ? $price_data['PRC_amount'] : 0,
1490
+				'PRC_name'       => ! empty($price_data['PRC_name']) ? $price_data['PRC_name'] : '',
1491
+				'PRC_desc'       => ! empty($price_data['PRC_desc']) ? $price_data['PRC_desc'] : '',
1492
+				'PRC_is_default' => 0, // make sure prices are NOT set as default from this context
1493
+				'PRC_order'      => $row,
1494
+			];
1495
+			if ($new_prices || empty($price_values['PRC_ID'])) {
1496
+				$price_values['PRC_ID'] = 0;
1497
+				$price                  = EE_Price::new_instance($price_values, $timezone);
1498
+			} else {
1499
+				$price = EEM_Price::instance($timezone)->get_one_by_ID($price_data['PRC_ID']);
1500
+				// update this price with new values
1501
+				foreach ($price_values as $field => $new_price) {
1502
+					$price->set($field, $new_price);
1503
+				}
1504
+			}
1505
+			if (! $price instanceof EE_Price) {
1506
+				throw new RuntimeException(
1507
+					sprintf(
1508
+						esc_html__(
1509
+							'Something went wrong! A valid Price could not be generated or retrieved using the supplied data: %1$s',
1510
+							'event_espresso'
1511
+						),
1512
+						print_r($price_values, true)
1513
+					)
1514
+				);
1515
+			}
1516
+			$price->save();
1517
+			$ticket->_add_relation_to($price, 'Price');
1518
+		}
1519
+	}
1520
+
1521
+
1522
+	/**
1523
+	 * Add in our autosave ajax handlers
1524
+	 *
1525
+	 */
1526
+	protected function _ee_autosave_create_new()
1527
+	{
1528
+	}
1529
+
1530
+
1531
+	/**
1532
+	 * More autosave handlers.
1533
+	 */
1534
+	protected function _ee_autosave_edit()
1535
+	{
1536
+	}
1537
+
1538
+
1539
+	/**
1540
+	 * @throws EE_Error
1541
+	 * @throws ReflectionException
1542
+	 */
1543
+	private function _generate_publish_box_extra_content()
1544
+	{
1545
+		// load formatter helper
1546
+		// args for getting related registrations
1547
+		$approved_query_args        = [
1548
+			[
1549
+				'REG_deleted' => 0,
1550
+				'STS_ID'      => EEM_Registration::status_id_approved,
1551
+			],
1552
+		];
1553
+		$not_approved_query_args    = [
1554
+			[
1555
+				'REG_deleted' => 0,
1556
+				'STS_ID'      => EEM_Registration::status_id_not_approved,
1557
+			],
1558
+		];
1559
+		$pending_payment_query_args = [
1560
+			[
1561
+				'REG_deleted' => 0,
1562
+				'STS_ID'      => EEM_Registration::status_id_pending_payment,
1563
+			],
1564
+		];
1565
+		// publish box
1566
+		$publish_box_extra_args = [
1567
+			'view_approved_reg_url'        => add_query_arg(
1568
+				[
1569
+					'action'      => 'default',
1570
+					'event_id'    => $this->_cpt_model_obj->ID(),
1571
+					'_reg_status' => EEM_Registration::status_id_approved,
1572
+				],
1573
+				REG_ADMIN_URL
1574
+			),
1575
+			'view_not_approved_reg_url'    => add_query_arg(
1576
+				[
1577
+					'action'      => 'default',
1578
+					'event_id'    => $this->_cpt_model_obj->ID(),
1579
+					'_reg_status' => EEM_Registration::status_id_not_approved,
1580
+				],
1581
+				REG_ADMIN_URL
1582
+			),
1583
+			'view_pending_payment_reg_url' => add_query_arg(
1584
+				[
1585
+					'action'      => 'default',
1586
+					'event_id'    => $this->_cpt_model_obj->ID(),
1587
+					'_reg_status' => EEM_Registration::status_id_pending_payment,
1588
+				],
1589
+				REG_ADMIN_URL
1590
+			),
1591
+			'approved_regs'                => $this->_cpt_model_obj->count_related(
1592
+				'Registration',
1593
+				$approved_query_args
1594
+			),
1595
+			'not_approved_regs'            => $this->_cpt_model_obj->count_related(
1596
+				'Registration',
1597
+				$not_approved_query_args
1598
+			),
1599
+			'pending_payment_regs'         => $this->_cpt_model_obj->count_related(
1600
+				'Registration',
1601
+				$pending_payment_query_args
1602
+			),
1603
+			'misc_pub_section_class'       => apply_filters(
1604
+				'FHEE_Events_Admin_Page___generate_publish_box_extra_content__misc_pub_section_class',
1605
+				'misc-pub-section'
1606
+			),
1607
+		];
1608
+		ob_start();
1609
+		do_action(
1610
+			'AHEE__Events_Admin_Page___generate_publish_box_extra_content__event_editor_overview_add',
1611
+			$this->_cpt_model_obj
1612
+		);
1613
+		$publish_box_extra_args['event_editor_overview_add'] = ob_get_clean();
1614
+		// load template
1615
+		EEH_Template::display_template(
1616
+			EVENTS_TEMPLATE_PATH . 'event_publish_box_extras.template.php',
1617
+			$publish_box_extra_args
1618
+		);
1619
+	}
1620
+
1621
+
1622
+	/**
1623
+	 * @return EE_Event
1624
+	 */
1625
+	public function get_event_object()
1626
+	{
1627
+		return $this->_cpt_model_obj;
1628
+	}
1629
+
1630
+
1631
+
1632
+
1633
+	/** METABOXES * */
1634
+	/**
1635
+	 * _register_event_editor_meta_boxes
1636
+	 * add all metaboxes related to the event_editor
1637
+	 *
1638
+	 * @return void
1639
+	 * @throws EE_Error
1640
+	 * @throws ReflectionException
1641
+	 */
1642
+	protected function _register_event_editor_meta_boxes()
1643
+	{
1644
+		$this->verify_cpt_object();
1645
+		$use_advanced_editor = $this->admin_config->useAdvancedEditor();
1646
+		// check if the new EDTR reg options meta box is being used, and if so, don't load the legacy version
1647
+		if (! $use_advanced_editor || ! $this->feature->allowed('use_reg_options_meta_box')) {
1648
+			$this->addMetaBox(
1649
+				'espresso_event_editor_event_options',
1650
+				esc_html__('Event Registration Options', 'event_espresso'),
1651
+				[$this, 'registration_options_meta_box'],
1652
+				$this->page_slug,
1653
+				'side'
1654
+			);
1655
+		}
1656
+		if (! $use_advanced_editor) {
1657
+			$this->addMetaBox(
1658
+				'espresso_event_editor_tickets',
1659
+				esc_html__('Event Datetime & Ticket', 'event_espresso'),
1660
+				[$this, 'ticket_metabox'],
1661
+				$this->page_slug,
1662
+				'normal',
1663
+				'high'
1664
+			);
1665
+		} elseif ($this->feature->allowed('use_reg_options_meta_box')) {
1666
+			add_action(
1667
+				'add_meta_boxes_espresso_events',
1668
+				function () {
1669
+					global $current_screen;
1670
+					remove_meta_box('authordiv', $current_screen, 'normal');
1671
+				},
1672
+				99
1673
+			);
1674
+		}
1675
+		// NOTE: if you're looking for other metaboxes in here,
1676
+		// where a metabox has a related management page in the admin
1677
+		// you will find it setup in the related management page's "_Hooks" file.
1678
+		// i.e. messages metabox is found in "espresso_events_Messages_Hooks.class.php".
1679
+	}
1680
+
1681
+
1682
+	/**
1683
+	 * @throws DomainException
1684
+	 * @throws EE_Error
1685
+	 * @throws ReflectionException
1686
+	 */
1687
+	public function ticket_metabox()
1688
+	{
1689
+		$existing_datetime_ids = $existing_ticket_ids = [];
1690
+		// defaults for template args
1691
+		$template_args = [
1692
+			'existing_datetime_ids'    => '',
1693
+			'event_datetime_help_link' => '',
1694
+			'ticket_options_help_link' => '',
1695
+			'time'                     => null,
1696
+			'ticket_rows'              => '',
1697
+			'existing_ticket_ids'      => '',
1698
+			'total_ticket_rows'        => 1,
1699
+			'ticket_js_structure'      => '',
1700
+			'trash_icon'               => 'dashicons dashicons-lock',
1701
+			'disabled'                 => '',
1702
+		];
1703
+		$event_id      = is_object($this->_cpt_model_obj) ? $this->_cpt_model_obj->ID() : null;
1704
+		/**
1705
+		 * 1. Start with retrieving Datetimes
1706
+		 * 2. Fore each datetime get related tickets
1707
+		 * 3. For each ticket get related prices
1708
+		 */
1709
+		/** @var EEM_Datetime $datetime_model */
1710
+		$datetime_model = EE_Registry::instance()->load_model('Datetime');
1711
+		/** @var EEM_Ticket $datetime_model */
1712
+		$ticket_model = EE_Registry::instance()->load_model('Ticket');
1713
+		$times        = $datetime_model->get_all_event_dates($event_id);
1714
+		/** @type EE_Datetime $first_datetime */
1715
+		$first_datetime = reset($times);
1716
+		// do we get related tickets?
1717
+		if (
1718
+			$first_datetime instanceof EE_Datetime
1719
+			&& $first_datetime->ID() !== 0
1720
+		) {
1721
+			$existing_datetime_ids[] = $first_datetime->get('DTT_ID');
1722
+			$template_args['time']   = $first_datetime;
1723
+			$related_tickets         = $first_datetime->tickets(
1724
+				[
1725
+					['OR' => ['TKT_deleted' => 1, 'TKT_deleted*' => 0]],
1726
+					'default_where_conditions' => 'none',
1727
+				]
1728
+			);
1729
+			if (! empty($related_tickets)) {
1730
+				$template_args['total_ticket_rows'] = count($related_tickets);
1731
+				$row                                = 0;
1732
+				foreach ($related_tickets as $ticket) {
1733
+					$existing_ticket_ids[]        = $ticket->get('TKT_ID');
1734
+					$template_args['ticket_rows'] .= $this->_get_ticket_row($ticket, false, $row);
1735
+					$row++;
1736
+				}
1737
+			} else {
1738
+				$template_args['total_ticket_rows'] = 1;
1739
+				/** @type EE_Ticket $ticket */
1740
+				$ticket                       = $ticket_model->create_default_object();
1741
+				$template_args['ticket_rows'] .= $this->_get_ticket_row($ticket);
1742
+			}
1743
+		} else {
1744
+			$template_args['time'] = $times[0];
1745
+			/** @type EE_Ticket[] $tickets */
1746
+			$tickets                      = $ticket_model->get_all_default_tickets();
1747
+			$template_args['ticket_rows'] .= $this->_get_ticket_row($tickets[1]);
1748
+			// NOTE: we're just sending the first default row
1749
+			// (decaf can't manage default tickets so this should be sufficient);
1750
+		}
1751
+		$template_args['event_datetime_help_link'] = $this->_get_help_tab_link(
1752
+			'event_editor_event_datetimes_help_tab'
1753
+		);
1754
+		$template_args['ticket_options_help_link'] = $this->_get_help_tab_link('ticket_options_info');
1755
+		$template_args['existing_datetime_ids']    = implode(',', $existing_datetime_ids);
1756
+		$template_args['existing_ticket_ids']      = implode(',', $existing_ticket_ids);
1757
+		$template_args['ticket_js_structure']      = $this->_get_ticket_row(
1758
+			$ticket_model->create_default_object(),
1759
+			true
1760
+		);
1761
+		$template                                  = apply_filters(
1762
+			'FHEE__Events_Admin_Page__ticket_metabox__template',
1763
+			EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_main.template.php'
1764
+		);
1765
+		EEH_Template::display_template($template, $template_args);
1766
+	}
1767
+
1768
+
1769
+	/**
1770
+	 * Setup an individual ticket form for the decaf event editor page
1771
+	 *
1772
+	 * @access private
1773
+	 * @param EE_Ticket $ticket   the ticket object
1774
+	 * @param boolean   $skeleton whether we're generating a skeleton for js manipulation
1775
+	 * @param int       $row
1776
+	 * @return string generated html for the ticket row.
1777
+	 * @throws EE_Error
1778
+	 * @throws ReflectionException
1779
+	 */
1780
+	private function _get_ticket_row($ticket, $skeleton = false, $row = 0)
1781
+	{
1782
+		$template_args = [
1783
+			'tkt_status_class'    => ' tkt-status-' . $ticket->ticket_status(),
1784
+			'tkt_archive_class'   => $ticket->ticket_status() === EE_Ticket::archived && ! $skeleton ? ' tkt-archived'
1785
+				: '',
1786
+			'ticketrow'           => $skeleton ? 'TICKETNUM' : $row,
1787
+			'TKT_ID'              => $ticket->get('TKT_ID'),
1788
+			'TKT_name'            => $ticket->get('TKT_name'),
1789
+			'TKT_start_date'      => $skeleton ? '' : $ticket->get_date('TKT_start_date', 'Y-m-d h:i a'),
1790
+			'TKT_end_date'        => $skeleton ? '' : $ticket->get_date('TKT_end_date', 'Y-m-d h:i a'),
1791
+			'TKT_is_default'      => $ticket->get('TKT_is_default'),
1792
+			'TKT_qty'             => $ticket->get_pretty('TKT_qty', 'input'),
1793
+			'edit_ticketrow_name' => $skeleton ? 'TICKETNAMEATTR' : 'edit_tickets',
1794
+			'TKT_sold'            => $skeleton ? 0 : $ticket->get('TKT_sold'),
1795
+			'trash_icon'          => ($skeleton || (! empty($ticket) && ! $ticket->get('TKT_deleted')))
1796
+									 && (! empty($ticket) && $ticket->get('TKT_sold') === 0)
1797
+				? 'trash-icon dashicons dashicons-post-trash clickable' : 'dashicons dashicons-lock',
1798
+			'disabled'            => $skeleton || (! empty($ticket) && ! $ticket->get('TKT_deleted')) ? ''
1799
+				: ' disabled=disabled',
1800
+		];
1801
+		$price         = $ticket->ID() !== 0
1802
+			? $ticket->get_first_related('Price', ['default_where_conditions' => 'none'])
1803
+			: null;
1804
+		$price         = $price instanceof EE_Price
1805
+			? $price
1806
+			: EEM_Price::instance()->create_default_object();
1807
+		$price_args    = [
1808
+			'price_currency_symbol' => EE_Registry::instance()->CFG->currency->sign,
1809
+			'PRC_amount'            => $price->get('PRC_amount'),
1810
+			'PRT_ID'                => $price->get('PRT_ID'),
1811
+			'PRC_ID'                => $price->get('PRC_ID'),
1812
+			'PRC_is_default'        => $price->get('PRC_is_default'),
1813
+		];
1814
+		// make sure we have default start and end dates if skeleton
1815
+		// handle rows that should NOT be empty
1816
+		if (empty($template_args['TKT_start_date'])) {
1817
+			// if empty then the start date will be now.
1818
+			$template_args['TKT_start_date'] = date('Y-m-d h:i a', current_time('timestamp'));
1819
+		}
1820
+		if (empty($template_args['TKT_end_date'])) {
1821
+			// get the earliest datetime (if present);
1822
+			$earliest_datetime             = $this->_cpt_model_obj->ID() > 0
1823
+				? $this->_cpt_model_obj->get_first_related(
1824
+					'Datetime',
1825
+					['order_by' => ['DTT_EVT_start' => 'ASC']]
1826
+				)
1827
+				: null;
1828
+			$template_args['TKT_end_date'] = $earliest_datetime instanceof EE_Datetime
1829
+				? $earliest_datetime->get_datetime('DTT_EVT_start', 'Y-m-d', 'h:i a')
1830
+				: date('Y-m-d h:i a', mktime(0, 0, 0, date('m'), date('d') + 7, date('Y')));
1831
+		}
1832
+		$template_args = array_merge($template_args, $price_args);
1833
+		$template      = apply_filters(
1834
+			'FHEE__Events_Admin_Page__get_ticket_row__template',
1835
+			EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_ticket_row.template.php',
1836
+			$ticket
1837
+		);
1838
+		return EEH_Template::display_template($template, $template_args, true);
1839
+	}
1840
+
1841
+
1842
+	/**
1843
+	 * @throws EE_Error
1844
+	 * @throws ReflectionException
1845
+	 */
1846
+	public function registration_options_meta_box()
1847
+	{
1848
+		$yes_no_values             = [
1849
+			['id' => true, 'text' => esc_html__('Yes', 'event_espresso')],
1850
+			['id' => false, 'text' => esc_html__('No', 'event_espresso')],
1851
+		];
1852
+		$default_reg_status_values = EEM_Registration::reg_status_array(
1853
+			[
1854
+				EEM_Registration::status_id_cancelled,
1855
+				EEM_Registration::status_id_declined,
1856
+				EEM_Registration::status_id_incomplete,
1857
+			],
1858
+			true
1859
+		);
1860
+		// $template_args['is_active_select'] = EEH_Form_Fields::select_input('is_active', $yes_no_values, $this->_cpt_model_obj->is_active());
1861
+		$template_args['_event']                          = $this->_cpt_model_obj;
1862
+		$template_args['event']                           = $this->_cpt_model_obj;
1863
+		$template_args['active_status']                   = $this->_cpt_model_obj->pretty_active_status(false);
1864
+		$template_args['additional_limit']                = $this->_cpt_model_obj->additional_limit();
1865
+		$template_args['default_registration_status']     = EEH_Form_Fields::select_input(
1866
+			'default_reg_status',
1867
+			$default_reg_status_values,
1868
+			$this->_cpt_model_obj->default_registration_status()
1869
+		);
1870
+		$template_args['display_description']             = EEH_Form_Fields::select_input(
1871
+			'display_desc',
1872
+			$yes_no_values,
1873
+			$this->_cpt_model_obj->display_description()
1874
+		);
1875
+		$template_args['display_ticket_selector']         = EEH_Form_Fields::select_input(
1876
+			'display_ticket_selector',
1877
+			$yes_no_values,
1878
+			$this->_cpt_model_obj->display_ticket_selector(),
1879
+			'',
1880
+			'',
1881
+			false
1882
+		);
1883
+		$template_args['additional_registration_options'] = apply_filters(
1884
+			'FHEE__Events_Admin_Page__registration_options_meta_box__additional_registration_options',
1885
+			'',
1886
+			$template_args,
1887
+			$yes_no_values,
1888
+			$default_reg_status_values
1889
+		);
1890
+		EEH_Template::display_template(
1891
+			EVENTS_TEMPLATE_PATH . 'event_registration_options.template.php',
1892
+			$template_args
1893
+		);
1894
+	}
1895
+
1896
+
1897
+	/**
1898
+	 * _get_events()
1899
+	 * This method simply returns all the events (for the given _view and paging)
1900
+	 *
1901
+	 * @access public
1902
+	 * @param int  $per_page     count of items per page (20 default);
1903
+	 * @param int  $current_page what is the current page being viewed.
1904
+	 * @param bool $count        if TRUE then we just return a count of ALL events matching the given _view.
1905
+	 *                           If FALSE then we return an array of event objects
1906
+	 *                           that match the given _view and paging parameters.
1907
+	 * @return array|int         an array of event objects or a count of them.
1908
+	 * @throws Exception
1909
+	 */
1910
+	public function get_events($per_page = 10, $current_page = 1, $count = false)
1911
+	{
1912
+		$EEM_Event   = $this->_event_model();
1913
+		$offset      = ($current_page - 1) * $per_page;
1914
+		$limit       = $count ? null : $offset . ',' . $per_page;
1915
+		$orderby     = $this->request->getRequestParam('orderby', 'EVT_ID');
1916
+		$order       = $this->request->getRequestParam('order', 'DESC');
1917
+		$month_range = $this->request->getRequestParam('month_range');
1918
+		if ($month_range) {
1919
+			$pieces = explode(' ', $month_range, 3);
1920
+			// simulate the FIRST day of the month, that fixes issues for months like February
1921
+			// where PHP doesn't know what to assume for date.
1922
+			// @see https://events.codebasehq.com/projects/event-espresso/tickets/10437
1923
+			$month_r = ! empty($pieces[0]) ? date('m', EEH_DTT_Helper::first_of_month_timestamp($pieces[0])) : '';
1924
+			$year_r  = ! empty($pieces[1]) ? $pieces[1] : '';
1925
+		}
1926
+		$where  = [];
1927
+		$status = $this->request->getRequestParam('status');
1928
+		// determine what post_status our condition will have for the query.
1929
+		switch ($status) {
1930
+			case 'month':
1931
+			case 'today':
1932
+			case null:
1933
+			case 'all':
1934
+				break;
1935
+			case 'draft':
1936
+				$where['status'] = ['IN', ['draft', 'auto-draft']];
1937
+				break;
1938
+			default:
1939
+				$where['status'] = $status;
1940
+		}
1941
+		// categories? The default for all categories is -1
1942
+		$category = $this->request->getRequestParam('EVT_CAT', -1, 'int');
1943
+		if ($category !== -1) {
1944
+			$where['Term_Taxonomy.taxonomy'] = EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY;
1945
+			$where['Term_Taxonomy.term_id']  = $category;
1946
+		}
1947
+		// date where conditions
1948
+		$start_formats = EEM_Datetime::instance()->get_formats_for('DTT_EVT_start');
1949
+		if ($month_range) {
1950
+			$DateTime = new DateTime(
1951
+				$year_r . '-' . $month_r . '-01 00:00:00',
1952
+				new DateTimeZone('UTC')
1953
+			);
1954
+			$start    = $DateTime->getTimestamp();
1955
+			// set the datetime to be the end of the month
1956
+			$DateTime->setDate(
1957
+				$year_r,
1958
+				$month_r,
1959
+				$DateTime->format('t')
1960
+			)->setTime(23, 59, 59);
1961
+			$end                             = $DateTime->getTimestamp();
1962
+			$where['Datetime.DTT_EVT_start'] = ['BETWEEN', [$start, $end]];
1963
+		} elseif ($status === 'today') {
1964
+			$DateTime                        =
1965
+				new DateTime('now', new DateTimeZone(EEM_Event::instance()->get_timezone()));
1966
+			$start                           = $DateTime->setTime(0, 0)->format(implode(' ', $start_formats));
1967
+			$end                             = $DateTime->setTime(23, 59, 59)->format(implode(' ', $start_formats));
1968
+			$where['Datetime.DTT_EVT_start'] = ['BETWEEN', [$start, $end]];
1969
+		} elseif ($status === 'month') {
1970
+			$now                             = date('Y-m-01');
1971
+			$DateTime                        =
1972
+				new DateTime($now, new DateTimeZone(EEM_Event::instance()->get_timezone()));
1973
+			$start                           = $DateTime->setTime(0, 0)->format(implode(' ', $start_formats));
1974
+			$end                             = $DateTime->setDate(date('Y'), date('m'), $DateTime->format('t'))
1975
+														->setTime(23, 59, 59)
1976
+														->format(implode(' ', $start_formats));
1977
+			$where['Datetime.DTT_EVT_start'] = ['BETWEEN', [$start, $end]];
1978
+		}
1979
+		if (! EE_Registry::instance()->CAP->current_user_can('ee_read_others_events', 'get_events')) {
1980
+			$where['EVT_wp_user'] = get_current_user_id();
1981
+		} else {
1982
+			if (! isset($where['status'])) {
1983
+				if (! EE_Registry::instance()->CAP->current_user_can('ee_read_private_events', 'get_events')) {
1984
+					$where['OR'] = [
1985
+						'status*restrict_private' => ['!=', 'private'],
1986
+						'AND'                     => [
1987
+							'status*inclusive' => ['=', 'private'],
1988
+							'EVT_wp_user'      => get_current_user_id(),
1989
+						],
1990
+					];
1991
+				}
1992
+			}
1993
+		}
1994
+		$wp_user = $this->request->getRequestParam('EVT_wp_user', 0, 'int');
1995
+		if (
1996
+			$wp_user
1997
+			&& $wp_user !== get_current_user_id()
1998
+			&& EE_Registry::instance()->CAP->current_user_can('ee_read_others_events', 'get_events')
1999
+		) {
2000
+			$where['EVT_wp_user'] = $wp_user;
2001
+		}
2002
+		// search query handling
2003
+		$search_term = $this->request->getRequestParam('s');
2004
+		if ($search_term) {
2005
+			$search_term = '%' . $search_term . '%';
2006
+			$where['OR'] = [
2007
+				'EVT_name'       => ['LIKE', $search_term],
2008
+				'EVT_desc'       => ['LIKE', $search_term],
2009
+				'EVT_short_desc' => ['LIKE', $search_term],
2010
+			];
2011
+		}
2012
+		// filter events by venue.
2013
+		$venue = $this->request->getRequestParam('venue', 0, 'int');
2014
+		if ($venue) {
2015
+			$where['Venue.VNU_ID'] = $venue;
2016
+		}
2017
+		$request_params = $this->request->requestParams();
2018
+		$where          = apply_filters('FHEE__Events_Admin_Page__get_events__where', $where, $request_params);
2019
+		$query_params   = apply_filters(
2020
+			'FHEE__Events_Admin_Page__get_events__query_params',
2021
+			[
2022
+				$where,
2023
+				'limit'    => $limit,
2024
+				'order_by' => $orderby,
2025
+				'order'    => $order,
2026
+				'group_by' => 'EVT_ID',
2027
+			],
2028
+			$request_params
2029
+		);
2030
+
2031
+		// let's first check if we have special requests coming in.
2032
+		$active_status = $this->request->getRequestParam('active_status');
2033
+		if ($active_status) {
2034
+			switch ($active_status) {
2035
+				case 'upcoming':
2036
+					return $EEM_Event->get_upcoming_events($query_params, $count);
2037
+				case 'expired':
2038
+					return $EEM_Event->get_expired_events($query_params, $count);
2039
+				case 'active':
2040
+					return $EEM_Event->get_active_events($query_params, $count);
2041
+				case 'inactive':
2042
+					return $EEM_Event->get_inactive_events($query_params, $count);
2043
+			}
2044
+		}
2045
+
2046
+		return $count ? $EEM_Event->count([$where], 'EVT_ID', true) : $EEM_Event->get_all($query_params);
2047
+	}
2048
+
2049
+
2050
+	/**
2051
+	 * handling for WordPress CPT actions (trash, restore, delete)
2052
+	 *
2053
+	 * @param string $post_id
2054
+	 * @throws EE_Error
2055
+	 * @throws ReflectionException
2056
+	 */
2057
+	public function trash_cpt_item($post_id)
2058
+	{
2059
+		$this->request->setRequestParam('EVT_ID', $post_id);
2060
+		$this->_trash_or_restore_event('trash', false);
2061
+	}
2062
+
2063
+
2064
+	/**
2065
+	 * @param string $post_id
2066
+	 * @throws EE_Error
2067
+	 * @throws ReflectionException
2068
+	 */
2069
+	public function restore_cpt_item($post_id)
2070
+	{
2071
+		$this->request->setRequestParam('EVT_ID', $post_id);
2072
+		$this->_trash_or_restore_event('draft', false);
2073
+	}
2074
+
2075
+
2076
+	/**
2077
+	 * @param string $post_id
2078
+	 * @throws EE_Error
2079
+	 * @throws EE_Error
2080
+	 */
2081
+	public function delete_cpt_item($post_id)
2082
+	{
2083
+		throw new EE_Error(
2084
+			esc_html__(
2085
+				'Please contact Event Espresso support with the details of the steps taken to produce this error.',
2086
+				'event_espresso'
2087
+			)
2088
+		);
2089
+		// $this->request->setRequestParam('EVT_ID', $post_id);
2090
+		// $this->_delete_event();
2091
+	}
2092
+
2093
+
2094
+	/**
2095
+	 * _trash_or_restore_event
2096
+	 *
2097
+	 * @access protected
2098
+	 * @param string $event_status
2099
+	 * @param bool   $redirect_after
2100
+	 * @throws EE_Error
2101
+	 * @throws EE_Error
2102
+	 * @throws ReflectionException
2103
+	 */
2104
+	protected function _trash_or_restore_event($event_status = 'trash', $redirect_after = true)
2105
+	{
2106
+		// determine the event id and set to array.
2107
+		$EVT_ID = $this->request->getRequestParam('EVT_ID', 0, 'int');
2108
+		// loop thru events
2109
+		if ($EVT_ID) {
2110
+			// clean status
2111
+			$event_status = sanitize_key($event_status);
2112
+			// grab status
2113
+			if (! empty($event_status)) {
2114
+				$success = $this->_change_event_status($EVT_ID, $event_status);
2115
+			} else {
2116
+				$success = false;
2117
+				$msg     = esc_html__(
2118
+					'An error occurred. The event could not be moved to the trash because a valid event status was not not supplied.',
2119
+					'event_espresso'
2120
+				);
2121
+				EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2122
+			}
2123
+		} else {
2124
+			$success = false;
2125
+			$msg     = esc_html__(
2126
+				'An error occurred. The event could not be moved to the trash because a valid event ID was not not supplied.',
2127
+				'event_espresso'
2128
+			);
2129
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2130
+		}
2131
+		$action = $event_status === 'trash' ? 'moved to the trash' : 'restored from the trash';
2132
+		if ($redirect_after) {
2133
+			$this->_redirect_after_action($success, 'Event', $action, ['action' => 'default']);
2134
+		}
2135
+	}
2136
+
2137
+
2138
+	/**
2139
+	 * _trash_or_restore_events
2140
+	 *
2141
+	 * @access protected
2142
+	 * @param string $event_status
2143
+	 * @return void
2144
+	 * @throws EE_Error
2145
+	 * @throws EE_Error
2146
+	 * @throws ReflectionException
2147
+	 */
2148
+	protected function _trash_or_restore_events($event_status = 'trash')
2149
+	{
2150
+		// clean status
2151
+		$event_status = sanitize_key($event_status);
2152
+		// grab status
2153
+		if (! empty($event_status)) {
2154
+			$success = true;
2155
+			// determine the event id and set to array.
2156
+			$EVT_IDs = $this->request->getRequestParam('EVT_IDs', [], 'int', true);
2157
+			// loop thru events
2158
+			foreach ($EVT_IDs as $EVT_ID) {
2159
+				if ($EVT_ID = absint($EVT_ID)) {
2160
+					$results = $this->_change_event_status($EVT_ID, $event_status);
2161
+					$success = $results !== false ? $success : false;
2162
+				} else {
2163
+					$msg = sprintf(
2164
+						esc_html__(
2165
+							'An error occurred. Event #%d could not be moved to the trash because a valid event ID was not not supplied.',
2166
+							'event_espresso'
2167
+						),
2168
+						$EVT_ID
2169
+					);
2170
+					EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2171
+					$success = false;
2172
+				}
2173
+			}
2174
+		} else {
2175
+			$success = false;
2176
+			$msg     = esc_html__(
2177
+				'An error occurred. The event could not be moved to the trash because a valid event status was not not supplied.',
2178
+				'event_espresso'
2179
+			);
2180
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2181
+		}
2182
+		// in order to force a pluralized result message we need to send back a success status greater than 1
2183
+		$success = $success ? 2 : false;
2184
+		$action  = $event_status === 'trash' ? 'moved to the trash' : 'restored from the trash';
2185
+		$this->_redirect_after_action($success, 'Events', $action, ['action' => 'default']);
2186
+	}
2187
+
2188
+
2189
+	/**
2190
+	 * @param int    $EVT_ID
2191
+	 * @param string $event_status
2192
+	 * @return bool
2193
+	 * @throws EE_Error
2194
+	 * @throws ReflectionException
2195
+	 */
2196
+	private function _change_event_status($EVT_ID = 0, $event_status = '')
2197
+	{
2198
+		// grab event id
2199
+		if (! $EVT_ID) {
2200
+			$msg = esc_html__(
2201
+				'An error occurred. No Event ID or an invalid Event ID was received.',
2202
+				'event_espresso'
2203
+			);
2204
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2205
+			return false;
2206
+		}
2207
+		$this->_cpt_model_obj = EEM_Event::instance()->get_one_by_ID($EVT_ID);
2208
+		// clean status
2209
+		$event_status = sanitize_key($event_status);
2210
+		// grab status
2211
+		if (empty($event_status)) {
2212
+			$msg = esc_html__(
2213
+				'An error occurred. No Event Status or an invalid Event Status was received.',
2214
+				'event_espresso'
2215
+			);
2216
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2217
+			return false;
2218
+		}
2219
+		// was event trashed or restored ?
2220
+		switch ($event_status) {
2221
+			case 'draft':
2222
+				$action = 'restored from the trash';
2223
+				$hook   = 'AHEE_event_restored_from_trash';
2224
+				break;
2225
+			case 'trash':
2226
+				$action = 'moved to the trash';
2227
+				$hook   = 'AHEE_event_moved_to_trash';
2228
+				break;
2229
+			default:
2230
+				$action = 'updated';
2231
+				$hook   = false;
2232
+		}
2233
+		// use class to change status
2234
+		$this->_cpt_model_obj->set_status($event_status);
2235
+		$success = $this->_cpt_model_obj->save();
2236
+		if (! $success) {
2237
+			$msg = sprintf(esc_html__('An error occurred. The event could not be %s.', 'event_espresso'), $action);
2238
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2239
+			return false;
2240
+		}
2241
+		if ($hook) {
2242
+			do_action($hook);
2243
+		}
2244
+		return true;
2245
+	}
2246
+
2247
+
2248
+	/**
2249
+	 * @param array $event_ids
2250
+	 * @return array
2251
+	 * @since   4.10.23.p
2252
+	 */
2253
+	private function cleanEventIds(array $event_ids)
2254
+	{
2255
+		return array_map('absint', $event_ids);
2256
+	}
2257
+
2258
+
2259
+	/**
2260
+	 * @return array
2261
+	 * @since   4.10.23.p
2262
+	 */
2263
+	private function getEventIdsFromRequest()
2264
+	{
2265
+		if ($this->request->requestParamIsSet('EVT_IDs')) {
2266
+			return $this->request->getRequestParam('EVT_IDs', [], 'int', true);
2267
+		} else {
2268
+			return $this->request->getRequestParam('EVT_ID', [], 'int', true);
2269
+		}
2270
+	}
2271
+
2272
+
2273
+	/**
2274
+	 * @param bool $preview_delete
2275
+	 * @throws EE_Error
2276
+	 */
2277
+	protected function _delete_event($preview_delete = true)
2278
+	{
2279
+		$this->_delete_events($preview_delete);
2280
+	}
2281
+
2282
+
2283
+	/**
2284
+	 * Gets the tree traversal batch persister.
2285
+	 *
2286
+	 * @return NodeGroupDao
2287
+	 * @throws InvalidArgumentException
2288
+	 * @throws InvalidDataTypeException
2289
+	 * @throws InvalidInterfaceException
2290
+	 * @since 4.10.12.p
2291
+	 */
2292
+	protected function getModelObjNodeGroupPersister()
2293
+	{
2294
+		if (! $this->model_obj_node_group_persister instanceof NodeGroupDao) {
2295
+			$this->model_obj_node_group_persister =
2296
+				$this->getLoader()->load('\EventEspresso\core\services\orm\tree_traversal\NodeGroupDao');
2297
+		}
2298
+		return $this->model_obj_node_group_persister;
2299
+	}
2300
+
2301
+
2302
+	/**
2303
+	 * @param bool $preview_delete
2304
+	 * @return void
2305
+	 * @throws EE_Error
2306
+	 */
2307
+	protected function _delete_events($preview_delete = true)
2308
+	{
2309
+		$event_ids = $this->getEventIdsFromRequest();
2310
+		if ($preview_delete) {
2311
+			$this->generateDeletionPreview($event_ids);
2312
+		} else {
2313
+			EEM_Event::instance()->delete_permanently([['EVT_ID' => ['IN', $event_ids]]]);
2314
+		}
2315
+	}
2316
+
2317
+
2318
+	/**
2319
+	 * @param array $event_ids
2320
+	 */
2321
+	protected function generateDeletionPreview(array $event_ids)
2322
+	{
2323
+		$event_ids = $this->cleanEventIds($event_ids);
2324
+		// Set a code we can use to reference this deletion task in the batch jobs and preview page.
2325
+		$deletion_job_code = $this->getModelObjNodeGroupPersister()->generateGroupCode();
2326
+		$return_url        = EE_Admin_Page::add_query_args_and_nonce(
2327
+			[
2328
+				'action'            => 'preview_deletion',
2329
+				'deletion_job_code' => $deletion_job_code,
2330
+			],
2331
+			$this->_admin_base_url
2332
+		);
2333
+		EEH_URL::safeRedirectAndExit(
2334
+			EE_Admin_Page::add_query_args_and_nonce(
2335
+				[
2336
+					'page'              => EED_Batch::PAGE_SLUG,
2337
+					'batch'             => EED_Batch::batch_job,
2338
+					'EVT_IDs'           => $event_ids,
2339
+					'deletion_job_code' => $deletion_job_code,
2340
+					'job_handler'       => urlencode('EventEspressoBatchRequest\JobHandlers\PreviewEventDeletion'),
2341
+					'return_url'        => urlencode($return_url),
2342
+				],
2343
+				admin_url()
2344
+			)
2345
+		);
2346
+	}
2347
+
2348
+
2349
+	/**
2350
+	 * Checks for a POST submission
2351
+	 *
2352
+	 * @since 4.10.12.p
2353
+	 */
2354
+	protected function confirmDeletion()
2355
+	{
2356
+		$deletion_redirect_logic =
2357
+			$this->getLoader()->getShared('\EventEspresso\core\domain\services\admin\events\data\ConfirmDeletion');
2358
+		$deletion_redirect_logic->handle($this->get_request_data(), $this->admin_base_url());
2359
+	}
2360
+
2361
+
2362
+	/**
2363
+	 * A page for users to preview what exactly will be deleted, and confirm they want to delete it.
2364
+	 *
2365
+	 * @throws EE_Error
2366
+	 * @since 4.10.12.p
2367
+	 */
2368
+	protected function previewDeletion()
2369
+	{
2370
+		$preview_deletion_logic =
2371
+			$this->getLoader()->getShared('\EventEspresso\core\domain\services\admin\events\data\PreviewDeletion');
2372
+		$this->set_template_args($preview_deletion_logic->handle($this->get_request_data(), $this->admin_base_url()));
2373
+		$this->display_admin_page_with_no_sidebar();
2374
+	}
2375
+
2376
+
2377
+	/**
2378
+	 * get total number of events
2379
+	 *
2380
+	 * @access public
2381
+	 * @return int
2382
+	 * @throws EE_Error
2383
+	 * @throws EE_Error
2384
+	 */
2385
+	public function total_events()
2386
+	{
2387
+		return EEM_Event::instance()->count(
2388
+			['caps' => 'read_admin'],
2389
+			'EVT_ID',
2390
+			true
2391
+		);
2392
+	}
2393
+
2394
+
2395
+	/**
2396
+	 * get total number of draft events
2397
+	 *
2398
+	 * @access public
2399
+	 * @return int
2400
+	 * @throws EE_Error
2401
+	 * @throws EE_Error
2402
+	 */
2403
+	public function total_events_draft()
2404
+	{
2405
+		return EEM_Event::instance()->count(
2406
+			[
2407
+				['status' => ['IN', ['draft', 'auto-draft']]],
2408
+				'caps' => 'read_admin',
2409
+			],
2410
+			'EVT_ID',
2411
+			true
2412
+		);
2413
+	}
2414
+
2415
+
2416
+	/**
2417
+	 * get total number of trashed events
2418
+	 *
2419
+	 * @access public
2420
+	 * @return int
2421
+	 * @throws EE_Error
2422
+	 * @throws EE_Error
2423
+	 */
2424
+	public function total_trashed_events()
2425
+	{
2426
+		return EEM_Event::instance()->count(
2427
+			[
2428
+				['status' => 'trash'],
2429
+				'caps' => 'read_admin',
2430
+			],
2431
+			'EVT_ID',
2432
+			true
2433
+		);
2434
+	}
2435
+
2436
+
2437
+	/**
2438
+	 *    _default_event_settings
2439
+	 *    This generates the Default Settings Tab
2440
+	 *
2441
+	 * @return void
2442
+	 * @throws DomainException
2443
+	 * @throws EE_Error
2444
+	 * @throws InvalidArgumentException
2445
+	 * @throws InvalidDataTypeException
2446
+	 * @throws InvalidInterfaceException
2447
+	 */
2448
+	protected function _default_event_settings()
2449
+	{
2450
+		$this->_set_add_edit_form_tags('update_default_event_settings');
2451
+		$this->_set_publish_post_box_vars(null, false, false, null, false);
2452
+		$this->_template_args['admin_page_content'] = EEH_HTML::div(
2453
+			$this->_default_event_settings_form()->get_html(),
2454
+			'',
2455
+			'padding'
2456
+		);
2457
+		$this->display_admin_page_with_sidebar();
2458
+	}
2459
+
2460
+
2461
+	/**
2462
+	 * Return the form for event settings.
2463
+	 *
2464
+	 * @return EE_Form_Section_Proper
2465
+	 * @throws EE_Error
2466
+	 */
2467
+	protected function _default_event_settings_form()
2468
+	{
2469
+		$registration_config              = EE_Registry::instance()->CFG->registration;
2470
+		$registration_stati_for_selection = EEM_Registration::reg_status_array(
2471
+		// exclude
2472
+			[
2473
+				EEM_Registration::status_id_cancelled,
2474
+				EEM_Registration::status_id_declined,
2475
+				EEM_Registration::status_id_incomplete,
2476
+				EEM_Registration::status_id_wait_list,
2477
+			],
2478
+			true
2479
+		);
2480
+		// setup Advanced Editor ???
2481
+		if (
2482
+			$this->raw_req_action === 'default_event_settings'
2483
+			|| $this->raw_req_action === 'update_default_event_settings'
2484
+		) {
2485
+			$this->advanced_editor_admin_form = $this->loader->getShared(AdvancedEditorAdminFormSection::class);
2486
+		}
2487
+		return new EE_Form_Section_Proper(
2488
+			[
2489
+				'name'            => 'update_default_event_settings',
2490
+				'html_id'         => 'update_default_event_settings',
2491
+				'html_class'      => 'form-table',
2492
+				'layout_strategy' => new EE_Admin_Two_Column_Layout(),
2493
+				'subsections'     => apply_filters(
2494
+					'FHEE__Events_Admin_Page___default_event_settings_form__form_subsections',
2495
+					[
2496
+						'defaults_section_header' => new EE_Form_Section_HTML(
2497
+							EEH_HTML::h2(
2498
+								esc_html__('Default Settings', 'event_espresso'),
2499
+								'',
2500
+								'ee-admin-settings-hdr'
2501
+							)
2502
+						),
2503
+						'default_reg_status'  => new EE_Select_Input(
2504
+							$registration_stati_for_selection,
2505
+							[
2506
+								'default'         => isset($registration_config->default_STS_ID)
2507
+													 && array_key_exists(
2508
+														 $registration_config->default_STS_ID,
2509
+														 $registration_stati_for_selection
2510
+													 )
2511
+									? sanitize_text_field($registration_config->default_STS_ID)
2512
+									: EEM_Registration::status_id_pending_payment,
2513
+								'html_label_text' => esc_html__('Default Registration Status', 'event_espresso')
2514
+													 . EEH_Template::get_help_tab_link(
2515
+														 'default_settings_status_help_tab'
2516
+													 ),
2517
+								'html_help_text'  => esc_html__(
2518
+									'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.',
2519
+									'event_espresso'
2520
+								),
2521
+							]
2522
+						),
2523
+						'default_max_tickets' => new EE_Integer_Input(
2524
+							[
2525
+								'default'         => isset($registration_config->default_maximum_number_of_tickets)
2526
+									? $registration_config->default_maximum_number_of_tickets
2527
+									: EEM_Event::get_default_additional_limit(),
2528
+								'html_label_text' => esc_html__(
2529
+									'Default Maximum Tickets Allowed Per Order:',
2530
+									'event_espresso'
2531
+								)
2532
+													 . EEH_Template::get_help_tab_link(
2533
+														 'default_maximum_tickets_help_tab"'
2534
+													 ),
2535
+								'html_help_text'  => esc_html__(
2536
+									'This setting allows you to indicate what will be the default for the maximum number of tickets per order when creating new events.',
2537
+									'event_espresso'
2538
+								),
2539
+							]
2540
+						),
2541
+					]
2542
+				),
2543
+			]
2544
+		);
2545
+	}
2546
+
2547
+
2548
+	/**
2549
+	 * @return void
2550
+	 * @throws EE_Error
2551
+	 * @throws InvalidArgumentException
2552
+	 * @throws InvalidDataTypeException
2553
+	 * @throws InvalidInterfaceException
2554
+	 */
2555
+	protected function _update_default_event_settings()
2556
+	{
2557
+		$form = $this->_default_event_settings_form();
2558
+		if ($form->was_submitted()) {
2559
+			$form->receive_form_submission();
2560
+			if ($form->is_valid()) {
2561
+				$registration_config = EE_Registry::instance()->CFG->registration;
2562
+				$valid_data          = $form->valid_data();
2563
+				if (isset($valid_data['default_reg_status'])) {
2564
+					$registration_config->default_STS_ID = $valid_data['default_reg_status'];
2565
+				}
2566
+				if (isset($valid_data['default_max_tickets'])) {
2567
+					$registration_config->default_maximum_number_of_tickets = $valid_data['default_max_tickets'];
2568
+				}
2569
+				do_action(
2570
+					'AHEE__Events_Admin_Page___update_default_event_settings',
2571
+					$valid_data,
2572
+					EE_Registry::instance()->CFG,
2573
+					$this
2574
+				);
2575
+				// update because data was valid!
2576
+				EE_Registry::instance()->CFG->update_espresso_config();
2577
+				EE_Error::overwrite_success();
2578
+				EE_Error::add_success(
2579
+					esc_html__('Default Event Settings were updated', 'event_espresso')
2580
+				);
2581
+			}
2582
+		}
2583
+		$this->_redirect_after_action(0, '', '', ['action' => 'default_event_settings'], true);
2584
+	}
2585
+
2586
+
2587
+	/*************        Templates        *************
21 2588
      *
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
-                    'order' => 10,
270
-                ],
271
-                'list_table'    => 'Events_Admin_List_Table',
272
-                'help_tabs'     => [
273
-                    'events_overview_help_tab'                       => [
274
-                        'title'    => esc_html__('Events Overview', 'event_espresso'),
275
-                        'filename' => 'events_overview',
276
-                    ],
277
-                    'events_overview_table_column_headings_help_tab' => [
278
-                        'title'    => esc_html__('Events Overview Table Column Headings', 'event_espresso'),
279
-                        'filename' => 'events_overview_table_column_headings',
280
-                    ],
281
-                    'events_overview_filters_help_tab'               => [
282
-                        'title'    => esc_html__('Events Overview Filters', 'event_espresso'),
283
-                        'filename' => 'events_overview_filters',
284
-                    ],
285
-                    'events_overview_view_help_tab'                  => [
286
-                        'title'    => esc_html__('Events Overview Views', 'event_espresso'),
287
-                        'filename' => 'events_overview_views',
288
-                    ],
289
-                    'events_overview_other_help_tab'                 => [
290
-                        'title'    => esc_html__('Events Overview Other', 'event_espresso'),
291
-                        'filename' => 'events_overview_other',
292
-                    ],
293
-                ],
294
-                'require_nonce' => false,
295
-            ],
296
-            'create_new'             => [
297
-                'nav'           => [
298
-                    'label'      => esc_html__('Add New Event', 'event_espresso'),
299
-                    'order'      => 5,
300
-                    'persistent' => false,
301
-                ],
302
-                'metaboxes'     => ['_register_event_editor_meta_boxes'],
303
-                'help_tabs'     => [
304
-                    'event_editor_help_tab'                            => [
305
-                        'title'    => esc_html__('Event Editor', 'event_espresso'),
306
-                        'filename' => 'event_editor',
307
-                    ],
308
-                    'event_editor_title_richtexteditor_help_tab'       => [
309
-                        'title'    => esc_html__('Event Title & Rich Text Editor', 'event_espresso'),
310
-                        'filename' => 'event_editor_title_richtexteditor',
311
-                    ],
312
-                    'event_editor_venue_details_help_tab'              => [
313
-                        'title'    => esc_html__('Event Venue Details', 'event_espresso'),
314
-                        'filename' => 'event_editor_venue_details',
315
-                    ],
316
-                    'event_editor_event_datetimes_help_tab'            => [
317
-                        'title'    => esc_html__('Event Datetimes', 'event_espresso'),
318
-                        'filename' => 'event_editor_event_datetimes',
319
-                    ],
320
-                    'event_editor_event_tickets_help_tab'              => [
321
-                        'title'    => esc_html__('Event Tickets', 'event_espresso'),
322
-                        'filename' => 'event_editor_event_tickets',
323
-                    ],
324
-                    'event_editor_event_registration_options_help_tab' => [
325
-                        'title'    => esc_html__('Event Registration Options', 'event_espresso'),
326
-                        'filename' => 'event_editor_event_registration_options',
327
-                    ],
328
-                    'event_editor_tags_categories_help_tab'            => [
329
-                        'title'    => esc_html__('Event Tags & Categories', 'event_espresso'),
330
-                        'filename' => 'event_editor_tags_categories',
331
-                    ],
332
-                    'event_editor_questions_registrants_help_tab'      => [
333
-                        'title'    => esc_html__('Questions for Registrants', 'event_espresso'),
334
-                        'filename' => 'event_editor_questions_registrants',
335
-                    ],
336
-                    'event_editor_save_new_event_help_tab'             => [
337
-                        'title'    => esc_html__('Save New Event', 'event_espresso'),
338
-                        'filename' => 'event_editor_save_new_event',
339
-                    ],
340
-                    'event_editor_other_help_tab'                      => [
341
-                        'title'    => esc_html__('Event Other', 'event_espresso'),
342
-                        'filename' => 'event_editor_other',
343
-                    ],
344
-                ],
345
-                'qtips'         => ['EE_Event_Editor_Decaf_Tips'],
346
-                'require_nonce' => false,
347
-            ],
348
-            'edit'                   => [
349
-                'nav'           => [
350
-                    'label'      => esc_html__('Edit Event', 'event_espresso'),
351
-                    'order'      => 5,
352
-                    'persistent' => false,
353
-                    'url'        => $post_id
354
-                        ? EE_Admin_Page::add_query_args_and_nonce(
355
-                            ['post' => $post_id, 'action' => 'edit'],
356
-                            $this->_current_page_view_url
357
-                        )
358
-                        : $this->_admin_base_url,
359
-                ],
360
-                'metaboxes'     => ['_register_event_editor_meta_boxes'],
361
-                'help_tabs'     => [
362
-                    'event_editor_help_tab'                            => [
363
-                        'title'    => esc_html__('Event Editor', 'event_espresso'),
364
-                        'filename' => 'event_editor',
365
-                    ],
366
-                    'event_editor_title_richtexteditor_help_tab'       => [
367
-                        'title'    => esc_html__('Event Title & Rich Text Editor', 'event_espresso'),
368
-                        'filename' => 'event_editor_title_richtexteditor',
369
-                    ],
370
-                    'event_editor_venue_details_help_tab'              => [
371
-                        'title'    => esc_html__('Event Venue Details', 'event_espresso'),
372
-                        'filename' => 'event_editor_venue_details',
373
-                    ],
374
-                    'event_editor_event_datetimes_help_tab'            => [
375
-                        'title'    => esc_html__('Event Datetimes', 'event_espresso'),
376
-                        'filename' => 'event_editor_event_datetimes',
377
-                    ],
378
-                    'event_editor_event_tickets_help_tab'              => [
379
-                        'title'    => esc_html__('Event Tickets', 'event_espresso'),
380
-                        'filename' => 'event_editor_event_tickets',
381
-                    ],
382
-                    'event_editor_event_registration_options_help_tab' => [
383
-                        'title'    => esc_html__('Event Registration Options', 'event_espresso'),
384
-                        'filename' => 'event_editor_event_registration_options',
385
-                    ],
386
-                    'event_editor_tags_categories_help_tab'            => [
387
-                        'title'    => esc_html__('Event Tags & Categories', 'event_espresso'),
388
-                        'filename' => 'event_editor_tags_categories',
389
-                    ],
390
-                    'event_editor_questions_registrants_help_tab'      => [
391
-                        'title'    => esc_html__('Questions for Registrants', 'event_espresso'),
392
-                        'filename' => 'event_editor_questions_registrants',
393
-                    ],
394
-                    'event_editor_save_new_event_help_tab'             => [
395
-                        'title'    => esc_html__('Save New Event', 'event_espresso'),
396
-                        'filename' => 'event_editor_save_new_event',
397
-                    ],
398
-                    'event_editor_other_help_tab'                      => [
399
-                        'title'    => esc_html__('Event Other', 'event_espresso'),
400
-                        'filename' => 'event_editor_other',
401
-                    ],
402
-                ],
403
-                'require_nonce' => false,
404
-            ],
405
-            'default_event_settings' => [
406
-                'nav'           => [
407
-                    'label' => esc_html__('Default Settings', 'event_espresso'),
408
-                    'order' => 40,
409
-                ],
410
-                'metaboxes'     => array_merge($this->_default_espresso_metaboxes, ['_publish_post_box']),
411
-                'labels'        => [
412
-                    'publishbox' => esc_html__('Update Settings', 'event_espresso'),
413
-                ],
414
-                'help_tabs'     => [
415
-                    'default_settings_help_tab'        => [
416
-                        'title'    => esc_html__('Default Event Settings', 'event_espresso'),
417
-                        'filename' => 'events_default_settings',
418
-                    ],
419
-                    'default_settings_status_help_tab' => [
420
-                        'title'    => esc_html__('Default Registration Status', 'event_espresso'),
421
-                        'filename' => 'events_default_settings_status',
422
-                    ],
423
-                    'default_maximum_tickets_help_tab' => [
424
-                        'title'    => esc_html__('Default Maximum Tickets Per Order', 'event_espresso'),
425
-                        'filename' => 'events_default_settings_max_tickets',
426
-                    ],
427
-                ],
428
-                'require_nonce' => false,
429
-            ],
430
-            // template settings
431
-            'template_settings'      => [
432
-                'nav'           => [
433
-                    'label' => esc_html__('Templates', 'event_espresso'),
434
-                    'order' => 30,
435
-                ],
436
-                'metaboxes'     => $this->_default_espresso_metaboxes,
437
-                'help_tabs'     => [
438
-                    'general_settings_templates_help_tab' => [
439
-                        'title'    => esc_html__('Templates', 'event_espresso'),
440
-                        'filename' => 'general_settings_templates',
441
-                    ],
442
-                ],
443
-                'require_nonce' => false,
444
-            ],
445
-            // event category stuff
446
-            'add_category'           => [
447
-                'nav'           => [
448
-                    'label'      => esc_html__('Add Category', 'event_espresso'),
449
-                    'order'      => 15,
450
-                    'persistent' => false,
451
-                ],
452
-                'help_tabs'     => [
453
-                    'add_category_help_tab' => [
454
-                        'title'    => esc_html__('Add New Event Category', 'event_espresso'),
455
-                        'filename' => 'events_add_category',
456
-                    ],
457
-                ],
458
-                'metaboxes'     => ['_publish_post_box'],
459
-                'require_nonce' => false,
460
-            ],
461
-            'edit_category'          => [
462
-                'nav'           => [
463
-                    'label'      => esc_html__('Edit Category', 'event_espresso'),
464
-                    'order'      => 15,
465
-                    'persistent' => false,
466
-                    'url'        => $EVT_CAT_ID
467
-                        ? add_query_arg(
468
-                            ['EVT_CAT_ID' => $EVT_CAT_ID],
469
-                            $this->_current_page_view_url
470
-                        )
471
-                        : $this->_admin_base_url,
472
-                ],
473
-                'help_tabs'     => [
474
-                    'edit_category_help_tab' => [
475
-                        'title'    => esc_html__('Edit Event Category', 'event_espresso'),
476
-                        'filename' => 'events_edit_category',
477
-                    ],
478
-                ],
479
-                'metaboxes'     => ['_publish_post_box'],
480
-                'require_nonce' => false,
481
-            ],
482
-            'category_list'          => [
483
-                'nav'           => [
484
-                    'label' => esc_html__('Categories', 'event_espresso'),
485
-                    'order' => 20,
486
-                ],
487
-                'list_table'    => 'Event_Categories_Admin_List_Table',
488
-                'help_tabs'     => [
489
-                    'events_categories_help_tab'                       => [
490
-                        'title'    => esc_html__('Event Categories', 'event_espresso'),
491
-                        'filename' => 'events_categories',
492
-                    ],
493
-                    'events_categories_table_column_headings_help_tab' => [
494
-                        'title'    => esc_html__('Event Categories Table Column Headings', 'event_espresso'),
495
-                        'filename' => 'events_categories_table_column_headings',
496
-                    ],
497
-                    'events_categories_view_help_tab'                  => [
498
-                        'title'    => esc_html__('Event Categories Views', 'event_espresso'),
499
-                        'filename' => 'events_categories_views',
500
-                    ],
501
-                    'events_categories_other_help_tab'                 => [
502
-                        'title'    => esc_html__('Event Categories Other', 'event_espresso'),
503
-                        'filename' => 'events_categories_other',
504
-                    ],
505
-                ],
506
-                'metaboxes'     => $this->_default_espresso_metaboxes,
507
-                'require_nonce' => false,
508
-            ],
509
-            'preview_deletion'       => [
510
-                'nav'           => [
511
-                    'label'      => esc_html__('Preview Deletion', 'event_espresso'),
512
-                    'order'      => 15,
513
-                    'persistent' => false,
514
-                    'url'        => '',
515
-                ],
516
-                'require_nonce' => false,
517
-            ],
518
-        ];
519
-    }
520
-
521
-
522
-    /**
523
-     * Used to register any global screen options if necessary for every route in this admin page group.
524
-     */
525
-    protected function _add_screen_options()
526
-    {
527
-    }
528
-
529
-
530
-    /**
531
-     * Implementing the screen options for the 'default' route.
532
-     *
533
-     * @throws InvalidArgumentException
534
-     * @throws InvalidDataTypeException
535
-     * @throws InvalidInterfaceException
536
-     */
537
-    protected function _add_screen_options_default()
538
-    {
539
-        $this->_per_page_screen_option();
540
-    }
541
-
542
-
543
-    /**
544
-     * Implementing screen options for the category list route.
545
-     *
546
-     * @throws InvalidArgumentException
547
-     * @throws InvalidDataTypeException
548
-     * @throws InvalidInterfaceException
549
-     */
550
-    protected function _add_screen_options_category_list()
551
-    {
552
-        $page_title              = $this->_admin_page_title;
553
-        $this->_admin_page_title = esc_html__('Categories', 'event_espresso');
554
-        $this->_per_page_screen_option();
555
-        $this->_admin_page_title = $page_title;
556
-    }
557
-
558
-
559
-    /**
560
-     * Used to register any global feature pointers for the admin page group.
561
-     */
562
-    protected function _add_feature_pointers()
563
-    {
564
-    }
565
-
566
-
567
-    /**
568
-     * Registers and enqueues any global scripts and styles for the entire admin page group.
569
-     */
570
-    public function load_scripts_styles()
571
-    {
572
-        wp_register_style(
573
-            'events-admin-css',
574
-            EVENTS_ASSETS_URL . 'events-admin-page.css',
575
-            [],
576
-            EVENT_ESPRESSO_VERSION
577
-        );
578
-        wp_register_style(
579
-            'ee-cat-admin',
580
-            EVENTS_ASSETS_URL . 'ee-cat-admin.css',
581
-            [],
582
-            EVENT_ESPRESSO_VERSION
583
-        );
584
-        wp_enqueue_style('events-admin-css');
585
-        wp_enqueue_style('ee-cat-admin');
586
-        // scripts
587
-        wp_register_script(
588
-            'event_editor_js',
589
-            EVENTS_ASSETS_URL . 'event_editor.js',
590
-            ['ee_admin_js', 'jquery-ui-slider', 'jquery-ui-timepicker-addon'],
591
-            EVENT_ESPRESSO_VERSION,
592
-            true
593
-        );
594
-    }
595
-
596
-
597
-    /**
598
-     * Enqueuing scripts and styles specific to this view
599
-     */
600
-    public function load_scripts_styles_create_new()
601
-    {
602
-        $this->load_scripts_styles_edit();
603
-    }
604
-
605
-
606
-    /**
607
-     * Enqueuing scripts and styles specific to this view
608
-     */
609
-    public function load_scripts_styles_edit()
610
-    {
611
-        // styles
612
-        wp_enqueue_style('espresso-ui-theme');
613
-        wp_register_style(
614
-            'event-editor-css',
615
-            EVENTS_ASSETS_URL . 'event-editor.css',
616
-            ['ee-admin-css'],
617
-            EVENT_ESPRESSO_VERSION
618
-        );
619
-        wp_enqueue_style('event-editor-css');
620
-        // scripts
621
-        if (! $this->admin_config->useAdvancedEditor()) {
622
-            wp_register_script(
623
-                'event-datetime-metabox',
624
-                EVENTS_ASSETS_URL . 'event-datetime-metabox.js',
625
-                ['event_editor_js', 'ee-datepicker'],
626
-                EVENT_ESPRESSO_VERSION
627
-            );
628
-            wp_enqueue_script('event-datetime-metabox');
629
-        }
630
-    }
631
-
632
-
633
-    /**
634
-     * Populating the _views property for the category list table view.
635
-     */
636
-    protected function _set_list_table_views_category_list()
637
-    {
638
-        $this->_views = [
639
-            'all' => [
640
-                'slug'        => 'all',
641
-                'label'       => esc_html__('All', 'event_espresso'),
642
-                'count'       => 0,
643
-                'bulk_action' => [
644
-                    'delete_categories' => esc_html__('Delete Permanently', 'event_espresso'),
645
-                ],
646
-            ],
647
-        ];
648
-    }
649
-
650
-
651
-    /**
652
-     * For adding anything that fires on the admin_init hook for any route within this admin page group.
653
-     */
654
-    public function admin_init()
655
-    {
656
-        EE_Registry::$i18n_js_strings['image_confirm'] = esc_html__(
657
-            'Do you really want to delete this image? Please remember to update your event to complete the removal.',
658
-            'event_espresso'
659
-        );
660
-    }
661
-
662
-
663
-    /**
664
-     * For adding anything that should be triggered on the admin_notices hook for any route within this admin page
665
-     * group.
666
-     */
667
-    public function admin_notices()
668
-    {
669
-    }
670
-
671
-
672
-    /**
673
-     * For adding anything that should be triggered on the `admin_print_footer_scripts` hook for any route within
674
-     * this admin page group.
675
-     */
676
-    public function admin_footer_scripts()
677
-    {
678
-    }
679
-
680
-
681
-    /**
682
-     * Call this function to verify if an event is public and has tickets for sale.  If it does, then we need to show a
683
-     * warning (via EE_Error::add_error());
684
-     *
685
-     * @param EE_Event $event Event object
686
-     * @param string   $req_type
687
-     * @return void
688
-     * @throws EE_Error
689
-     * @throws ReflectionException
690
-     */
691
-    public function verify_event_edit($event = null, $req_type = '')
692
-    {
693
-        // don't need to do this when processing
694
-        if (! empty($req_type)) {
695
-            return;
696
-        }
697
-        // no event?
698
-        if (! $event instanceof EE_Event) {
699
-            $event = $this->_cpt_model_obj;
700
-        }
701
-        // STILL no event?
702
-        if (! $event instanceof EE_Event) {
703
-            return;
704
-        }
705
-        $orig_status = $event->status();
706
-        // first check if event is active.
707
-        if (
708
-            $orig_status === EEM_Event::cancelled
709
-            || $orig_status === EEM_Event::postponed
710
-            || $event->is_expired()
711
-            || $event->is_inactive()
712
-        ) {
713
-            return;
714
-        }
715
-        // made it here so it IS active... next check that any of the tickets are sold.
716
-        if ($event->is_sold_out(true)) {
717
-            if ($orig_status !== EEM_Event::sold_out && $event->status() !== $orig_status) {
718
-                EE_Error::add_attention(
719
-                    sprintf(
720
-                        esc_html__(
721
-                            '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.',
722
-                            'event_espresso'
723
-                        ),
724
-                        EEH_Template::pretty_status(EEM_Event::sold_out, false, 'sentence')
725
-                    )
726
-                );
727
-            }
728
-            return;
729
-        }
730
-        if ($orig_status === EEM_Event::sold_out) {
731
-            EE_Error::add_attention(
732
-                sprintf(
733
-                    esc_html__(
734
-                        '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.',
735
-                        'event_espresso'
736
-                    ),
737
-                    EEH_Template::pretty_status($event->status(), false, 'sentence')
738
-                )
739
-            );
740
-        }
741
-        // now we need to determine if the event has any tickets on sale.  If not then we dont' show the error
742
-        if (! $event->tickets_on_sale()) {
743
-            return;
744
-        }
745
-        // made it here so show warning
746
-        $this->_edit_event_warning();
747
-    }
748
-
749
-
750
-    /**
751
-     * This is the text used for when an event is being edited that is public and has tickets for sale.
752
-     * When needed, hook this into a EE_Error::add_error() notice.
753
-     *
754
-     * @access protected
755
-     * @return void
756
-     */
757
-    protected function _edit_event_warning()
758
-    {
759
-        // we don't want to add warnings during these requests
760
-        if ($this->request->getRequestParam('action') === 'editpost') {
761
-            return;
762
-        }
763
-        EE_Error::add_attention(
764
-            sprintf(
765
-                esc_html__(
766
-                    'Your event is open for registration. Making changes may disrupt any transactions in progress. %sLearn more%s',
767
-                    'event_espresso'
768
-                ),
769
-                '<a class="espresso-help-tab-lnk ee-help-tab-link">',
770
-                '</a>'
771
-            )
772
-        );
773
-    }
774
-
775
-
776
-    /**
777
-     * When a user is creating a new event, notify them if they haven't set their timezone.
778
-     * Otherwise, do the normal logic
779
-     *
780
-     * @return void
781
-     * @throws EE_Error
782
-     * @throws InvalidArgumentException
783
-     * @throws InvalidDataTypeException
784
-     * @throws InvalidInterfaceException
785
-     */
786
-    protected function _create_new_cpt_item()
787
-    {
788
-        $has_timezone_string = get_option('timezone_string');
789
-        // only nag them about setting their timezone if it's their first event, and they haven't already done it
790
-        if (! $has_timezone_string && ! EEM_Event::instance()->exists([])) {
791
-            EE_Error::add_attention(
792
-                sprintf(
793
-                    esc_html__(
794
-                        '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',
795
-                        'event_espresso'
796
-                    ),
797
-                    '<br>',
798
-                    '<select id="timezone_string" name="timezone_string" aria-describedby="timezone-description">'
799
-                    . EEH_DTT_Helper::wp_timezone_choice('', EEH_DTT_Helper::get_user_locale())
800
-                    . '</select>',
801
-                    '<button class="button button--secondary timezone-submit">',
802
-                    '</button><span class="spinner"></span>'
803
-                ),
804
-                __FILE__,
805
-                __FUNCTION__,
806
-                __LINE__
807
-            );
808
-        }
809
-        parent::_create_new_cpt_item();
810
-    }
811
-
812
-
813
-    /**
814
-     * Sets the _views property for the default route in this admin page group.
815
-     */
816
-    protected function _set_list_table_views_default()
817
-    {
818
-        $this->_views = [
819
-            'all'   => [
820
-                'slug'        => 'all',
821
-                'label'       => esc_html__('View All Events', 'event_espresso'),
822
-                'count'       => 0,
823
-                'bulk_action' => [
824
-                    'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
825
-                ],
826
-            ],
827
-            'draft' => [
828
-                'slug'        => 'draft',
829
-                'label'       => esc_html__('Draft', 'event_espresso'),
830
-                'count'       => 0,
831
-                'bulk_action' => [
832
-                    'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
833
-                ],
834
-            ],
835
-        ];
836
-        if (EE_Registry::instance()->CAP->current_user_can('ee_delete_events', 'espresso_events_trash_events')) {
837
-            $this->_views['trash'] = [
838
-                'slug'        => 'trash',
839
-                'label'       => esc_html__('Trash', 'event_espresso'),
840
-                'count'       => 0,
841
-                'bulk_action' => [
842
-                    'restore_events' => esc_html__('Restore From Trash', 'event_espresso'),
843
-                    'delete_events'  => esc_html__('Delete Permanently', 'event_espresso'),
844
-                ],
845
-            ];
846
-        }
847
-    }
848
-
849
-
850
-    /**
851
-     * Provides the legend item array for the default list table view.
852
-     *
853
-     * @return array
854
-     * @throws EE_Error
855
-     * @throws EE_Error
856
-     */
857
-    protected function _event_legend_items()
858
-    {
859
-        $items    = [
860
-            'view_details'   => [
861
-                'class' => 'dashicons dashicons-visibility',
862
-                'desc'  => esc_html__('View Event', 'event_espresso'),
863
-            ],
864
-            'edit_event'     => [
865
-                'class' => 'dashicons dashicons-calendar-alt',
866
-                'desc'  => esc_html__('Edit Event Details', 'event_espresso'),
867
-            ],
868
-            'view_attendees' => [
869
-                'class' => 'dashicons dashicons-groups',
870
-                'desc'  => esc_html__('View Registrations for Event', 'event_espresso'),
871
-            ],
872
-        ];
873
-        $items    = apply_filters('FHEE__Events_Admin_Page___event_legend_items__items', $items);
874
-        $statuses = [
875
-            'sold_out_status'  => [
876
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::sold_out,
877
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::sold_out, false, 'sentence'),
878
-            ],
879
-            'active_status'    => [
880
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::active,
881
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::active, false, 'sentence'),
882
-            ],
883
-            'upcoming_status'  => [
884
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::upcoming,
885
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::upcoming, false, 'sentence'),
886
-            ],
887
-            'postponed_status' => [
888
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::postponed,
889
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::postponed, false, 'sentence'),
890
-            ],
891
-            'cancelled_status' => [
892
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::cancelled,
893
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::cancelled, false, 'sentence'),
894
-            ],
895
-            'expired_status'   => [
896
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::expired,
897
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::expired, false, 'sentence'),
898
-            ],
899
-            'inactive_status'  => [
900
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::inactive,
901
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::inactive, false, 'sentence'),
902
-            ],
903
-        ];
904
-        $statuses = apply_filters('FHEE__Events_Admin_Page__event_legend_items__statuses', $statuses);
905
-        return array_merge($items, $statuses);
906
-    }
907
-
908
-
909
-    /**
910
-     * @return EEM_Event
911
-     * @throws EE_Error
912
-     * @throws InvalidArgumentException
913
-     * @throws InvalidDataTypeException
914
-     * @throws InvalidInterfaceException
915
-     * @throws ReflectionException
916
-     */
917
-    private function _event_model()
918
-    {
919
-        if (! $this->_event_model instanceof EEM_Event) {
920
-            $this->_event_model = EE_Registry::instance()->load_model('Event');
921
-        }
922
-        return $this->_event_model;
923
-    }
924
-
925
-
926
-    /**
927
-     * Adds extra buttons to the WP CPT permalink field row.
928
-     * Method is called from parent and is hooked into the wp 'get_sample_permalink_html' filter.
929
-     *
930
-     * @param string $return    the current html
931
-     * @param int    $id        the post id for the page
932
-     * @param string $new_title What the title is
933
-     * @param string $new_slug  what the slug is
934
-     * @return string            The new html string for the permalink area
935
-     */
936
-    public function extra_permalink_field_buttons($return, $id, $new_title, $new_slug)
937
-    {
938
-        // make sure this is only when editing
939
-        if (! empty($id)) {
940
-            $post = get_post($id);
941
-            $return .= '<a class="button button--small button--secondary" onclick="prompt(\'Shortcode:\', jQuery(\'#shortcode\').val()); return false;" href="#"  tabindex="-1">'
942
-                       . esc_html__('Shortcode', 'event_espresso')
943
-                       . '</a> ';
944
-            $return .= '<input id="shortcode" type="hidden" value="[ESPRESSO_TICKET_SELECTOR event_id='
945
-                       . $post->ID
946
-                       . ']">';
947
-        }
948
-        return $return;
949
-    }
950
-
951
-
952
-    /**
953
-     * _events_overview_list_table
954
-     * This contains the logic for showing the events_overview list
955
-     *
956
-     * @access protected
957
-     * @return void
958
-     * @throws DomainException
959
-     * @throws EE_Error
960
-     * @throws InvalidArgumentException
961
-     * @throws InvalidDataTypeException
962
-     * @throws InvalidInterfaceException
963
-     */
964
-    protected function _events_overview_list_table()
965
-    {
966
-        $after_list_table                           = [];
967
-        $links_html = EEH_HTML::div('', '', 'ee-admin-section ee-layout-stack');
968
-        $links_html .= EEH_HTML::h3(esc_html__('Links', 'event_espresso'));
969
-        $links_html .= EEH_HTML::div(
970
-            EEH_Template::get_button_or_link(
971
-                get_post_type_archive_link('espresso_events'),
972
-                esc_html__('View Event Archive Page', 'event_espresso'),
973
-                'button button--small button--secondary'
974
-            ),
975
-            '',
976
-            'ee-admin-button-row ee-admin-button-row--align-start'
977
-        );
978
-        $links_html .= EEH_HTML::divx();
979
-
980
-        $after_list_table['view_event_list_button'] = $links_html;
981
-
982
-        $after_list_table['legend'] = $this->_display_legend($this->_event_legend_items());
983
-        $this->_admin_page_title                    .= ' ' . $this->get_action_link_or_button(
984
-            'create_new',
985
-            'add',
986
-            [],
987
-            'add-new-h2'
988
-        );
989
-
990
-        $this->_template_args['after_list_table']   = array_merge(
991
-            (array) $this->_template_args['after_list_table'],
992
-            $after_list_table
993
-        );
994
-        $this->display_admin_list_table_page_with_no_sidebar();
995
-    }
996
-
997
-
998
-    /**
999
-     * this allows for extra misc actions in the default WP publish box
1000
-     *
1001
-     * @return void
1002
-     * @throws DomainException
1003
-     * @throws EE_Error
1004
-     * @throws InvalidArgumentException
1005
-     * @throws InvalidDataTypeException
1006
-     * @throws InvalidInterfaceException
1007
-     * @throws ReflectionException
1008
-     */
1009
-    public function extra_misc_actions_publish_box()
1010
-    {
1011
-        $this->_generate_publish_box_extra_content();
1012
-    }
1013
-
1014
-
1015
-    /**
1016
-     * This is hooked into the WordPress do_action('save_post') hook and runs after the custom post type has been
1017
-     * saved.
1018
-     * Typically you would use this to save any additional data.
1019
-     * Keep in mind also that "save_post" runs on EVERY post update to the database.
1020
-     * ALSO very important.  When a post transitions from scheduled to published,
1021
-     * the save_post action is fired but you will NOT have any _POST data containing any extra info you may have from
1022
-     * other meta saves. So MAKE sure that you handle this accordingly.
1023
-     *
1024
-     * @access protected
1025
-     * @abstract
1026
-     * @param string $post_id The ID of the cpt that was saved (so you can link relationally)
1027
-     * @param WP_Post $post    The post object of the cpt that was saved.
1028
-     * @return void
1029
-     * @throws EE_Error
1030
-     * @throws InvalidArgumentException
1031
-     * @throws InvalidDataTypeException
1032
-     * @throws InvalidInterfaceException
1033
-     * @throws ReflectionException
1034
-     */
1035
-    protected function _insert_update_cpt_item($post_id, $post)
1036
-    {
1037
-        if ($post instanceof WP_Post && $post->post_type !== 'espresso_events') {
1038
-            // get out we're not processing an event save.
1039
-            return;
1040
-        }
1041
-        $event_values = [
1042
-            'EVT_member_only'     => $this->request->getRequestParam('member_only', false, 'bool'),
1043
-            'EVT_allow_overflow'  => $this->request->getRequestParam('EVT_allow_overflow', false, 'bool'),
1044
-            'EVT_timezone_string' => $this->request->getRequestParam('timezone_string'),
1045
-        ];
1046
-        // check if the new EDTR reg options meta box is being used, and if so, don't run updates for legacy version
1047
-        if (! $this->admin_config->useAdvancedEditor() || ! $this->feature->allowed('use_reg_options_meta_box')) {
1048
-            $event_values['EVT_display_ticket_selector']     = $this->request->getRequestParam(
1049
-                'display_ticket_selector',
1050
-                false,
1051
-                'bool'
1052
-            );
1053
-            $event_values['EVT_additional_limit']            = min(
1054
-                apply_filters('FHEE__EE_Events_Admin__insert_update_cpt_item__EVT_additional_limit_max', 255),
1055
-                $this->request->getRequestParam('additional_limit', null, 'int')
1056
-            );
1057
-            $event_values['EVT_default_registration_status'] = $this->request->getRequestParam(
1058
-                'EVT_default_registration_status',
1059
-                EE_Registry::instance()->CFG->registration->default_STS_ID
1060
-            );
1061
-
1062
-            $event_values['EVT_external_URL'] = $this->request->getRequestParam('externalURL');
1063
-            $event_values['EVT_phone']        = $this->request->getRequestParam('event_phone');
1064
-            $event_values['EVT_display_desc'] = $this->request->getRequestParam('display_desc', false, 'bool');
1065
-        }
1066
-        // update event
1067
-        $success = $this->_event_model()->update_by_ID($event_values, $post_id);
1068
-        // get event_object for other metaboxes...
1069
-        // though it would seem to make sense to just use $this->_event_model()->get_one_by_ID( $post_id )..
1070
-        // i have to setup where conditions to override the filters in the model
1071
-        // that filter out autodraft and inherit statuses so we GET the inherit id!
1072
-        $event = $this->_event_model()->get_one(
1073
-            [
1074
-                [
1075
-                    $this->_event_model()->primary_key_name() => $post_id,
1076
-                    'OR'                                      => [
1077
-                        'status'   => $post->post_status,
1078
-                        // if trying to "Publish" a sold out event, it's status will get switched back to "sold_out" in the db,
1079
-                        // but the returned object here has a status of "publish", so use the original post status as well
1080
-                        'status*1' => $this->request->getRequestParam('original_post_status'),
1081
-                    ],
1082
-                ],
1083
-            ]
1084
-        );
1085
-
1086
-        // the following are default callbacks for event attachment updates
1087
-        // that can be overridden by caffeinated functionality and/or addons.
1088
-        $event_update_callbacks = [];
1089
-        if (! $this->admin_config->useAdvancedEditor()) {
1090
-            $event_update_callbacks['_default_venue_update']   = [$this, '_default_venue_update'];
1091
-            $event_update_callbacks['_default_tickets_update'] = [$this, '_default_tickets_update'];
1092
-        }
1093
-        $event_update_callbacks = apply_filters(
1094
-            'FHEE__Events_Admin_Page___insert_update_cpt_item__event_update_callbacks',
1095
-            $event_update_callbacks
1096
-        );
1097
-
1098
-        $att_success = true;
1099
-        foreach ($event_update_callbacks as $e_callback) {
1100
-            $_success = is_callable($e_callback)
1101
-                ? $e_callback($event, $this->request->requestParams())
1102
-                : false;
1103
-            // if ANY of these updates fail then we want the appropriate global error message
1104
-            $att_success = $_success !== false ? $att_success : false;
1105
-        }
1106
-        // any errors?
1107
-        if ($success && $att_success === false) {
1108
-            EE_Error::add_error(
1109
-                esc_html__(
1110
-                    'Event Details saved successfully but something went wrong with saving attachments.',
1111
-                    'event_espresso'
1112
-                ),
1113
-                __FILE__,
1114
-                __FUNCTION__,
1115
-                __LINE__
1116
-            );
1117
-        } elseif ($success === false) {
1118
-            EE_Error::add_error(
1119
-                esc_html__('Event Details did not save successfully.', 'event_espresso'),
1120
-                __FILE__,
1121
-                __FUNCTION__,
1122
-                __LINE__
1123
-            );
1124
-        }
1125
-    }
1126
-
1127
-
1128
-    /**
1129
-     * @param int $post_id
1130
-     * @param int $revision_id
1131
-     * @throws EE_Error
1132
-     * @throws EE_Error
1133
-     * @throws ReflectionException
1134
-     * @see parent::restore_item()
1135
-     */
1136
-    protected function _restore_cpt_item($post_id, $revision_id)
1137
-    {
1138
-        // copy existing event meta to new post
1139
-        $post_evt = $this->_event_model()->get_one_by_ID($post_id);
1140
-        if ($post_evt instanceof EE_Event) {
1141
-            // meta revision restore
1142
-            $post_evt->restore_revision($revision_id);
1143
-            // related objs restore
1144
-            $post_evt->restore_revision($revision_id, ['Venue', 'Datetime', 'Price']);
1145
-        }
1146
-    }
1147
-
1148
-
1149
-    /**
1150
-     * Attach the venue to the Event
1151
-     *
1152
-     * @param EE_Event $event Event Object to add the venue to
1153
-     * @param array    $data  The request data from the form
1154
-     * @return bool           Success or fail.
1155
-     * @throws EE_Error
1156
-     * @throws ReflectionException
1157
-     */
1158
-    protected function _default_venue_update(EE_Event $event, $data)
1159
-    {
1160
-        require_once(EE_MODELS . 'EEM_Venue.model.php');
1161
-        $venue_model = EE_Registry::instance()->load_model('Venue');
1162
-        $venue_id    = ! empty($data['venue_id']) ? $data['venue_id'] : null;
1163
-        // very important.  If we don't have a venue name...
1164
-        // then we'll get out because not necessary to create empty venue
1165
-        if (empty($data['venue_title'])) {
1166
-            return false;
1167
-        }
1168
-        $venue_array = [
1169
-            'VNU_wp_user'         => $event->get('EVT_wp_user'),
1170
-            'VNU_name'            => ! empty($data['venue_title']) ? $data['venue_title'] : null,
1171
-            'VNU_desc'            => ! empty($data['venue_description']) ? $data['venue_description'] : null,
1172
-            'VNU_identifier'      => ! empty($data['venue_identifier']) ? $data['venue_identifier'] : null,
1173
-            'VNU_short_desc'      => ! empty($data['venue_short_description'])
1174
-                ? $data['venue_short_description']
1175
-                : null,
1176
-            'VNU_address'         => ! empty($data['address']) ? $data['address'] : null,
1177
-            'VNU_address2'        => ! empty($data['address2']) ? $data['address2'] : null,
1178
-            'VNU_city'            => ! empty($data['city']) ? $data['city'] : null,
1179
-            'STA_ID'              => ! empty($data['state']) ? $data['state'] : null,
1180
-            'CNT_ISO'             => ! empty($data['countries']) ? $data['countries'] : null,
1181
-            'VNU_zip'             => ! empty($data['zip']) ? $data['zip'] : null,
1182
-            'VNU_phone'           => ! empty($data['venue_phone']) ? $data['venue_phone'] : null,
1183
-            'VNU_capacity'        => ! empty($data['venue_capacity']) ? $data['venue_capacity'] : null,
1184
-            'VNU_url'             => ! empty($data['venue_url']) ? $data['venue_url'] : null,
1185
-            'VNU_virtual_phone'   => ! empty($data['virtual_phone']) ? $data['virtual_phone'] : null,
1186
-            'VNU_virtual_url'     => ! empty($data['virtual_url']) ? $data['virtual_url'] : null,
1187
-            'VNU_enable_for_gmap' => isset($data['enable_for_gmap']) ? 1 : 0,
1188
-            'status'              => 'publish',
1189
-        ];
1190
-        // if we've got the venue_id then we're just updating the existing venue so let's do that and then get out.
1191
-        if (! empty($venue_id)) {
1192
-            $update_where  = [$venue_model->primary_key_name() => $venue_id];
1193
-            $rows_affected = $venue_model->update($venue_array, [$update_where]);
1194
-            // we've gotta make sure that the venue is always attached to a revision..
1195
-            // add_relation_to should take care of making sure that the relation is already present.
1196
-            $event->_add_relation_to($venue_id, 'Venue');
1197
-            return $rows_affected > 0;
1198
-        }
1199
-        // we insert the venue
1200
-        $venue_id = $venue_model->insert($venue_array);
1201
-        $event->_add_relation_to($venue_id, 'Venue');
1202
-        return ! empty($venue_id);
1203
-        // when we have the ancestor come in it's already been handled by the revision save.
1204
-    }
1205
-
1206
-
1207
-    /**
1208
-     * Handles saving everything related to Tickets (datetimes, tickets, prices)
1209
-     *
1210
-     * @param EE_Event $event The Event object we're attaching data to
1211
-     * @param array    $data  The request data from the form
1212
-     * @return array
1213
-     * @throws EE_Error
1214
-     * @throws ReflectionException
1215
-     * @throws Exception
1216
-     */
1217
-    protected function _default_tickets_update(EE_Event $event, $data)
1218
-    {
1219
-        if ($this->admin_config->useAdvancedEditor()) {
1220
-            return [];
1221
-        }
1222
-        $datetime       = null;
1223
-        $saved_tickets  = [];
1224
-        $event_timezone = $event->get_timezone();
1225
-        $date_formats   = ['Y-m-d', 'h:i a'];
1226
-        foreach ($data['edit_event_datetimes'] as $row => $datetime_data) {
1227
-            // trim all values to ensure any excess whitespace is removed.
1228
-            $datetime_data                = array_map('trim', $datetime_data);
1229
-            $datetime_data['DTT_EVT_end'] =
1230
-                isset($datetime_data['DTT_EVT_end']) && ! empty($datetime_data['DTT_EVT_end'])
1231
-                    ? $datetime_data['DTT_EVT_end']
1232
-                    : $datetime_data['DTT_EVT_start'];
1233
-            $datetime_values              = [
1234
-                'DTT_ID'        => ! empty($datetime_data['DTT_ID']) ? $datetime_data['DTT_ID'] : null,
1235
-                'DTT_EVT_start' => $datetime_data['DTT_EVT_start'],
1236
-                'DTT_EVT_end'   => $datetime_data['DTT_EVT_end'],
1237
-                'DTT_reg_limit' => empty($datetime_data['DTT_reg_limit']) ? EE_INF : $datetime_data['DTT_reg_limit'],
1238
-                'DTT_order'     => $row,
1239
-            ];
1240
-            // if we have an id then let's get existing object first and then set the new values.
1241
-            //  Otherwise we instantiate a new object for save.
1242
-            if (! empty($datetime_data['DTT_ID'])) {
1243
-                $datetime = EEM_Datetime::instance($event_timezone)->get_one_by_ID($datetime_data['DTT_ID']);
1244
-                if (! $datetime instanceof EE_Datetime) {
1245
-                    throw new RuntimeException(
1246
-                        sprintf(
1247
-                            esc_html__(
1248
-                                'Something went wrong! A valid Datetime could not be retrieved from the database using the supplied ID: %1$d',
1249
-                                'event_espresso'
1250
-                            ),
1251
-                            $datetime_data['DTT_ID']
1252
-                        )
1253
-                    );
1254
-                }
1255
-                $datetime->set_date_format($date_formats[0]);
1256
-                $datetime->set_time_format($date_formats[1]);
1257
-                foreach ($datetime_values as $field => $value) {
1258
-                    $datetime->set($field, $value);
1259
-                }
1260
-            } else {
1261
-                $datetime = EE_Datetime::new_instance($datetime_values, $event_timezone, $date_formats);
1262
-            }
1263
-            if (! $datetime instanceof EE_Datetime) {
1264
-                throw new RuntimeException(
1265
-                    sprintf(
1266
-                        esc_html__(
1267
-                            'Something went wrong! A valid Datetime could not be generated or retrieved using the supplied data: %1$s',
1268
-                            'event_espresso'
1269
-                        ),
1270
-                        print_r($datetime_values, true)
1271
-                    )
1272
-                );
1273
-            }
1274
-            // before going any further make sure our dates are setup correctly
1275
-            // so that the end date is always equal or greater than the start date.
1276
-            if ($datetime->get_raw('DTT_EVT_start') > $datetime->get_raw('DTT_EVT_end')) {
1277
-                $datetime->set('DTT_EVT_end', $datetime->get('DTT_EVT_start'));
1278
-                $datetime = EEH_DTT_Helper::date_time_add($datetime, 'DTT_EVT_end', 'days');
1279
-            }
1280
-            $datetime->save();
1281
-            $event->_add_relation_to($datetime, 'Datetime');
1282
-        }
1283
-        // no datetimes get deleted so we don't do any of that logic here.
1284
-        // update tickets next
1285
-        $old_tickets = isset($data['ticket_IDs']) ? explode(',', $data['ticket_IDs']) : [];
1286
-
1287
-        // set up some default start and end dates in case those are not present in the incoming data
1288
-        $default_start_date = new DateTime('now', new DateTimeZone($event->get_timezone()));
1289
-        $default_start_date = $default_start_date->format($date_formats[0] . ' ' . $date_formats[1]);
1290
-        // use the start date of the first datetime for the end date
1291
-        $first_datetime   = $event->first_datetime();
1292
-        $default_end_date = $first_datetime->start_date_and_time($date_formats[0], $date_formats[1]);
1293
-
1294
-        // now process the incoming data
1295
-        foreach ($data['edit_tickets'] as $row => $ticket_data) {
1296
-            $update_prices = false;
1297
-            $ticket_price  = isset($data['edit_prices'][ $row ][1]['PRC_amount'])
1298
-                ? $data['edit_prices'][ $row ][1]['PRC_amount']
1299
-                : 0;
1300
-            // trim inputs to ensure any excess whitespace is removed.
1301
-            $ticket_data   = array_map('trim', $ticket_data);
1302
-            $ticket_values = [
1303
-                'TKT_ID'          => ! empty($ticket_data['TKT_ID']) ? $ticket_data['TKT_ID'] : null,
1304
-                'TTM_ID'          => ! empty($ticket_data['TTM_ID']) ? $ticket_data['TTM_ID'] : 0,
1305
-                'TKT_name'        => ! empty($ticket_data['TKT_name']) ? $ticket_data['TKT_name'] : '',
1306
-                'TKT_description' => ! empty($ticket_data['TKT_description']) ? $ticket_data['TKT_description'] : '',
1307
-                'TKT_start_date'  => ! empty($ticket_data['TKT_start_date'])
1308
-                    ? $ticket_data['TKT_start_date']
1309
-                    : $default_start_date,
1310
-                'TKT_end_date'    => ! empty($ticket_data['TKT_end_date'])
1311
-                    ? $ticket_data['TKT_end_date']
1312
-                    : $default_end_date,
1313
-                'TKT_qty'         => ! empty($ticket_data['TKT_qty'])
1314
-                                     || (isset($ticket_data['TKT_qty']) && (int) $ticket_data['TKT_qty'] === 0)
1315
-                    ? $ticket_data['TKT_qty']
1316
-                    : EE_INF,
1317
-                'TKT_uses'        => ! empty($ticket_data['TKT_uses'])
1318
-                                     || (isset($ticket_data['TKT_uses']) && (int) $ticket_data['TKT_uses'] === 0)
1319
-                    ? $ticket_data['TKT_uses']
1320
-                    : EE_INF,
1321
-                'TKT_min'         => ! empty($ticket_data['TKT_min']) ? $ticket_data['TKT_min'] : 0,
1322
-                'TKT_max'         => ! empty($ticket_data['TKT_max']) ? $ticket_data['TKT_max'] : EE_INF,
1323
-                'TKT_order'       => isset($ticket_data['TKT_order']) ? $ticket_data['TKT_order'] : $row,
1324
-                'TKT_price'       => $ticket_price,
1325
-                'TKT_row'         => $row,
1326
-            ];
1327
-            // if this is a default ticket, then we need to set the TKT_ID to 0 and update accordingly,
1328
-            // which means in turn that the prices will become new prices as well.
1329
-            if (isset($ticket_data['TKT_is_default']) && $ticket_data['TKT_is_default']) {
1330
-                $ticket_values['TKT_ID']         = 0;
1331
-                $ticket_values['TKT_is_default'] = 0;
1332
-                $update_prices                   = true;
1333
-            }
1334
-            // if we have a TKT_ID then we need to get that existing TKT_obj and update it
1335
-            // we actually do our saves ahead of adding any relations because its entirely possible that this
1336
-            // ticket didn't get removed or added to any datetime in the session but DID have it's items modified.
1337
-            // keep in mind that if the ticket has been sold (and we have changed pricing information),
1338
-            // then we won't be updating the tkt but instead a new tkt will be created and the old one archived.
1339
-            if (! empty($ticket_data['TKT_ID'])) {
1340
-                $existing_ticket = EEM_Ticket::instance($event_timezone)->get_one_by_ID($ticket_data['TKT_ID']);
1341
-                if (! $existing_ticket instanceof EE_Ticket) {
1342
-                    throw new RuntimeException(
1343
-                        sprintf(
1344
-                            esc_html__(
1345
-                                'Something went wrong! A valid Ticket could not be retrieved from the database using the supplied ID: %1$d',
1346
-                                'event_espresso'
1347
-                            ),
1348
-                            $ticket_data['TKT_ID']
1349
-                        )
1350
-                    );
1351
-                }
1352
-                $ticket_sold = $existing_ticket->count_related(
1353
-                    'Registration',
1354
-                    [
1355
-                            [
1356
-                                'STS_ID' => [
1357
-                                    'NOT IN',
1358
-                                    [EEM_Registration::status_id_incomplete],
1359
-                                ],
1360
-                            ],
1361
-                        ]
1362
-                ) > 0;
1363
-                // let's just check the total price for the existing ticket and determine if it matches the new total price.
1364
-                // if they are different then we create a new ticket (if $ticket_sold)
1365
-                // if they aren't different then we go ahead and modify existing ticket.
1366
-                $create_new_ticket = $ticket_sold
1367
-                                     && $ticket_price !== $existing_ticket->price()
1368
-                                     && ! $existing_ticket->deleted();
1369
-                $existing_ticket->set_date_format($date_formats[0]);
1370
-                $existing_ticket->set_time_format($date_formats[1]);
1371
-                // set new values
1372
-                foreach ($ticket_values as $field => $value) {
1373
-                    if ($field == 'TKT_qty') {
1374
-                        $existing_ticket->set_qty($value);
1375
-                    } elseif ($field == 'TKT_price') {
1376
-                        $existing_ticket->set('TKT_price', $ticket_price);
1377
-                    } else {
1378
-                        $existing_ticket->set($field, $value);
1379
-                    }
1380
-                }
1381
-                $ticket = $existing_ticket;
1382
-                // if $create_new_ticket is false then we can safely update the existing ticket.
1383
-                //  Otherwise we have to create a new ticket.
1384
-                if ($create_new_ticket) {
1385
-                    // archive the old ticket first
1386
-                    $existing_ticket->set('TKT_deleted', 1);
1387
-                    $existing_ticket->save();
1388
-                    // make sure this ticket is still recorded in our $saved_tickets
1389
-                    // so we don't run it through the regular trash routine.
1390
-                    $saved_tickets[ $existing_ticket->ID() ] = $existing_ticket;
1391
-                    // create new ticket that's a copy of the existing except,
1392
-                    // (a new id of course and not archived) AND has the new TKT_price associated with it.
1393
-                    $new_ticket = clone $existing_ticket;
1394
-                    $new_ticket->set('TKT_ID', 0);
1395
-                    $new_ticket->set('TKT_deleted', 0);
1396
-                    $new_ticket->set('TKT_sold', 0);
1397
-                    // now we need to make sure that $new prices are created as well and attached to new ticket.
1398
-                    $update_prices = true;
1399
-                    $ticket        = $new_ticket;
1400
-                }
1401
-            } else {
1402
-                // no TKT_id so a new ticket
1403
-                $ticket_values['TKT_price'] = $ticket_price;
1404
-                $ticket                     = EE_Ticket::new_instance($ticket_values, $event_timezone, $date_formats);
1405
-                $update_prices              = true;
1406
-            }
1407
-            if (! $ticket instanceof EE_Ticket) {
1408
-                throw new RuntimeException(
1409
-                    sprintf(
1410
-                        esc_html__(
1411
-                            'Something went wrong! A valid Ticket could not be generated or retrieved using the supplied data: %1$s',
1412
-                            'event_espresso'
1413
-                        ),
1414
-                        print_r($ticket_values, true)
1415
-                    )
1416
-                );
1417
-            }
1418
-            // cap ticket qty by datetime reg limits
1419
-            $ticket->set_qty(min($ticket->qty(), $ticket->qty('reg_limit')));
1420
-            // update ticket.
1421
-            $ticket->save();
1422
-            // before going any further make sure our dates are setup correctly
1423
-            // so that the end date is always equal or greater than the start date.
1424
-            if ($ticket->get_raw('TKT_start_date') > $ticket->get_raw('TKT_end_date')) {
1425
-                $ticket->set('TKT_end_date', $ticket->get('TKT_start_date'));
1426
-                $ticket = EEH_DTT_Helper::date_time_add($ticket, 'TKT_end_date', 'days');
1427
-                $ticket->save();
1428
-            }
1429
-            // initially let's add the ticket to the datetime
1430
-            $datetime->_add_relation_to($ticket, 'Ticket');
1431
-            $saved_tickets[ $ticket->ID() ] = $ticket;
1432
-            // add prices to ticket
1433
-            $prices_data = isset($data['edit_prices'][ $row ]) && is_array($data['edit_prices'][ $row ])
1434
-                ? $data['edit_prices'][ $row ]
1435
-                : [];
1436
-            $this->_add_prices_to_ticket($prices_data, $ticket, $update_prices);
1437
-        }
1438
-        // however now we need to handle permanently deleting tickets via the ui.
1439
-        // Keep in mind that the ui does not allow deleting/archiving tickets that have ticket sold.
1440
-        // However, it does allow for deleting tickets that have no tickets sold,
1441
-        // in which case we want to get rid of permanently because there is no need to save in db.
1442
-        $old_tickets     = isset($old_tickets[0]) && $old_tickets[0] === '' ? [] : $old_tickets;
1443
-        $tickets_removed = array_diff($old_tickets, array_keys($saved_tickets));
1444
-        foreach ($tickets_removed as $id) {
1445
-            $id = absint($id);
1446
-            // get the ticket for this id
1447
-            $ticket_to_remove = EEM_Ticket::instance()->get_one_by_ID($id);
1448
-            if (! $ticket_to_remove instanceof EE_Ticket) {
1449
-                continue;
1450
-            }
1451
-            // need to get all the related datetimes on this ticket and remove from every single one of them
1452
-            // (remember this process can ONLY kick off if there are NO tickets sold)
1453
-            $related_datetimes = $ticket_to_remove->get_many_related('Datetime');
1454
-            foreach ($related_datetimes as $related_datetime) {
1455
-                $ticket_to_remove->_remove_relation_to($related_datetime, 'Datetime');
1456
-            }
1457
-            // need to do the same for prices (except these prices can also be deleted because again,
1458
-            // tickets can only be trashed if they don't have any TKTs sold (otherwise they are just archived))
1459
-            $ticket_to_remove->delete_related_permanently('Price');
1460
-            // finally let's delete this ticket
1461
-            // (which should not be blocked at this point b/c we've removed all our relationships)
1462
-            $ticket_to_remove->delete_permanently();
1463
-        }
1464
-        return [$datetime, $saved_tickets];
1465
-    }
1466
-
1467
-
1468
-    /**
1469
-     * This attaches a list of given prices to a ticket.
1470
-     * Note we dont' have to worry about ever removing relationships (or archiving prices)
1471
-     * because if there is a change in price information on a ticket, a new ticket is created anyways
1472
-     * so the archived ticket will retain the old price info and prices are automatically "archived" via the ticket.
1473
-     *
1474
-     * @access  private
1475
-     * @param array     $prices_data Array of prices from the form.
1476
-     * @param EE_Ticket $ticket      EE_Ticket object that prices are being attached to.
1477
-     * @param bool      $new_prices  Whether attach existing incoming prices or create new ones.
1478
-     * @return  void
1479
-     * @throws EE_Error
1480
-     * @throws ReflectionException
1481
-     */
1482
-    private function _add_prices_to_ticket($prices_data, EE_Ticket $ticket, $new_prices = false)
1483
-    {
1484
-        $timezone = $ticket->get_timezone();
1485
-        foreach ($prices_data as $row => $price_data) {
1486
-            $price_values = [
1487
-                'PRC_ID'         => ! empty($price_data['PRC_ID']) ? $price_data['PRC_ID'] : null,
1488
-                'PRT_ID'         => ! empty($price_data['PRT_ID']) ? $price_data['PRT_ID'] : null,
1489
-                'PRC_amount'     => ! empty($price_data['PRC_amount']) ? $price_data['PRC_amount'] : 0,
1490
-                'PRC_name'       => ! empty($price_data['PRC_name']) ? $price_data['PRC_name'] : '',
1491
-                'PRC_desc'       => ! empty($price_data['PRC_desc']) ? $price_data['PRC_desc'] : '',
1492
-                'PRC_is_default' => 0, // make sure prices are NOT set as default from this context
1493
-                'PRC_order'      => $row,
1494
-            ];
1495
-            if ($new_prices || empty($price_values['PRC_ID'])) {
1496
-                $price_values['PRC_ID'] = 0;
1497
-                $price                  = EE_Price::new_instance($price_values, $timezone);
1498
-            } else {
1499
-                $price = EEM_Price::instance($timezone)->get_one_by_ID($price_data['PRC_ID']);
1500
-                // update this price with new values
1501
-                foreach ($price_values as $field => $new_price) {
1502
-                    $price->set($field, $new_price);
1503
-                }
1504
-            }
1505
-            if (! $price instanceof EE_Price) {
1506
-                throw new RuntimeException(
1507
-                    sprintf(
1508
-                        esc_html__(
1509
-                            'Something went wrong! A valid Price could not be generated or retrieved using the supplied data: %1$s',
1510
-                            'event_espresso'
1511
-                        ),
1512
-                        print_r($price_values, true)
1513
-                    )
1514
-                );
1515
-            }
1516
-            $price->save();
1517
-            $ticket->_add_relation_to($price, 'Price');
1518
-        }
1519
-    }
1520
-
1521
-
1522
-    /**
1523
-     * Add in our autosave ajax handlers
1524
-     *
1525
-     */
1526
-    protected function _ee_autosave_create_new()
1527
-    {
1528
-    }
1529
-
1530
-
1531
-    /**
1532
-     * More autosave handlers.
1533
-     */
1534
-    protected function _ee_autosave_edit()
1535
-    {
1536
-    }
1537
-
1538
-
1539
-    /**
1540
-     * @throws EE_Error
1541
-     * @throws ReflectionException
1542
-     */
1543
-    private function _generate_publish_box_extra_content()
1544
-    {
1545
-        // load formatter helper
1546
-        // args for getting related registrations
1547
-        $approved_query_args        = [
1548
-            [
1549
-                'REG_deleted' => 0,
1550
-                'STS_ID'      => EEM_Registration::status_id_approved,
1551
-            ],
1552
-        ];
1553
-        $not_approved_query_args    = [
1554
-            [
1555
-                'REG_deleted' => 0,
1556
-                'STS_ID'      => EEM_Registration::status_id_not_approved,
1557
-            ],
1558
-        ];
1559
-        $pending_payment_query_args = [
1560
-            [
1561
-                'REG_deleted' => 0,
1562
-                'STS_ID'      => EEM_Registration::status_id_pending_payment,
1563
-            ],
1564
-        ];
1565
-        // publish box
1566
-        $publish_box_extra_args = [
1567
-            'view_approved_reg_url'        => add_query_arg(
1568
-                [
1569
-                    'action'      => 'default',
1570
-                    'event_id'    => $this->_cpt_model_obj->ID(),
1571
-                    '_reg_status' => EEM_Registration::status_id_approved,
1572
-                ],
1573
-                REG_ADMIN_URL
1574
-            ),
1575
-            'view_not_approved_reg_url'    => add_query_arg(
1576
-                [
1577
-                    'action'      => 'default',
1578
-                    'event_id'    => $this->_cpt_model_obj->ID(),
1579
-                    '_reg_status' => EEM_Registration::status_id_not_approved,
1580
-                ],
1581
-                REG_ADMIN_URL
1582
-            ),
1583
-            'view_pending_payment_reg_url' => add_query_arg(
1584
-                [
1585
-                    'action'      => 'default',
1586
-                    'event_id'    => $this->_cpt_model_obj->ID(),
1587
-                    '_reg_status' => EEM_Registration::status_id_pending_payment,
1588
-                ],
1589
-                REG_ADMIN_URL
1590
-            ),
1591
-            'approved_regs'                => $this->_cpt_model_obj->count_related(
1592
-                'Registration',
1593
-                $approved_query_args
1594
-            ),
1595
-            'not_approved_regs'            => $this->_cpt_model_obj->count_related(
1596
-                'Registration',
1597
-                $not_approved_query_args
1598
-            ),
1599
-            'pending_payment_regs'         => $this->_cpt_model_obj->count_related(
1600
-                'Registration',
1601
-                $pending_payment_query_args
1602
-            ),
1603
-            'misc_pub_section_class'       => apply_filters(
1604
-                'FHEE_Events_Admin_Page___generate_publish_box_extra_content__misc_pub_section_class',
1605
-                'misc-pub-section'
1606
-            ),
1607
-        ];
1608
-        ob_start();
1609
-        do_action(
1610
-            'AHEE__Events_Admin_Page___generate_publish_box_extra_content__event_editor_overview_add',
1611
-            $this->_cpt_model_obj
1612
-        );
1613
-        $publish_box_extra_args['event_editor_overview_add'] = ob_get_clean();
1614
-        // load template
1615
-        EEH_Template::display_template(
1616
-            EVENTS_TEMPLATE_PATH . 'event_publish_box_extras.template.php',
1617
-            $publish_box_extra_args
1618
-        );
1619
-    }
1620
-
1621
-
1622
-    /**
1623
-     * @return EE_Event
1624
-     */
1625
-    public function get_event_object()
1626
-    {
1627
-        return $this->_cpt_model_obj;
1628
-    }
1629
-
1630
-
1631
-
1632
-
1633
-    /** METABOXES * */
1634
-    /**
1635
-     * _register_event_editor_meta_boxes
1636
-     * add all metaboxes related to the event_editor
1637
-     *
1638
-     * @return void
1639
-     * @throws EE_Error
1640
-     * @throws ReflectionException
1641
-     */
1642
-    protected function _register_event_editor_meta_boxes()
1643
-    {
1644
-        $this->verify_cpt_object();
1645
-        $use_advanced_editor = $this->admin_config->useAdvancedEditor();
1646
-        // check if the new EDTR reg options meta box is being used, and if so, don't load the legacy version
1647
-        if (! $use_advanced_editor || ! $this->feature->allowed('use_reg_options_meta_box')) {
1648
-            $this->addMetaBox(
1649
-                'espresso_event_editor_event_options',
1650
-                esc_html__('Event Registration Options', 'event_espresso'),
1651
-                [$this, 'registration_options_meta_box'],
1652
-                $this->page_slug,
1653
-                'side'
1654
-            );
1655
-        }
1656
-        if (! $use_advanced_editor) {
1657
-            $this->addMetaBox(
1658
-                'espresso_event_editor_tickets',
1659
-                esc_html__('Event Datetime & Ticket', 'event_espresso'),
1660
-                [$this, 'ticket_metabox'],
1661
-                $this->page_slug,
1662
-                'normal',
1663
-                'high'
1664
-            );
1665
-        } elseif ($this->feature->allowed('use_reg_options_meta_box')) {
1666
-            add_action(
1667
-                'add_meta_boxes_espresso_events',
1668
-                function () {
1669
-                    global $current_screen;
1670
-                    remove_meta_box('authordiv', $current_screen, 'normal');
1671
-                },
1672
-                99
1673
-            );
1674
-        }
1675
-        // NOTE: if you're looking for other metaboxes in here,
1676
-        // where a metabox has a related management page in the admin
1677
-        // you will find it setup in the related management page's "_Hooks" file.
1678
-        // i.e. messages metabox is found in "espresso_events_Messages_Hooks.class.php".
1679
-    }
1680
-
1681
-
1682
-    /**
1683
-     * @throws DomainException
1684
-     * @throws EE_Error
1685
-     * @throws ReflectionException
1686
-     */
1687
-    public function ticket_metabox()
1688
-    {
1689
-        $existing_datetime_ids = $existing_ticket_ids = [];
1690
-        // defaults for template args
1691
-        $template_args = [
1692
-            'existing_datetime_ids'    => '',
1693
-            'event_datetime_help_link' => '',
1694
-            'ticket_options_help_link' => '',
1695
-            'time'                     => null,
1696
-            'ticket_rows'              => '',
1697
-            'existing_ticket_ids'      => '',
1698
-            'total_ticket_rows'        => 1,
1699
-            'ticket_js_structure'      => '',
1700
-            'trash_icon'               => 'dashicons dashicons-lock',
1701
-            'disabled'                 => '',
1702
-        ];
1703
-        $event_id      = is_object($this->_cpt_model_obj) ? $this->_cpt_model_obj->ID() : null;
1704
-        /**
1705
-         * 1. Start with retrieving Datetimes
1706
-         * 2. Fore each datetime get related tickets
1707
-         * 3. For each ticket get related prices
1708
-         */
1709
-        /** @var EEM_Datetime $datetime_model */
1710
-        $datetime_model = EE_Registry::instance()->load_model('Datetime');
1711
-        /** @var EEM_Ticket $datetime_model */
1712
-        $ticket_model = EE_Registry::instance()->load_model('Ticket');
1713
-        $times        = $datetime_model->get_all_event_dates($event_id);
1714
-        /** @type EE_Datetime $first_datetime */
1715
-        $first_datetime = reset($times);
1716
-        // do we get related tickets?
1717
-        if (
1718
-            $first_datetime instanceof EE_Datetime
1719
-            && $first_datetime->ID() !== 0
1720
-        ) {
1721
-            $existing_datetime_ids[] = $first_datetime->get('DTT_ID');
1722
-            $template_args['time']   = $first_datetime;
1723
-            $related_tickets         = $first_datetime->tickets(
1724
-                [
1725
-                    ['OR' => ['TKT_deleted' => 1, 'TKT_deleted*' => 0]],
1726
-                    'default_where_conditions' => 'none',
1727
-                ]
1728
-            );
1729
-            if (! empty($related_tickets)) {
1730
-                $template_args['total_ticket_rows'] = count($related_tickets);
1731
-                $row                                = 0;
1732
-                foreach ($related_tickets as $ticket) {
1733
-                    $existing_ticket_ids[]        = $ticket->get('TKT_ID');
1734
-                    $template_args['ticket_rows'] .= $this->_get_ticket_row($ticket, false, $row);
1735
-                    $row++;
1736
-                }
1737
-            } else {
1738
-                $template_args['total_ticket_rows'] = 1;
1739
-                /** @type EE_Ticket $ticket */
1740
-                $ticket                       = $ticket_model->create_default_object();
1741
-                $template_args['ticket_rows'] .= $this->_get_ticket_row($ticket);
1742
-            }
1743
-        } else {
1744
-            $template_args['time'] = $times[0];
1745
-            /** @type EE_Ticket[] $tickets */
1746
-            $tickets                      = $ticket_model->get_all_default_tickets();
1747
-            $template_args['ticket_rows'] .= $this->_get_ticket_row($tickets[1]);
1748
-            // NOTE: we're just sending the first default row
1749
-            // (decaf can't manage default tickets so this should be sufficient);
1750
-        }
1751
-        $template_args['event_datetime_help_link'] = $this->_get_help_tab_link(
1752
-            'event_editor_event_datetimes_help_tab'
1753
-        );
1754
-        $template_args['ticket_options_help_link'] = $this->_get_help_tab_link('ticket_options_info');
1755
-        $template_args['existing_datetime_ids']    = implode(',', $existing_datetime_ids);
1756
-        $template_args['existing_ticket_ids']      = implode(',', $existing_ticket_ids);
1757
-        $template_args['ticket_js_structure']      = $this->_get_ticket_row(
1758
-            $ticket_model->create_default_object(),
1759
-            true
1760
-        );
1761
-        $template                                  = apply_filters(
1762
-            'FHEE__Events_Admin_Page__ticket_metabox__template',
1763
-            EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_main.template.php'
1764
-        );
1765
-        EEH_Template::display_template($template, $template_args);
1766
-    }
1767
-
1768
-
1769
-    /**
1770
-     * Setup an individual ticket form for the decaf event editor page
1771
-     *
1772
-     * @access private
1773
-     * @param EE_Ticket $ticket   the ticket object
1774
-     * @param boolean   $skeleton whether we're generating a skeleton for js manipulation
1775
-     * @param int       $row
1776
-     * @return string generated html for the ticket row.
1777
-     * @throws EE_Error
1778
-     * @throws ReflectionException
1779
-     */
1780
-    private function _get_ticket_row($ticket, $skeleton = false, $row = 0)
1781
-    {
1782
-        $template_args = [
1783
-            'tkt_status_class'    => ' tkt-status-' . $ticket->ticket_status(),
1784
-            'tkt_archive_class'   => $ticket->ticket_status() === EE_Ticket::archived && ! $skeleton ? ' tkt-archived'
1785
-                : '',
1786
-            'ticketrow'           => $skeleton ? 'TICKETNUM' : $row,
1787
-            'TKT_ID'              => $ticket->get('TKT_ID'),
1788
-            'TKT_name'            => $ticket->get('TKT_name'),
1789
-            'TKT_start_date'      => $skeleton ? '' : $ticket->get_date('TKT_start_date', 'Y-m-d h:i a'),
1790
-            'TKT_end_date'        => $skeleton ? '' : $ticket->get_date('TKT_end_date', 'Y-m-d h:i a'),
1791
-            'TKT_is_default'      => $ticket->get('TKT_is_default'),
1792
-            'TKT_qty'             => $ticket->get_pretty('TKT_qty', 'input'),
1793
-            'edit_ticketrow_name' => $skeleton ? 'TICKETNAMEATTR' : 'edit_tickets',
1794
-            'TKT_sold'            => $skeleton ? 0 : $ticket->get('TKT_sold'),
1795
-            'trash_icon'          => ($skeleton || (! empty($ticket) && ! $ticket->get('TKT_deleted')))
1796
-                                     && (! empty($ticket) && $ticket->get('TKT_sold') === 0)
1797
-                ? 'trash-icon dashicons dashicons-post-trash clickable' : 'dashicons dashicons-lock',
1798
-            'disabled'            => $skeleton || (! empty($ticket) && ! $ticket->get('TKT_deleted')) ? ''
1799
-                : ' disabled=disabled',
1800
-        ];
1801
-        $price         = $ticket->ID() !== 0
1802
-            ? $ticket->get_first_related('Price', ['default_where_conditions' => 'none'])
1803
-            : null;
1804
-        $price         = $price instanceof EE_Price
1805
-            ? $price
1806
-            : EEM_Price::instance()->create_default_object();
1807
-        $price_args    = [
1808
-            'price_currency_symbol' => EE_Registry::instance()->CFG->currency->sign,
1809
-            'PRC_amount'            => $price->get('PRC_amount'),
1810
-            'PRT_ID'                => $price->get('PRT_ID'),
1811
-            'PRC_ID'                => $price->get('PRC_ID'),
1812
-            'PRC_is_default'        => $price->get('PRC_is_default'),
1813
-        ];
1814
-        // make sure we have default start and end dates if skeleton
1815
-        // handle rows that should NOT be empty
1816
-        if (empty($template_args['TKT_start_date'])) {
1817
-            // if empty then the start date will be now.
1818
-            $template_args['TKT_start_date'] = date('Y-m-d h:i a', current_time('timestamp'));
1819
-        }
1820
-        if (empty($template_args['TKT_end_date'])) {
1821
-            // get the earliest datetime (if present);
1822
-            $earliest_datetime             = $this->_cpt_model_obj->ID() > 0
1823
-                ? $this->_cpt_model_obj->get_first_related(
1824
-                    'Datetime',
1825
-                    ['order_by' => ['DTT_EVT_start' => 'ASC']]
1826
-                )
1827
-                : null;
1828
-            $template_args['TKT_end_date'] = $earliest_datetime instanceof EE_Datetime
1829
-                ? $earliest_datetime->get_datetime('DTT_EVT_start', 'Y-m-d', 'h:i a')
1830
-                : date('Y-m-d h:i a', mktime(0, 0, 0, date('m'), date('d') + 7, date('Y')));
1831
-        }
1832
-        $template_args = array_merge($template_args, $price_args);
1833
-        $template      = apply_filters(
1834
-            'FHEE__Events_Admin_Page__get_ticket_row__template',
1835
-            EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_ticket_row.template.php',
1836
-            $ticket
1837
-        );
1838
-        return EEH_Template::display_template($template, $template_args, true);
1839
-    }
1840
-
1841
-
1842
-    /**
1843
-     * @throws EE_Error
1844
-     * @throws ReflectionException
1845
-     */
1846
-    public function registration_options_meta_box()
1847
-    {
1848
-        $yes_no_values             = [
1849
-            ['id' => true, 'text' => esc_html__('Yes', 'event_espresso')],
1850
-            ['id' => false, 'text' => esc_html__('No', 'event_espresso')],
1851
-        ];
1852
-        $default_reg_status_values = EEM_Registration::reg_status_array(
1853
-            [
1854
-                EEM_Registration::status_id_cancelled,
1855
-                EEM_Registration::status_id_declined,
1856
-                EEM_Registration::status_id_incomplete,
1857
-            ],
1858
-            true
1859
-        );
1860
-        // $template_args['is_active_select'] = EEH_Form_Fields::select_input('is_active', $yes_no_values, $this->_cpt_model_obj->is_active());
1861
-        $template_args['_event']                          = $this->_cpt_model_obj;
1862
-        $template_args['event']                           = $this->_cpt_model_obj;
1863
-        $template_args['active_status']                   = $this->_cpt_model_obj->pretty_active_status(false);
1864
-        $template_args['additional_limit']                = $this->_cpt_model_obj->additional_limit();
1865
-        $template_args['default_registration_status']     = EEH_Form_Fields::select_input(
1866
-            'default_reg_status',
1867
-            $default_reg_status_values,
1868
-            $this->_cpt_model_obj->default_registration_status()
1869
-        );
1870
-        $template_args['display_description']             = EEH_Form_Fields::select_input(
1871
-            'display_desc',
1872
-            $yes_no_values,
1873
-            $this->_cpt_model_obj->display_description()
1874
-        );
1875
-        $template_args['display_ticket_selector']         = EEH_Form_Fields::select_input(
1876
-            'display_ticket_selector',
1877
-            $yes_no_values,
1878
-            $this->_cpt_model_obj->display_ticket_selector(),
1879
-            '',
1880
-            '',
1881
-            false
1882
-        );
1883
-        $template_args['additional_registration_options'] = apply_filters(
1884
-            'FHEE__Events_Admin_Page__registration_options_meta_box__additional_registration_options',
1885
-            '',
1886
-            $template_args,
1887
-            $yes_no_values,
1888
-            $default_reg_status_values
1889
-        );
1890
-        EEH_Template::display_template(
1891
-            EVENTS_TEMPLATE_PATH . 'event_registration_options.template.php',
1892
-            $template_args
1893
-        );
1894
-    }
1895
-
1896
-
1897
-    /**
1898
-     * _get_events()
1899
-     * This method simply returns all the events (for the given _view and paging)
1900
-     *
1901
-     * @access public
1902
-     * @param int  $per_page     count of items per page (20 default);
1903
-     * @param int  $current_page what is the current page being viewed.
1904
-     * @param bool $count        if TRUE then we just return a count of ALL events matching the given _view.
1905
-     *                           If FALSE then we return an array of event objects
1906
-     *                           that match the given _view and paging parameters.
1907
-     * @return array|int         an array of event objects or a count of them.
1908
-     * @throws Exception
1909
-     */
1910
-    public function get_events($per_page = 10, $current_page = 1, $count = false)
1911
-    {
1912
-        $EEM_Event   = $this->_event_model();
1913
-        $offset      = ($current_page - 1) * $per_page;
1914
-        $limit       = $count ? null : $offset . ',' . $per_page;
1915
-        $orderby     = $this->request->getRequestParam('orderby', 'EVT_ID');
1916
-        $order       = $this->request->getRequestParam('order', 'DESC');
1917
-        $month_range = $this->request->getRequestParam('month_range');
1918
-        if ($month_range) {
1919
-            $pieces = explode(' ', $month_range, 3);
1920
-            // simulate the FIRST day of the month, that fixes issues for months like February
1921
-            // where PHP doesn't know what to assume for date.
1922
-            // @see https://events.codebasehq.com/projects/event-espresso/tickets/10437
1923
-            $month_r = ! empty($pieces[0]) ? date('m', EEH_DTT_Helper::first_of_month_timestamp($pieces[0])) : '';
1924
-            $year_r  = ! empty($pieces[1]) ? $pieces[1] : '';
1925
-        }
1926
-        $where  = [];
1927
-        $status = $this->request->getRequestParam('status');
1928
-        // determine what post_status our condition will have for the query.
1929
-        switch ($status) {
1930
-            case 'month':
1931
-            case 'today':
1932
-            case null:
1933
-            case 'all':
1934
-                break;
1935
-            case 'draft':
1936
-                $where['status'] = ['IN', ['draft', 'auto-draft']];
1937
-                break;
1938
-            default:
1939
-                $where['status'] = $status;
1940
-        }
1941
-        // categories? The default for all categories is -1
1942
-        $category = $this->request->getRequestParam('EVT_CAT', -1, 'int');
1943
-        if ($category !== -1) {
1944
-            $where['Term_Taxonomy.taxonomy'] = EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY;
1945
-            $where['Term_Taxonomy.term_id']  = $category;
1946
-        }
1947
-        // date where conditions
1948
-        $start_formats = EEM_Datetime::instance()->get_formats_for('DTT_EVT_start');
1949
-        if ($month_range) {
1950
-            $DateTime = new DateTime(
1951
-                $year_r . '-' . $month_r . '-01 00:00:00',
1952
-                new DateTimeZone('UTC')
1953
-            );
1954
-            $start    = $DateTime->getTimestamp();
1955
-            // set the datetime to be the end of the month
1956
-            $DateTime->setDate(
1957
-                $year_r,
1958
-                $month_r,
1959
-                $DateTime->format('t')
1960
-            )->setTime(23, 59, 59);
1961
-            $end                             = $DateTime->getTimestamp();
1962
-            $where['Datetime.DTT_EVT_start'] = ['BETWEEN', [$start, $end]];
1963
-        } elseif ($status === 'today') {
1964
-            $DateTime                        =
1965
-                new DateTime('now', new DateTimeZone(EEM_Event::instance()->get_timezone()));
1966
-            $start                           = $DateTime->setTime(0, 0)->format(implode(' ', $start_formats));
1967
-            $end                             = $DateTime->setTime(23, 59, 59)->format(implode(' ', $start_formats));
1968
-            $where['Datetime.DTT_EVT_start'] = ['BETWEEN', [$start, $end]];
1969
-        } elseif ($status === 'month') {
1970
-            $now                             = date('Y-m-01');
1971
-            $DateTime                        =
1972
-                new DateTime($now, new DateTimeZone(EEM_Event::instance()->get_timezone()));
1973
-            $start                           = $DateTime->setTime(0, 0)->format(implode(' ', $start_formats));
1974
-            $end                             = $DateTime->setDate(date('Y'), date('m'), $DateTime->format('t'))
1975
-                                                        ->setTime(23, 59, 59)
1976
-                                                        ->format(implode(' ', $start_formats));
1977
-            $where['Datetime.DTT_EVT_start'] = ['BETWEEN', [$start, $end]];
1978
-        }
1979
-        if (! EE_Registry::instance()->CAP->current_user_can('ee_read_others_events', 'get_events')) {
1980
-            $where['EVT_wp_user'] = get_current_user_id();
1981
-        } else {
1982
-            if (! isset($where['status'])) {
1983
-                if (! EE_Registry::instance()->CAP->current_user_can('ee_read_private_events', 'get_events')) {
1984
-                    $where['OR'] = [
1985
-                        'status*restrict_private' => ['!=', 'private'],
1986
-                        'AND'                     => [
1987
-                            'status*inclusive' => ['=', 'private'],
1988
-                            'EVT_wp_user'      => get_current_user_id(),
1989
-                        ],
1990
-                    ];
1991
-                }
1992
-            }
1993
-        }
1994
-        $wp_user = $this->request->getRequestParam('EVT_wp_user', 0, 'int');
1995
-        if (
1996
-            $wp_user
1997
-            && $wp_user !== get_current_user_id()
1998
-            && EE_Registry::instance()->CAP->current_user_can('ee_read_others_events', 'get_events')
1999
-        ) {
2000
-            $where['EVT_wp_user'] = $wp_user;
2001
-        }
2002
-        // search query handling
2003
-        $search_term = $this->request->getRequestParam('s');
2004
-        if ($search_term) {
2005
-            $search_term = '%' . $search_term . '%';
2006
-            $where['OR'] = [
2007
-                'EVT_name'       => ['LIKE', $search_term],
2008
-                'EVT_desc'       => ['LIKE', $search_term],
2009
-                'EVT_short_desc' => ['LIKE', $search_term],
2010
-            ];
2011
-        }
2012
-        // filter events by venue.
2013
-        $venue = $this->request->getRequestParam('venue', 0, 'int');
2014
-        if ($venue) {
2015
-            $where['Venue.VNU_ID'] = $venue;
2016
-        }
2017
-        $request_params = $this->request->requestParams();
2018
-        $where          = apply_filters('FHEE__Events_Admin_Page__get_events__where', $where, $request_params);
2019
-        $query_params   = apply_filters(
2020
-            'FHEE__Events_Admin_Page__get_events__query_params',
2021
-            [
2022
-                $where,
2023
-                'limit'    => $limit,
2024
-                'order_by' => $orderby,
2025
-                'order'    => $order,
2026
-                'group_by' => 'EVT_ID',
2027
-            ],
2028
-            $request_params
2029
-        );
2030
-
2031
-        // let's first check if we have special requests coming in.
2032
-        $active_status = $this->request->getRequestParam('active_status');
2033
-        if ($active_status) {
2034
-            switch ($active_status) {
2035
-                case 'upcoming':
2036
-                    return $EEM_Event->get_upcoming_events($query_params, $count);
2037
-                case 'expired':
2038
-                    return $EEM_Event->get_expired_events($query_params, $count);
2039
-                case 'active':
2040
-                    return $EEM_Event->get_active_events($query_params, $count);
2041
-                case 'inactive':
2042
-                    return $EEM_Event->get_inactive_events($query_params, $count);
2043
-            }
2044
-        }
2045
-
2046
-        return $count ? $EEM_Event->count([$where], 'EVT_ID', true) : $EEM_Event->get_all($query_params);
2047
-    }
2048
-
2049
-
2050
-    /**
2051
-     * handling for WordPress CPT actions (trash, restore, delete)
2052
-     *
2053
-     * @param string $post_id
2054
-     * @throws EE_Error
2055
-     * @throws ReflectionException
2056
-     */
2057
-    public function trash_cpt_item($post_id)
2058
-    {
2059
-        $this->request->setRequestParam('EVT_ID', $post_id);
2060
-        $this->_trash_or_restore_event('trash', false);
2061
-    }
2062
-
2063
-
2064
-    /**
2065
-     * @param string $post_id
2066
-     * @throws EE_Error
2067
-     * @throws ReflectionException
2068
-     */
2069
-    public function restore_cpt_item($post_id)
2070
-    {
2071
-        $this->request->setRequestParam('EVT_ID', $post_id);
2072
-        $this->_trash_or_restore_event('draft', false);
2073
-    }
2074
-
2075
-
2076
-    /**
2077
-     * @param string $post_id
2078
-     * @throws EE_Error
2079
-     * @throws EE_Error
2080
-     */
2081
-    public function delete_cpt_item($post_id)
2082
-    {
2083
-        throw new EE_Error(
2084
-            esc_html__(
2085
-                'Please contact Event Espresso support with the details of the steps taken to produce this error.',
2086
-                'event_espresso'
2087
-            )
2088
-        );
2089
-        // $this->request->setRequestParam('EVT_ID', $post_id);
2090
-        // $this->_delete_event();
2091
-    }
2092
-
2093
-
2094
-    /**
2095
-     * _trash_or_restore_event
2096
-     *
2097
-     * @access protected
2098
-     * @param string $event_status
2099
-     * @param bool   $redirect_after
2100
-     * @throws EE_Error
2101
-     * @throws EE_Error
2102
-     * @throws ReflectionException
2103
-     */
2104
-    protected function _trash_or_restore_event($event_status = 'trash', $redirect_after = true)
2105
-    {
2106
-        // determine the event id and set to array.
2107
-        $EVT_ID = $this->request->getRequestParam('EVT_ID', 0, 'int');
2108
-        // loop thru events
2109
-        if ($EVT_ID) {
2110
-            // clean status
2111
-            $event_status = sanitize_key($event_status);
2112
-            // grab status
2113
-            if (! empty($event_status)) {
2114
-                $success = $this->_change_event_status($EVT_ID, $event_status);
2115
-            } else {
2116
-                $success = false;
2117
-                $msg     = esc_html__(
2118
-                    'An error occurred. The event could not be moved to the trash because a valid event status was not not supplied.',
2119
-                    'event_espresso'
2120
-                );
2121
-                EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2122
-            }
2123
-        } else {
2124
-            $success = false;
2125
-            $msg     = esc_html__(
2126
-                'An error occurred. The event could not be moved to the trash because a valid event ID was not not supplied.',
2127
-                'event_espresso'
2128
-            );
2129
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2130
-        }
2131
-        $action = $event_status === 'trash' ? 'moved to the trash' : 'restored from the trash';
2132
-        if ($redirect_after) {
2133
-            $this->_redirect_after_action($success, 'Event', $action, ['action' => 'default']);
2134
-        }
2135
-    }
2136
-
2137
-
2138
-    /**
2139
-     * _trash_or_restore_events
2140
-     *
2141
-     * @access protected
2142
-     * @param string $event_status
2143
-     * @return void
2144
-     * @throws EE_Error
2145
-     * @throws EE_Error
2146
-     * @throws ReflectionException
2147
-     */
2148
-    protected function _trash_or_restore_events($event_status = 'trash')
2149
-    {
2150
-        // clean status
2151
-        $event_status = sanitize_key($event_status);
2152
-        // grab status
2153
-        if (! empty($event_status)) {
2154
-            $success = true;
2155
-            // determine the event id and set to array.
2156
-            $EVT_IDs = $this->request->getRequestParam('EVT_IDs', [], 'int', true);
2157
-            // loop thru events
2158
-            foreach ($EVT_IDs as $EVT_ID) {
2159
-                if ($EVT_ID = absint($EVT_ID)) {
2160
-                    $results = $this->_change_event_status($EVT_ID, $event_status);
2161
-                    $success = $results !== false ? $success : false;
2162
-                } else {
2163
-                    $msg = sprintf(
2164
-                        esc_html__(
2165
-                            'An error occurred. Event #%d could not be moved to the trash because a valid event ID was not not supplied.',
2166
-                            'event_espresso'
2167
-                        ),
2168
-                        $EVT_ID
2169
-                    );
2170
-                    EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2171
-                    $success = false;
2172
-                }
2173
-            }
2174
-        } else {
2175
-            $success = false;
2176
-            $msg     = esc_html__(
2177
-                'An error occurred. The event could not be moved to the trash because a valid event status was not not supplied.',
2178
-                'event_espresso'
2179
-            );
2180
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2181
-        }
2182
-        // in order to force a pluralized result message we need to send back a success status greater than 1
2183
-        $success = $success ? 2 : false;
2184
-        $action  = $event_status === 'trash' ? 'moved to the trash' : 'restored from the trash';
2185
-        $this->_redirect_after_action($success, 'Events', $action, ['action' => 'default']);
2186
-    }
2187
-
2188
-
2189
-    /**
2190
-     * @param int    $EVT_ID
2191
-     * @param string $event_status
2192
-     * @return bool
2193
-     * @throws EE_Error
2194
-     * @throws ReflectionException
2195
-     */
2196
-    private function _change_event_status($EVT_ID = 0, $event_status = '')
2197
-    {
2198
-        // grab event id
2199
-        if (! $EVT_ID) {
2200
-            $msg = esc_html__(
2201
-                'An error occurred. No Event ID or an invalid Event ID was received.',
2202
-                'event_espresso'
2203
-            );
2204
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2205
-            return false;
2206
-        }
2207
-        $this->_cpt_model_obj = EEM_Event::instance()->get_one_by_ID($EVT_ID);
2208
-        // clean status
2209
-        $event_status = sanitize_key($event_status);
2210
-        // grab status
2211
-        if (empty($event_status)) {
2212
-            $msg = esc_html__(
2213
-                'An error occurred. No Event Status or an invalid Event Status was received.',
2214
-                'event_espresso'
2215
-            );
2216
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2217
-            return false;
2218
-        }
2219
-        // was event trashed or restored ?
2220
-        switch ($event_status) {
2221
-            case 'draft':
2222
-                $action = 'restored from the trash';
2223
-                $hook   = 'AHEE_event_restored_from_trash';
2224
-                break;
2225
-            case 'trash':
2226
-                $action = 'moved to the trash';
2227
-                $hook   = 'AHEE_event_moved_to_trash';
2228
-                break;
2229
-            default:
2230
-                $action = 'updated';
2231
-                $hook   = false;
2232
-        }
2233
-        // use class to change status
2234
-        $this->_cpt_model_obj->set_status($event_status);
2235
-        $success = $this->_cpt_model_obj->save();
2236
-        if (! $success) {
2237
-            $msg = sprintf(esc_html__('An error occurred. The event could not be %s.', 'event_espresso'), $action);
2238
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2239
-            return false;
2240
-        }
2241
-        if ($hook) {
2242
-            do_action($hook);
2243
-        }
2244
-        return true;
2245
-    }
2246
-
2247
-
2248
-    /**
2249
-     * @param array $event_ids
2250
-     * @return array
2251
-     * @since   4.10.23.p
2252
-     */
2253
-    private function cleanEventIds(array $event_ids)
2254
-    {
2255
-        return array_map('absint', $event_ids);
2256
-    }
2257
-
2258
-
2259
-    /**
2260
-     * @return array
2261
-     * @since   4.10.23.p
2262
-     */
2263
-    private function getEventIdsFromRequest()
2264
-    {
2265
-        if ($this->request->requestParamIsSet('EVT_IDs')) {
2266
-            return $this->request->getRequestParam('EVT_IDs', [], 'int', true);
2267
-        } else {
2268
-            return $this->request->getRequestParam('EVT_ID', [], 'int', true);
2269
-        }
2270
-    }
2271
-
2272
-
2273
-    /**
2274
-     * @param bool $preview_delete
2275
-     * @throws EE_Error
2276
-     */
2277
-    protected function _delete_event($preview_delete = true)
2278
-    {
2279
-        $this->_delete_events($preview_delete);
2280
-    }
2281
-
2282
-
2283
-    /**
2284
-     * Gets the tree traversal batch persister.
2285
-     *
2286
-     * @return NodeGroupDao
2287
-     * @throws InvalidArgumentException
2288
-     * @throws InvalidDataTypeException
2289
-     * @throws InvalidInterfaceException
2290
-     * @since 4.10.12.p
2291
-     */
2292
-    protected function getModelObjNodeGroupPersister()
2293
-    {
2294
-        if (! $this->model_obj_node_group_persister instanceof NodeGroupDao) {
2295
-            $this->model_obj_node_group_persister =
2296
-                $this->getLoader()->load('\EventEspresso\core\services\orm\tree_traversal\NodeGroupDao');
2297
-        }
2298
-        return $this->model_obj_node_group_persister;
2299
-    }
2300
-
2301
-
2302
-    /**
2303
-     * @param bool $preview_delete
2304
-     * @return void
2305
-     * @throws EE_Error
2306
-     */
2307
-    protected function _delete_events($preview_delete = true)
2308
-    {
2309
-        $event_ids = $this->getEventIdsFromRequest();
2310
-        if ($preview_delete) {
2311
-            $this->generateDeletionPreview($event_ids);
2312
-        } else {
2313
-            EEM_Event::instance()->delete_permanently([['EVT_ID' => ['IN', $event_ids]]]);
2314
-        }
2315
-    }
2316
-
2317
-
2318
-    /**
2319
-     * @param array $event_ids
2320
-     */
2321
-    protected function generateDeletionPreview(array $event_ids)
2322
-    {
2323
-        $event_ids = $this->cleanEventIds($event_ids);
2324
-        // Set a code we can use to reference this deletion task in the batch jobs and preview page.
2325
-        $deletion_job_code = $this->getModelObjNodeGroupPersister()->generateGroupCode();
2326
-        $return_url        = EE_Admin_Page::add_query_args_and_nonce(
2327
-            [
2328
-                'action'            => 'preview_deletion',
2329
-                'deletion_job_code' => $deletion_job_code,
2330
-            ],
2331
-            $this->_admin_base_url
2332
-        );
2333
-        EEH_URL::safeRedirectAndExit(
2334
-            EE_Admin_Page::add_query_args_and_nonce(
2335
-                [
2336
-                    'page'              => EED_Batch::PAGE_SLUG,
2337
-                    'batch'             => EED_Batch::batch_job,
2338
-                    'EVT_IDs'           => $event_ids,
2339
-                    'deletion_job_code' => $deletion_job_code,
2340
-                    'job_handler'       => urlencode('EventEspressoBatchRequest\JobHandlers\PreviewEventDeletion'),
2341
-                    'return_url'        => urlencode($return_url),
2342
-                ],
2343
-                admin_url()
2344
-            )
2345
-        );
2346
-    }
2347
-
2348
-
2349
-    /**
2350
-     * Checks for a POST submission
2351
-     *
2352
-     * @since 4.10.12.p
2353
-     */
2354
-    protected function confirmDeletion()
2355
-    {
2356
-        $deletion_redirect_logic =
2357
-            $this->getLoader()->getShared('\EventEspresso\core\domain\services\admin\events\data\ConfirmDeletion');
2358
-        $deletion_redirect_logic->handle($this->get_request_data(), $this->admin_base_url());
2359
-    }
2360
-
2361
-
2362
-    /**
2363
-     * A page for users to preview what exactly will be deleted, and confirm they want to delete it.
2364
-     *
2365
-     * @throws EE_Error
2366
-     * @since 4.10.12.p
2367
-     */
2368
-    protected function previewDeletion()
2369
-    {
2370
-        $preview_deletion_logic =
2371
-            $this->getLoader()->getShared('\EventEspresso\core\domain\services\admin\events\data\PreviewDeletion');
2372
-        $this->set_template_args($preview_deletion_logic->handle($this->get_request_data(), $this->admin_base_url()));
2373
-        $this->display_admin_page_with_no_sidebar();
2374
-    }
2375
-
2376
-
2377
-    /**
2378
-     * get total number of events
2379
-     *
2380
-     * @access public
2381
-     * @return int
2382
-     * @throws EE_Error
2383
-     * @throws EE_Error
2384
-     */
2385
-    public function total_events()
2386
-    {
2387
-        return EEM_Event::instance()->count(
2388
-            ['caps' => 'read_admin'],
2389
-            'EVT_ID',
2390
-            true
2391
-        );
2392
-    }
2393
-
2394
-
2395
-    /**
2396
-     * get total number of draft events
2397
-     *
2398
-     * @access public
2399
-     * @return int
2400
-     * @throws EE_Error
2401
-     * @throws EE_Error
2402
-     */
2403
-    public function total_events_draft()
2404
-    {
2405
-        return EEM_Event::instance()->count(
2406
-            [
2407
-                ['status' => ['IN', ['draft', 'auto-draft']]],
2408
-                'caps' => 'read_admin',
2409
-            ],
2410
-            'EVT_ID',
2411
-            true
2412
-        );
2413
-    }
2414
-
2415
-
2416
-    /**
2417
-     * get total number of trashed events
2418
-     *
2419
-     * @access public
2420
-     * @return int
2421
-     * @throws EE_Error
2422
-     * @throws EE_Error
2423
-     */
2424
-    public function total_trashed_events()
2425
-    {
2426
-        return EEM_Event::instance()->count(
2427
-            [
2428
-                ['status' => 'trash'],
2429
-                'caps' => 'read_admin',
2430
-            ],
2431
-            'EVT_ID',
2432
-            true
2433
-        );
2434
-    }
2435
-
2436
-
2437
-    /**
2438
-     *    _default_event_settings
2439
-     *    This generates the Default Settings Tab
2440
-     *
2441
-     * @return void
2442
-     * @throws DomainException
2443
-     * @throws EE_Error
2444
-     * @throws InvalidArgumentException
2445
-     * @throws InvalidDataTypeException
2446
-     * @throws InvalidInterfaceException
2447
-     */
2448
-    protected function _default_event_settings()
2449
-    {
2450
-        $this->_set_add_edit_form_tags('update_default_event_settings');
2451
-        $this->_set_publish_post_box_vars(null, false, false, null, false);
2452
-        $this->_template_args['admin_page_content'] = EEH_HTML::div(
2453
-            $this->_default_event_settings_form()->get_html(),
2454
-            '',
2455
-            'padding'
2456
-        );
2457
-        $this->display_admin_page_with_sidebar();
2458
-    }
2459
-
2460
-
2461
-    /**
2462
-     * Return the form for event settings.
2463
-     *
2464
-     * @return EE_Form_Section_Proper
2465
-     * @throws EE_Error
2466
-     */
2467
-    protected function _default_event_settings_form()
2468
-    {
2469
-        $registration_config              = EE_Registry::instance()->CFG->registration;
2470
-        $registration_stati_for_selection = EEM_Registration::reg_status_array(
2471
-        // exclude
2472
-            [
2473
-                EEM_Registration::status_id_cancelled,
2474
-                EEM_Registration::status_id_declined,
2475
-                EEM_Registration::status_id_incomplete,
2476
-                EEM_Registration::status_id_wait_list,
2477
-            ],
2478
-            true
2479
-        );
2480
-        // setup Advanced Editor ???
2481
-        if (
2482
-            $this->raw_req_action === 'default_event_settings'
2483
-            || $this->raw_req_action === 'update_default_event_settings'
2484
-        ) {
2485
-            $this->advanced_editor_admin_form = $this->loader->getShared(AdvancedEditorAdminFormSection::class);
2486
-        }
2487
-        return new EE_Form_Section_Proper(
2488
-            [
2489
-                'name'            => 'update_default_event_settings',
2490
-                'html_id'         => 'update_default_event_settings',
2491
-                'html_class'      => 'form-table',
2492
-                'layout_strategy' => new EE_Admin_Two_Column_Layout(),
2493
-                'subsections'     => apply_filters(
2494
-                    'FHEE__Events_Admin_Page___default_event_settings_form__form_subsections',
2495
-                    [
2496
-                        'defaults_section_header' => new EE_Form_Section_HTML(
2497
-                            EEH_HTML::h2(
2498
-                                esc_html__('Default Settings', 'event_espresso'),
2499
-                                '',
2500
-                                'ee-admin-settings-hdr'
2501
-                            )
2502
-                        ),
2503
-                        'default_reg_status'  => new EE_Select_Input(
2504
-                            $registration_stati_for_selection,
2505
-                            [
2506
-                                'default'         => isset($registration_config->default_STS_ID)
2507
-                                                     && array_key_exists(
2508
-                                                         $registration_config->default_STS_ID,
2509
-                                                         $registration_stati_for_selection
2510
-                                                     )
2511
-                                    ? sanitize_text_field($registration_config->default_STS_ID)
2512
-                                    : EEM_Registration::status_id_pending_payment,
2513
-                                'html_label_text' => esc_html__('Default Registration Status', 'event_espresso')
2514
-                                                     . EEH_Template::get_help_tab_link(
2515
-                                                         'default_settings_status_help_tab'
2516
-                                                     ),
2517
-                                'html_help_text'  => esc_html__(
2518
-                                    '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.',
2519
-                                    'event_espresso'
2520
-                                ),
2521
-                            ]
2522
-                        ),
2523
-                        'default_max_tickets' => new EE_Integer_Input(
2524
-                            [
2525
-                                'default'         => isset($registration_config->default_maximum_number_of_tickets)
2526
-                                    ? $registration_config->default_maximum_number_of_tickets
2527
-                                    : EEM_Event::get_default_additional_limit(),
2528
-                                'html_label_text' => esc_html__(
2529
-                                    'Default Maximum Tickets Allowed Per Order:',
2530
-                                    'event_espresso'
2531
-                                )
2532
-                                                     . EEH_Template::get_help_tab_link(
2533
-                                                         'default_maximum_tickets_help_tab"'
2534
-                                                     ),
2535
-                                'html_help_text'  => esc_html__(
2536
-                                    'This setting allows you to indicate what will be the default for the maximum number of tickets per order when creating new events.',
2537
-                                    'event_espresso'
2538
-                                ),
2539
-                            ]
2540
-                        ),
2541
-                    ]
2542
-                ),
2543
-            ]
2544
-        );
2545
-    }
2546
-
2547
-
2548
-    /**
2549
-     * @return void
2550
-     * @throws EE_Error
2551
-     * @throws InvalidArgumentException
2552
-     * @throws InvalidDataTypeException
2553
-     * @throws InvalidInterfaceException
2554
-     */
2555
-    protected function _update_default_event_settings()
2556
-    {
2557
-        $form = $this->_default_event_settings_form();
2558
-        if ($form->was_submitted()) {
2559
-            $form->receive_form_submission();
2560
-            if ($form->is_valid()) {
2561
-                $registration_config = EE_Registry::instance()->CFG->registration;
2562
-                $valid_data          = $form->valid_data();
2563
-                if (isset($valid_data['default_reg_status'])) {
2564
-                    $registration_config->default_STS_ID = $valid_data['default_reg_status'];
2565
-                }
2566
-                if (isset($valid_data['default_max_tickets'])) {
2567
-                    $registration_config->default_maximum_number_of_tickets = $valid_data['default_max_tickets'];
2568
-                }
2569
-                do_action(
2570
-                    'AHEE__Events_Admin_Page___update_default_event_settings',
2571
-                    $valid_data,
2572
-                    EE_Registry::instance()->CFG,
2573
-                    $this
2574
-                );
2575
-                // update because data was valid!
2576
-                EE_Registry::instance()->CFG->update_espresso_config();
2577
-                EE_Error::overwrite_success();
2578
-                EE_Error::add_success(
2579
-                    esc_html__('Default Event Settings were updated', 'event_espresso')
2580
-                );
2581
-            }
2582
-        }
2583
-        $this->_redirect_after_action(0, '', '', ['action' => 'default_event_settings'], true);
2584
-    }
2585
-
2586
-
2587
-    /*************        Templates        *************
2588
-     *
2589
-     * @throws EE_Error
2590
-     */
2591
-    protected function _template_settings()
2592
-    {
2593
-        $this->_admin_page_title              = esc_html__('Template Settings (Preview)', 'event_espresso');
2594
-        $this->_template_args['preview_img']  = '<img src="'
2595
-                                                . EVENTS_ASSETS_URL
2596
-                                                . '/images/'
2597
-                                                . 'caffeinated_template_features.jpg" alt="'
2598
-                                                . esc_attr__('Template Settings Preview screenshot', 'event_espresso')
2599
-                                                . '" />';
2600
-        $this->_template_args['preview_text'] = '<strong>'
2601
-                                                . esc_html__(
2602
-                                                    '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.',
2603
-                                                    'event_espresso'
2604
-                                                ) . '</strong>';
2605
-        $this->display_admin_caf_preview_page('template_settings_tab');
2606
-    }
2607
-
2608
-
2609
-    /** Event Category Stuff **/
2610
-    /**
2611
-     * set the _category property with the category object for the loaded page.
2612
-     *
2613
-     * @access private
2614
-     * @return void
2615
-     */
2616
-    private function _set_category_object()
2617
-    {
2618
-        if (isset($this->_category->id) && ! empty($this->_category->id)) {
2619
-            return;
2620
-        } //already have the category object so get out.
2621
-        // set default category object
2622
-        $this->_set_empty_category_object();
2623
-        // only set if we've got an id
2624
-        $category_ID = $this->request->getRequestParam('EVT_CAT_ID', 0, 'int');
2625
-        if (! $category_ID) {
2626
-            return;
2627
-        }
2628
-        $term = get_term($category_ID, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY);
2629
-        if (! empty($term)) {
2630
-            $this->_category->category_name       = $term->name;
2631
-            $this->_category->category_identifier = $term->slug;
2632
-            $this->_category->category_desc       = $term->description;
2633
-            $this->_category->id                  = $term->term_id;
2634
-            $this->_category->parent              = $term->parent;
2635
-        }
2636
-    }
2637
-
2638
-
2639
-    /**
2640
-     * Clears out category properties.
2641
-     */
2642
-    private function _set_empty_category_object()
2643
-    {
2644
-        $this->_category                = new stdClass();
2645
-        $this->_category->category_name = $this->_category->category_identifier = $this->_category->category_desc = '';
2646
-        $this->_category->id            = $this->_category->parent = 0;
2647
-    }
2648
-
2649
-
2650
-    /**
2651
-     * @throws DomainException
2652
-     * @throws EE_Error
2653
-     * @throws InvalidArgumentException
2654
-     * @throws InvalidDataTypeException
2655
-     * @throws InvalidInterfaceException
2656
-     */
2657
-    protected function _category_list_table()
2658
-    {
2659
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2660
-        $this->_search_btn_label = esc_html__('Categories', 'event_espresso');
2661
-        $this->_admin_page_title .= ' ';
2662
-        $this->_admin_page_title .= $this->get_action_link_or_button(
2663
-            'add_category',
2664
-            'add_category',
2665
-            [],
2666
-            'add-new-h2'
2667
-        );
2668
-        $this->display_admin_list_table_page_with_sidebar();
2669
-    }
2670
-
2671
-
2672
-    /**
2673
-     * Output category details view.
2674
-     *
2675
-     * @throws EE_Error
2676
-     * @throws EE_Error
2677
-     */
2678
-    protected function _category_details($view)
2679
-    {
2680
-        // load formatter helper
2681
-        // load field generator helper
2682
-        $route = $view === 'edit' ? 'update_category' : 'insert_category';
2683
-        $this->_set_add_edit_form_tags($route);
2684
-        $this->_set_category_object();
2685
-        $id            = ! empty($this->_category->id) ? $this->_category->id : '';
2686
-        $delete_action = 'delete_category';
2687
-        // custom redirect
2688
-        $redirect = EE_Admin_Page::add_query_args_and_nonce(
2689
-            ['action' => 'category_list'],
2690
-            $this->_admin_base_url
2691
-        );
2692
-        $this->_set_publish_post_box_vars('EVT_CAT_ID', $id, $delete_action, $redirect);
2693
-        // take care of contents
2694
-        $this->_template_args['admin_page_content'] = $this->_category_details_content();
2695
-        $this->display_admin_page_with_sidebar();
2696
-    }
2697
-
2698
-
2699
-    /**
2700
-     * Output category details content.
2701
-     *
2702
-     * @throws DomainException
2703
-     */
2704
-    protected function _category_details_content()
2705
-    {
2706
-        $editor_args['category_desc'] = [
2707
-            'type'          => 'wp_editor',
2708
-            'value'         => EEH_Formatter::admin_format_content($this->_category->category_desc),
2709
-            'class'         => 'my_editor_custom',
2710
-            'wpeditor_args' => ['media_buttons' => false],
2711
-        ];
2712
-        $_wp_editor                   = $this->_generate_admin_form_fields($editor_args, 'array');
2713
-        $all_terms                    = get_terms(
2714
-            [EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY],
2715
-            ['hide_empty' => 0, 'exclude' => [$this->_category->id]]
2716
-        );
2717
-        // setup category select for term parents.
2718
-        $category_select_values[] = [
2719
-            'text' => esc_html__('No Parent', 'event_espresso'),
2720
-            'id'   => 0,
2721
-        ];
2722
-        foreach ($all_terms as $term) {
2723
-            $category_select_values[] = [
2724
-                'text' => $term->name,
2725
-                'id'   => $term->term_id,
2726
-            ];
2727
-        }
2728
-        $category_select = EEH_Form_Fields::select_input(
2729
-            'category_parent',
2730
-            $category_select_values,
2731
-            $this->_category->parent
2732
-        );
2733
-        $template_args   = [
2734
-            'category'                 => $this->_category,
2735
-            'category_select'          => $category_select,
2736
-            'unique_id_info_help_link' => $this->_get_help_tab_link('unique_id_info'),
2737
-            'category_desc_editor'     => $_wp_editor['category_desc']['field'],
2738
-            'disable'                  => '',
2739
-            'disabled_message'         => false,
2740
-        ];
2741
-        $template        = EVENTS_TEMPLATE_PATH . 'event_category_details.template.php';
2742
-        return EEH_Template::display_template($template, $template_args, true);
2743
-    }
2744
-
2745
-
2746
-    /**
2747
-     * Handles deleting categories.
2748
-     *
2749
-     * @throws EE_Error
2750
-     */
2751
-    protected function _delete_categories()
2752
-    {
2753
-        $category_IDs = $this->request->getRequestParam('EVT_CAT_ID', 0, 'int', true);
2754
-        foreach ($category_IDs as $category_ID) {
2755
-            $this->_delete_category($category_ID);
2756
-        }
2757
-        // doesn't matter what page we're coming from... we're going to the same place after delete.
2758
-        $query_args = [
2759
-            'action' => 'category_list',
2760
-        ];
2761
-        $this->_redirect_after_action(0, '', '', $query_args);
2762
-    }
2763
-
2764
-
2765
-    /**
2766
-     * Handles deleting specific category.
2767
-     *
2768
-     * @param int $cat_id
2769
-     */
2770
-    protected function _delete_category($cat_id)
2771
-    {
2772
-        $cat_id = absint($cat_id);
2773
-        wp_delete_term($cat_id, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY);
2774
-    }
2775
-
2776
-
2777
-    /**
2778
-     * Handles triggering the update or insertion of a new category.
2779
-     *
2780
-     * @param bool $new_category true means we're triggering the insert of a new category.
2781
-     * @throws EE_Error
2782
-     * @throws EE_Error
2783
-     */
2784
-    protected function _insert_or_update_category($new_category)
2785
-    {
2786
-        $cat_id  = $new_category ? $this->_insert_category() : $this->_insert_category(true);
2787
-        $success = 0; // we already have a success message so lets not send another.
2788
-        if ($cat_id) {
2789
-            $query_args = [
2790
-                'action'     => 'edit_category',
2791
-                'EVT_CAT_ID' => $cat_id,
2792
-            ];
2793
-        } else {
2794
-            $query_args = ['action' => 'add_category'];
2795
-        }
2796
-        $this->_redirect_after_action($success, '', '', $query_args, true);
2797
-    }
2798
-
2799
-
2800
-    /**
2801
-     * Inserts or updates category
2802
-     *
2803
-     * @param bool $update (true indicates we're updating a category).
2804
-     * @return bool|mixed|string
2805
-     */
2806
-    private function _insert_category($update = false)
2807
-    {
2808
-        $category_ID         = $update ? $this->request->getRequestParam('EVT_CAT_ID', 0, 'int') : 0;
2809
-        $category_name       = $this->request->getRequestParam('category_name', '');
2810
-        $category_desc       = $this->request->getRequestParam('category_desc', '');
2811
-        $category_parent     = $this->request->getRequestParam('category_parent', 0, 'int');
2812
-        $category_identifier = $this->request->getRequestParam('category_identifier', '');
2813
-
2814
-        if (empty($category_name)) {
2815
-            $msg = esc_html__('You must add a name for the category.', 'event_espresso');
2816
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2817
-            return false;
2818
-        }
2819
-        $term_args = [
2820
-            'name'        => $category_name,
2821
-            'description' => $category_desc,
2822
-            'parent'      => $category_parent,
2823
-        ];
2824
-        // was the category_identifier input disabled?
2825
-        if ($category_identifier) {
2826
-            $term_args['slug'] = $category_identifier;
2827
-        }
2828
-        $insert_ids = $update
2829
-            ? wp_update_term($category_ID, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY, $term_args)
2830
-            : wp_insert_term($category_name, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY, $term_args);
2831
-        if (! is_array($insert_ids)) {
2832
-            $msg = esc_html__(
2833
-                'An error occurred and the category has not been saved to the database.',
2834
-                'event_espresso'
2835
-            );
2836
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2837
-        } else {
2838
-            $category_ID = $insert_ids['term_id'];
2839
-            $msg         = sprintf(
2840
-                esc_html__('The category %s was successfully saved', 'event_espresso'),
2841
-                $category_name
2842
-            );
2843
-            EE_Error::add_success($msg);
2844
-        }
2845
-        return $category_ID;
2846
-    }
2847
-
2848
-
2849
-    /**
2850
-     * Gets categories or count of categories matching the arguments in the request.
2851
-     *
2852
-     * @param int  $per_page
2853
-     * @param int  $current_page
2854
-     * @param bool $count
2855
-     * @return EE_Term_Taxonomy[]|int
2856
-     * @throws EE_Error
2857
-     */
2858
-    public function get_categories($per_page = 10, $current_page = 1, $count = false)
2859
-    {
2860
-        // testing term stuff
2861
-        $orderby     = $this->request->getRequestParam('orderby', 'Term.term_id');
2862
-        $order       = $this->request->getRequestParam('order', 'DESC');
2863
-        $limit       = ($current_page - 1) * $per_page;
2864
-        $where       = ['taxonomy' => EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY];
2865
-        $search_term = $this->request->getRequestParam('s');
2866
-        if ($search_term) {
2867
-            $search_term = '%' . $search_term . '%';
2868
-            $where['OR'] = [
2869
-                'Term.name'   => ['LIKE', $search_term],
2870
-                'description' => ['LIKE', $search_term],
2871
-            ];
2872
-        }
2873
-        $query_params = [
2874
-            $where,
2875
-            'order_by'   => [$orderby => $order],
2876
-            'limit'      => $limit . ',' . $per_page,
2877
-            'force_join' => ['Term'],
2878
-        ];
2879
-        return $count
2880
-            ? EEM_Term_Taxonomy::instance()->count($query_params, 'term_id')
2881
-            : EEM_Term_Taxonomy::instance()->get_all($query_params);
2882
-    }
2883
-
2884
-    /* end category stuff */
2885
-
2886
-
2887
-    /**************/
2888
-
2889
-
2890
-    /**
2891
-     * Callback for the `ee_save_timezone_setting` ajax action.
2892
-     *
2893
-     * @throws EE_Error
2894
-     * @throws InvalidArgumentException
2895
-     * @throws InvalidDataTypeException
2896
-     * @throws InvalidInterfaceException
2897
-     */
2898
-    public function saveTimezoneString()
2899
-    {
2900
-        $timezone_string = $this->request->getRequestParam('timezone_selected');
2901
-        if (empty($timezone_string) || ! EEH_DTT_Helper::validate_timezone($timezone_string, false)) {
2902
-            EE_Error::add_error(
2903
-                esc_html__('An invalid timezone string submitted.', 'event_espresso'),
2904
-                __FILE__,
2905
-                __FUNCTION__,
2906
-                __LINE__
2907
-            );
2908
-            $this->_template_args['error'] = true;
2909
-            $this->_return_json();
2910
-        }
2911
-
2912
-        update_option('timezone_string', $timezone_string);
2913
-        EE_Error::add_success(
2914
-            esc_html__('Your timezone string was updated.', 'event_espresso')
2915
-        );
2916
-        $this->_template_args['success'] = true;
2917
-        $this->_return_json(true, ['action' => 'create_new']);
2918
-    }
2919
-
2920
-
2921
-    /**
2922 2589
      * @throws EE_Error
2923
-     * @deprecated 4.10.25.p
2924 2590
      */
2925
-    public function save_timezonestring_setting()
2926
-    {
2927
-        $this->saveTimezoneString();
2928
-    }
2591
+	protected function _template_settings()
2592
+	{
2593
+		$this->_admin_page_title              = esc_html__('Template Settings (Preview)', 'event_espresso');
2594
+		$this->_template_args['preview_img']  = '<img src="'
2595
+												. EVENTS_ASSETS_URL
2596
+												. '/images/'
2597
+												. 'caffeinated_template_features.jpg" alt="'
2598
+												. esc_attr__('Template Settings Preview screenshot', 'event_espresso')
2599
+												. '" />';
2600
+		$this->_template_args['preview_text'] = '<strong>'
2601
+												. esc_html__(
2602
+													'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.',
2603
+													'event_espresso'
2604
+												) . '</strong>';
2605
+		$this->display_admin_caf_preview_page('template_settings_tab');
2606
+	}
2607
+
2608
+
2609
+	/** Event Category Stuff **/
2610
+	/**
2611
+	 * set the _category property with the category object for the loaded page.
2612
+	 *
2613
+	 * @access private
2614
+	 * @return void
2615
+	 */
2616
+	private function _set_category_object()
2617
+	{
2618
+		if (isset($this->_category->id) && ! empty($this->_category->id)) {
2619
+			return;
2620
+		} //already have the category object so get out.
2621
+		// set default category object
2622
+		$this->_set_empty_category_object();
2623
+		// only set if we've got an id
2624
+		$category_ID = $this->request->getRequestParam('EVT_CAT_ID', 0, 'int');
2625
+		if (! $category_ID) {
2626
+			return;
2627
+		}
2628
+		$term = get_term($category_ID, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY);
2629
+		if (! empty($term)) {
2630
+			$this->_category->category_name       = $term->name;
2631
+			$this->_category->category_identifier = $term->slug;
2632
+			$this->_category->category_desc       = $term->description;
2633
+			$this->_category->id                  = $term->term_id;
2634
+			$this->_category->parent              = $term->parent;
2635
+		}
2636
+	}
2637
+
2638
+
2639
+	/**
2640
+	 * Clears out category properties.
2641
+	 */
2642
+	private function _set_empty_category_object()
2643
+	{
2644
+		$this->_category                = new stdClass();
2645
+		$this->_category->category_name = $this->_category->category_identifier = $this->_category->category_desc = '';
2646
+		$this->_category->id            = $this->_category->parent = 0;
2647
+	}
2648
+
2649
+
2650
+	/**
2651
+	 * @throws DomainException
2652
+	 * @throws EE_Error
2653
+	 * @throws InvalidArgumentException
2654
+	 * @throws InvalidDataTypeException
2655
+	 * @throws InvalidInterfaceException
2656
+	 */
2657
+	protected function _category_list_table()
2658
+	{
2659
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2660
+		$this->_search_btn_label = esc_html__('Categories', 'event_espresso');
2661
+		$this->_admin_page_title .= ' ';
2662
+		$this->_admin_page_title .= $this->get_action_link_or_button(
2663
+			'add_category',
2664
+			'add_category',
2665
+			[],
2666
+			'add-new-h2'
2667
+		);
2668
+		$this->display_admin_list_table_page_with_sidebar();
2669
+	}
2670
+
2671
+
2672
+	/**
2673
+	 * Output category details view.
2674
+	 *
2675
+	 * @throws EE_Error
2676
+	 * @throws EE_Error
2677
+	 */
2678
+	protected function _category_details($view)
2679
+	{
2680
+		// load formatter helper
2681
+		// load field generator helper
2682
+		$route = $view === 'edit' ? 'update_category' : 'insert_category';
2683
+		$this->_set_add_edit_form_tags($route);
2684
+		$this->_set_category_object();
2685
+		$id            = ! empty($this->_category->id) ? $this->_category->id : '';
2686
+		$delete_action = 'delete_category';
2687
+		// custom redirect
2688
+		$redirect = EE_Admin_Page::add_query_args_and_nonce(
2689
+			['action' => 'category_list'],
2690
+			$this->_admin_base_url
2691
+		);
2692
+		$this->_set_publish_post_box_vars('EVT_CAT_ID', $id, $delete_action, $redirect);
2693
+		// take care of contents
2694
+		$this->_template_args['admin_page_content'] = $this->_category_details_content();
2695
+		$this->display_admin_page_with_sidebar();
2696
+	}
2697
+
2698
+
2699
+	/**
2700
+	 * Output category details content.
2701
+	 *
2702
+	 * @throws DomainException
2703
+	 */
2704
+	protected function _category_details_content()
2705
+	{
2706
+		$editor_args['category_desc'] = [
2707
+			'type'          => 'wp_editor',
2708
+			'value'         => EEH_Formatter::admin_format_content($this->_category->category_desc),
2709
+			'class'         => 'my_editor_custom',
2710
+			'wpeditor_args' => ['media_buttons' => false],
2711
+		];
2712
+		$_wp_editor                   = $this->_generate_admin_form_fields($editor_args, 'array');
2713
+		$all_terms                    = get_terms(
2714
+			[EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY],
2715
+			['hide_empty' => 0, 'exclude' => [$this->_category->id]]
2716
+		);
2717
+		// setup category select for term parents.
2718
+		$category_select_values[] = [
2719
+			'text' => esc_html__('No Parent', 'event_espresso'),
2720
+			'id'   => 0,
2721
+		];
2722
+		foreach ($all_terms as $term) {
2723
+			$category_select_values[] = [
2724
+				'text' => $term->name,
2725
+				'id'   => $term->term_id,
2726
+			];
2727
+		}
2728
+		$category_select = EEH_Form_Fields::select_input(
2729
+			'category_parent',
2730
+			$category_select_values,
2731
+			$this->_category->parent
2732
+		);
2733
+		$template_args   = [
2734
+			'category'                 => $this->_category,
2735
+			'category_select'          => $category_select,
2736
+			'unique_id_info_help_link' => $this->_get_help_tab_link('unique_id_info'),
2737
+			'category_desc_editor'     => $_wp_editor['category_desc']['field'],
2738
+			'disable'                  => '',
2739
+			'disabled_message'         => false,
2740
+		];
2741
+		$template        = EVENTS_TEMPLATE_PATH . 'event_category_details.template.php';
2742
+		return EEH_Template::display_template($template, $template_args, true);
2743
+	}
2744
+
2745
+
2746
+	/**
2747
+	 * Handles deleting categories.
2748
+	 *
2749
+	 * @throws EE_Error
2750
+	 */
2751
+	protected function _delete_categories()
2752
+	{
2753
+		$category_IDs = $this->request->getRequestParam('EVT_CAT_ID', 0, 'int', true);
2754
+		foreach ($category_IDs as $category_ID) {
2755
+			$this->_delete_category($category_ID);
2756
+		}
2757
+		// doesn't matter what page we're coming from... we're going to the same place after delete.
2758
+		$query_args = [
2759
+			'action' => 'category_list',
2760
+		];
2761
+		$this->_redirect_after_action(0, '', '', $query_args);
2762
+	}
2763
+
2764
+
2765
+	/**
2766
+	 * Handles deleting specific category.
2767
+	 *
2768
+	 * @param int $cat_id
2769
+	 */
2770
+	protected function _delete_category($cat_id)
2771
+	{
2772
+		$cat_id = absint($cat_id);
2773
+		wp_delete_term($cat_id, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY);
2774
+	}
2775
+
2776
+
2777
+	/**
2778
+	 * Handles triggering the update or insertion of a new category.
2779
+	 *
2780
+	 * @param bool $new_category true means we're triggering the insert of a new category.
2781
+	 * @throws EE_Error
2782
+	 * @throws EE_Error
2783
+	 */
2784
+	protected function _insert_or_update_category($new_category)
2785
+	{
2786
+		$cat_id  = $new_category ? $this->_insert_category() : $this->_insert_category(true);
2787
+		$success = 0; // we already have a success message so lets not send another.
2788
+		if ($cat_id) {
2789
+			$query_args = [
2790
+				'action'     => 'edit_category',
2791
+				'EVT_CAT_ID' => $cat_id,
2792
+			];
2793
+		} else {
2794
+			$query_args = ['action' => 'add_category'];
2795
+		}
2796
+		$this->_redirect_after_action($success, '', '', $query_args, true);
2797
+	}
2798
+
2799
+
2800
+	/**
2801
+	 * Inserts or updates category
2802
+	 *
2803
+	 * @param bool $update (true indicates we're updating a category).
2804
+	 * @return bool|mixed|string
2805
+	 */
2806
+	private function _insert_category($update = false)
2807
+	{
2808
+		$category_ID         = $update ? $this->request->getRequestParam('EVT_CAT_ID', 0, 'int') : 0;
2809
+		$category_name       = $this->request->getRequestParam('category_name', '');
2810
+		$category_desc       = $this->request->getRequestParam('category_desc', '');
2811
+		$category_parent     = $this->request->getRequestParam('category_parent', 0, 'int');
2812
+		$category_identifier = $this->request->getRequestParam('category_identifier', '');
2813
+
2814
+		if (empty($category_name)) {
2815
+			$msg = esc_html__('You must add a name for the category.', 'event_espresso');
2816
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2817
+			return false;
2818
+		}
2819
+		$term_args = [
2820
+			'name'        => $category_name,
2821
+			'description' => $category_desc,
2822
+			'parent'      => $category_parent,
2823
+		];
2824
+		// was the category_identifier input disabled?
2825
+		if ($category_identifier) {
2826
+			$term_args['slug'] = $category_identifier;
2827
+		}
2828
+		$insert_ids = $update
2829
+			? wp_update_term($category_ID, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY, $term_args)
2830
+			: wp_insert_term($category_name, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY, $term_args);
2831
+		if (! is_array($insert_ids)) {
2832
+			$msg = esc_html__(
2833
+				'An error occurred and the category has not been saved to the database.',
2834
+				'event_espresso'
2835
+			);
2836
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2837
+		} else {
2838
+			$category_ID = $insert_ids['term_id'];
2839
+			$msg         = sprintf(
2840
+				esc_html__('The category %s was successfully saved', 'event_espresso'),
2841
+				$category_name
2842
+			);
2843
+			EE_Error::add_success($msg);
2844
+		}
2845
+		return $category_ID;
2846
+	}
2847
+
2848
+
2849
+	/**
2850
+	 * Gets categories or count of categories matching the arguments in the request.
2851
+	 *
2852
+	 * @param int  $per_page
2853
+	 * @param int  $current_page
2854
+	 * @param bool $count
2855
+	 * @return EE_Term_Taxonomy[]|int
2856
+	 * @throws EE_Error
2857
+	 */
2858
+	public function get_categories($per_page = 10, $current_page = 1, $count = false)
2859
+	{
2860
+		// testing term stuff
2861
+		$orderby     = $this->request->getRequestParam('orderby', 'Term.term_id');
2862
+		$order       = $this->request->getRequestParam('order', 'DESC');
2863
+		$limit       = ($current_page - 1) * $per_page;
2864
+		$where       = ['taxonomy' => EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY];
2865
+		$search_term = $this->request->getRequestParam('s');
2866
+		if ($search_term) {
2867
+			$search_term = '%' . $search_term . '%';
2868
+			$where['OR'] = [
2869
+				'Term.name'   => ['LIKE', $search_term],
2870
+				'description' => ['LIKE', $search_term],
2871
+			];
2872
+		}
2873
+		$query_params = [
2874
+			$where,
2875
+			'order_by'   => [$orderby => $order],
2876
+			'limit'      => $limit . ',' . $per_page,
2877
+			'force_join' => ['Term'],
2878
+		];
2879
+		return $count
2880
+			? EEM_Term_Taxonomy::instance()->count($query_params, 'term_id')
2881
+			: EEM_Term_Taxonomy::instance()->get_all($query_params);
2882
+	}
2883
+
2884
+	/* end category stuff */
2885
+
2886
+
2887
+	/**************/
2888
+
2889
+
2890
+	/**
2891
+	 * Callback for the `ee_save_timezone_setting` ajax action.
2892
+	 *
2893
+	 * @throws EE_Error
2894
+	 * @throws InvalidArgumentException
2895
+	 * @throws InvalidDataTypeException
2896
+	 * @throws InvalidInterfaceException
2897
+	 */
2898
+	public function saveTimezoneString()
2899
+	{
2900
+		$timezone_string = $this->request->getRequestParam('timezone_selected');
2901
+		if (empty($timezone_string) || ! EEH_DTT_Helper::validate_timezone($timezone_string, false)) {
2902
+			EE_Error::add_error(
2903
+				esc_html__('An invalid timezone string submitted.', 'event_espresso'),
2904
+				__FILE__,
2905
+				__FUNCTION__,
2906
+				__LINE__
2907
+			);
2908
+			$this->_template_args['error'] = true;
2909
+			$this->_return_json();
2910
+		}
2911
+
2912
+		update_option('timezone_string', $timezone_string);
2913
+		EE_Error::add_success(
2914
+			esc_html__('Your timezone string was updated.', 'event_espresso')
2915
+		);
2916
+		$this->_template_args['success'] = true;
2917
+		$this->_return_json(true, ['action' => 'create_new']);
2918
+	}
2919
+
2920
+
2921
+	/**
2922
+	 * @throws EE_Error
2923
+	 * @deprecated 4.10.25.p
2924
+	 */
2925
+	public function save_timezonestring_setting()
2926
+	{
2927
+		$this->saveTimezoneString();
2928
+	}
2929 2929
 }
Please login to merge, or discard this patch.
core/domain/services/admin/events/data/ConfirmDeletion.php 1 patch
Indentation   +76 added lines, -76 removed lines patch added patch discarded remove patch
@@ -30,86 +30,86 @@
 block discarded – undo
30 30
  */
31 31
 class ConfirmDeletion
32 32
 {
33
-    /**
34
-     * @var NodeGroupDao
35
-     */
36
-    private $dao;
33
+	/**
34
+	 * @var NodeGroupDao
35
+	 */
36
+	private $dao;
37 37
 
38
-    /**
39
-     * ConfirmDeletion constructor.
40
-     * @param NodeGroupDao $dao
41
-     */
42
-    public function __construct(
43
-        NodeGroupDao $dao
44
-    ) {
38
+	/**
39
+	 * ConfirmDeletion constructor.
40
+	 * @param NodeGroupDao $dao
41
+	 */
42
+	public function __construct(
43
+		NodeGroupDao $dao
44
+	) {
45 45
 
46
-        $this->dao = $dao;
47
-    }
46
+		$this->dao = $dao;
47
+	}
48 48
 
49
-    /**
50
-     * Redirects to the batch job for deleting events if the form submission is valid, otherwise back to the deletion
51
-     * preview page.
52
-     * @since 4.10.12.p
53
-     * @param $request_data
54
-     * @param $admin_base_url
55
-     * @throws EE_Error
56
-     * @throws InvalidArgumentException
57
-     * @throws InvalidDataTypeException
58
-     * @throws InvalidInterfaceException
59
-     * @throws ReflectionException
60
-     * @throws UnexpectedEntityException
61
-     */
62
-    public function handle($request_data, $admin_base_url)
63
-    {
64
-        $deletion_job_code = isset($request_data['deletion_job_code']) ? sanitize_key($request_data['deletion_job_code']) : '';
65
-        $models_and_ids_to_delete = $this->dao->getModelsAndIdsFromGroup($deletion_job_code);
66
-        $form = new ConfirmEventDeletionForm($models_and_ids_to_delete['Event']);
67
-        // Initialize the form from the request, and check if its valid.
68
-        $form->receive_form_submission($request_data);
69
-        if ($form->is_valid()) {
70
-            // Redirect the user to the deletion batch job.
71
-            EEH_URL::safeRedirectAndExit(
72
-                EE_Admin_Page::add_query_args_and_nonce(
73
-                    array(
74
-                        'page' => EED_Batch::PAGE_SLUG,
75
-                        'batch' => EED_Batch::batch_job,
76
-                        'deletion_job_code' => $deletion_job_code,
77
-                        'job_handler' => urlencode('EventEspressoBatchRequest\JobHandlers\ExecuteBatchDeletion'),
78
-                        'return_url' => urlencode(
79
-                            add_query_arg(
80
-                                [
81
-                                    'status' => 'trash'
82
-                                ],
83
-                                EVENTS_ADMIN_URL
84
-                            )
85
-                        )
86
-                    ),
87
-                    admin_url()
88
-                )
89
-            );
90
-        }
91
-        // Dont' use $form->submission_error_message() because it adds the form input's label in front
92
-        // of each validation error which ends up looking quite confusing.
93
-        $validation_errors = $form->get_validation_errors_accumulated();
94
-        foreach ($validation_errors as $validation_error) {
95
-            EE_Error::add_error(
96
-                $validation_error->getMessage(),
97
-                __FILE__,
98
-                __FUNCTION__,
99
-                __LINE__
100
-            );
101
-        }
49
+	/**
50
+	 * Redirects to the batch job for deleting events if the form submission is valid, otherwise back to the deletion
51
+	 * preview page.
52
+	 * @since 4.10.12.p
53
+	 * @param $request_data
54
+	 * @param $admin_base_url
55
+	 * @throws EE_Error
56
+	 * @throws InvalidArgumentException
57
+	 * @throws InvalidDataTypeException
58
+	 * @throws InvalidInterfaceException
59
+	 * @throws ReflectionException
60
+	 * @throws UnexpectedEntityException
61
+	 */
62
+	public function handle($request_data, $admin_base_url)
63
+	{
64
+		$deletion_job_code = isset($request_data['deletion_job_code']) ? sanitize_key($request_data['deletion_job_code']) : '';
65
+		$models_and_ids_to_delete = $this->dao->getModelsAndIdsFromGroup($deletion_job_code);
66
+		$form = new ConfirmEventDeletionForm($models_and_ids_to_delete['Event']);
67
+		// Initialize the form from the request, and check if its valid.
68
+		$form->receive_form_submission($request_data);
69
+		if ($form->is_valid()) {
70
+			// Redirect the user to the deletion batch job.
71
+			EEH_URL::safeRedirectAndExit(
72
+				EE_Admin_Page::add_query_args_and_nonce(
73
+					array(
74
+						'page' => EED_Batch::PAGE_SLUG,
75
+						'batch' => EED_Batch::batch_job,
76
+						'deletion_job_code' => $deletion_job_code,
77
+						'job_handler' => urlencode('EventEspressoBatchRequest\JobHandlers\ExecuteBatchDeletion'),
78
+						'return_url' => urlencode(
79
+							add_query_arg(
80
+								[
81
+									'status' => 'trash'
82
+								],
83
+								EVENTS_ADMIN_URL
84
+							)
85
+						)
86
+					),
87
+					admin_url()
88
+				)
89
+			);
90
+		}
91
+		// Dont' use $form->submission_error_message() because it adds the form input's label in front
92
+		// of each validation error which ends up looking quite confusing.
93
+		$validation_errors = $form->get_validation_errors_accumulated();
94
+		foreach ($validation_errors as $validation_error) {
95
+			EE_Error::add_error(
96
+				$validation_error->getMessage(),
97
+				__FILE__,
98
+				__FUNCTION__,
99
+				__LINE__
100
+			);
101
+		}
102 102
 
103
-        EEH_URL::safeRedirectAndExit(
104
-            EE_Admin_Page::add_query_args_and_nonce(
105
-                [
106
-                    'action' => 'preview_deletion',
107
-                    'deletion_job_code' => $deletion_job_code
108
-                ],
109
-                $admin_base_url
110
-            )
111
-        );
112
-    }
103
+		EEH_URL::safeRedirectAndExit(
104
+			EE_Admin_Page::add_query_args_and_nonce(
105
+				[
106
+					'action' => 'preview_deletion',
107
+					'deletion_job_code' => $deletion_job_code
108
+				],
109
+				$admin_base_url
110
+			)
111
+		);
112
+	}
113 113
 }
114 114
 // End of file ConfirmDeletion.php
115 115
 // Location: EventEspresso\core\domain\services\admin\events\data/ConfirmDeletion.php
Please login to merge, or discard this patch.
core/libraries/form_sections/inputs/EE_Select_Input.input.php 1 patch
Indentation   +12 added lines, -12 removed lines patch added patch discarded remove patch
@@ -13,16 +13,16 @@
 block discarded – undo
13 13
  */
14 14
 class EE_Select_Input extends EE_Form_Input_With_Options_Base
15 15
 {
16
-    /**
17
-     * @param array $answer_options
18
-     * @param array $input_settings
19
-     */
20
-    public function __construct($answer_options, $input_settings = array())
21
-    {
22
-        $this->_set_display_strategy(new EE_Select_Display_Strategy($answer_options));
23
-        $this->_add_validation_strategy(
24
-            new EE_Enum_Validation_Strategy($input_settings['validation_error_message'] ?? null)
25
-        );
26
-        parent::__construct($answer_options, $input_settings);
27
-    }
16
+	/**
17
+	 * @param array $answer_options
18
+	 * @param array $input_settings
19
+	 */
20
+	public function __construct($answer_options, $input_settings = array())
21
+	{
22
+		$this->_set_display_strategy(new EE_Select_Display_Strategy($answer_options));
23
+		$this->_add_validation_strategy(
24
+			new EE_Enum_Validation_Strategy($input_settings['validation_error_message'] ?? null)
25
+		);
26
+		parent::__construct($answer_options, $input_settings);
27
+	}
28 28
 }
Please login to merge, or discard this patch.
core/libraries/form_sections/inputs/EE_Radio_Button_Input.input.php 1 patch
Indentation   +13 added lines, -13 removed lines patch added patch discarded remove patch
@@ -11,17 +11,17 @@
 block discarded – undo
11 11
  */
12 12
 class EE_Radio_Button_Input extends EE_Form_Input_With_Options_Base
13 13
 {
14
-    /**
15
-     * @param array $answer_options
16
-     * @param array $input_settings
17
-     */
18
-    public function __construct($answer_options, $input_settings = array())
19
-    {
20
-        $this->_set_display_strategy(new EE_Radio_Button_Display_Strategy());
21
-        $this->_add_validation_strategy(
22
-            new EE_Enum_Validation_Strategy($input_settings['validation_error_message'] ?? null)
23
-        );
24
-        $this->_multiple_selections = false;
25
-        parent::__construct($answer_options, $input_settings);
26
-    }
14
+	/**
15
+	 * @param array $answer_options
16
+	 * @param array $input_settings
17
+	 */
18
+	public function __construct($answer_options, $input_settings = array())
19
+	{
20
+		$this->_set_display_strategy(new EE_Radio_Button_Display_Strategy());
21
+		$this->_add_validation_strategy(
22
+			new EE_Enum_Validation_Strategy($input_settings['validation_error_message'] ?? null)
23
+		);
24
+		$this->_multiple_selections = false;
25
+		parent::__construct($answer_options, $input_settings);
26
+	}
27 27
 }
Please login to merge, or discard this patch.
core/libraries/batch/JobHandlers/DatetimeOffsetFix.php 2 patches
Indentation   +467 added lines, -467 removed lines patch added patch discarded remove patch
@@ -23,471 +23,471 @@
 block discarded – undo
23 23
 
24 24
 class DatetimeOffsetFix extends JobHandler
25 25
 {
26
-    /**
27
-     * Key for the option used to track which models have been processed when doing the batches.
28
-     */
29
-    const MODELS_TO_PROCESS_OPTION_KEY = 'ee_models_processed_for_datetime_offset_fix';
30
-
31
-
32
-    const COUNT_OF_MODELS_PROCESSED = 'ee_count_of_ee_models_processed_for_datetime_offset_fixed';
33
-
34
-    /**
35
-     * Key for the option used to track what the current offset is that will be applied when this tool is executed.
36
-     */
37
-    const OFFSET_TO_APPLY_OPTION_KEY = 'ee_datetime_offset_fix_offset_to_apply';
38
-
39
-
40
-    const OPTION_KEY_OFFSET_RANGE_START_DATE = 'ee_datetime_offset_start_date_range';
41
-
42
-
43
-    const OPTION_KEY_OFFSET_RANGE_END_DATE = 'ee_datetime_offset_end_date_range';
44
-
45
-
46
-    /**
47
-     * String labelling the datetime offset fix type for change-log entries.
48
-     */
49
-    const DATETIME_OFFSET_FIX_CHANGELOG_TYPE = 'datetime_offset_fix';
50
-
51
-
52
-    /**
53
-     * String labelling a datetime offset fix error for change-log entries.
54
-     */
55
-    const DATETIME_OFFSET_FIX_CHANGELOG_ERROR_TYPE = 'datetime_offset_fix_error';
56
-
57
-    /**
58
-     * @var EEM_Base[]
59
-     */
60
-    protected $models_with_datetime_fields = array();
61
-
62
-    // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
63
-
64
-    /**
65
-     * Performs any necessary setup for starting the job. This is also a good
66
-     * place to setup the $job_arguments which will be used for subsequent HTTP requests
67
-     * when continue_job will be called
68
-     *
69
-     * @param JobParameters $job_parameters
70
-     * @return JobStepResponse
71
-     * @throws EE_Error
72
-     * @throws InvalidArgumentException
73
-     * @throws InvalidDataTypeException
74
-     * @throws InvalidInterfaceException
75
-     */
76
-    public function create_job(JobParameters $job_parameters)
77
-    {
78
-        $models_with_datetime_fields = $this->getModelsWithDatetimeFields();
79
-        // we'll be doing each model as a batch.
80
-        $job_parameters->set_job_size(count($models_with_datetime_fields));
81
-        return new JobStepResponse(
82
-            $job_parameters,
83
-            esc_html__('Starting Datetime Offset Fix', 'event_espresso')
84
-        );
85
-    }
86
-
87
-    /**
88
-     * Performs another step of the job
89
-     *
90
-     * @param JobParameters $job_parameters
91
-     * @param int           $batch_size
92
-     * @return JobStepResponse
93
-     * @throws EE_Error
94
-     * @throws InvalidArgumentException
95
-     * @throws InvalidDataTypeException
96
-     * @throws InvalidInterfaceException
97
-     */
98
-    public function continue_job(JobParameters $job_parameters, $batch_size = 50)
99
-    {
100
-        $models_to_process = $this->getModelsWithDatetimeFields();
101
-        // let's pop off the a model and do the query to apply the offset.
102
-        $model_to_process = array_pop($models_to_process);
103
-        // update our record
104
-        $this->setModelsToProcess($models_to_process);
105
-        $this->processModel($model_to_process);
106
-        $this->updateCountOfModelsProcessed();
107
-        $job_parameters->set_units_processed($this->getCountOfModelsProcessed());
108
-        if (count($models_to_process) > 0) {
109
-            $job_parameters->set_status(JobParameters::status_continue);
110
-        } else {
111
-            $job_parameters->set_status(JobParameters::status_complete);
112
-        }
113
-        return new JobStepResponse(
114
-            $job_parameters,
115
-            sprintf(
116
-                esc_html__('Updated the offset for all datetime fields on the %s model.', 'event_espresso'),
117
-                $model_to_process
118
-            )
119
-        );
120
-    }
121
-
122
-    /**
123
-     * Performs any clean-up logic when we know the job is completed
124
-     *
125
-     * @param JobParameters $job_parameters
126
-     * @return JobStepResponse
127
-     * @throws BatchRequestException
128
-     */
129
-    public function cleanup_job(JobParameters $job_parameters)
130
-    {
131
-        // delete important saved options.
132
-        delete_option(self::MODELS_TO_PROCESS_OPTION_KEY);
133
-        delete_option(self::COUNT_OF_MODELS_PROCESSED);
134
-        delete_option(self::OPTION_KEY_OFFSET_RANGE_START_DATE);
135
-        delete_option(self::OPTION_KEY_OFFSET_RANGE_END_DATE);
136
-        return new JobStepResponse($job_parameters, esc_html__(
137
-            'Offset has been applied to all affected fields.',
138
-            'event_espresso'
139
-        ));
140
-    }
141
-
142
-
143
-    /**
144
-     * Contains the logic for processing a model and applying the datetime offset to affected fields on that model.
145
-     *
146
-     * @param string $model_class_name
147
-     * @throws EE_Error
148
-     */
149
-    protected function processModel($model_class_name)
150
-    {
151
-        global $wpdb;
152
-        /** @var EEM_Base $model */
153
-        $model = $model_class_name::instance();
154
-        $original_offset = self::getOffset();
155
-        $start_date_range = self::getStartDateRange();
156
-        $end_date_range = self::getEndDateRange();
157
-        $sql_date_function = $original_offset > 0 ? 'DATE_ADD' : 'DATE_SUB';
158
-        $offset = abs($original_offset) * 60;
159
-        $date_ranges = array();
160
-        // since some affected models might have two tables, we have to get our tables and set up a query for each table.
161
-        foreach ($model->get_tables() as $table) {
162
-            $query = 'UPDATE ' . $table->get_table_name();
163
-            $fields_affected = array();
164
-            $inner_query = array();
165
-            foreach ($model->_get_fields_for_table($table->get_table_alias()) as $model_field) {
166
-                if ($model_field instanceof EE_Datetime_Field) {
167
-                    $inner_query[ $model_field->get_table_column() ] = $model_field->get_table_column() . ' = '
168
-                                                                       . $sql_date_function . '('
169
-                                                                       . $model_field->get_table_column()
170
-                                                                       . ", INTERVAL {$offset} MINUTE)";
171
-                    $fields_affected[] = $model_field;
172
-                }
173
-            }
174
-            if (! $fields_affected) {
175
-                continue;
176
-            }
177
-            // do we do one query per column/field or one query for all fields on the model? It all depends on whether
178
-            // there is a date range applied or not.
179
-            if ($start_date_range instanceof DbSafeDateTime || $end_date_range instanceof DbSafeDateTime) {
180
-                $result = $this->doQueryForEachField($query, $inner_query, $start_date_range, $end_date_range);
181
-            } else {
182
-                $result = $this->doQueryForAllFields($query, $inner_query);
183
-            }
184
-
185
-            // record appropriate logs for the query
186
-            switch (true) {
187
-                case $result === false:
188
-                    // record error.
189
-                    $error_message = $wpdb->last_error;
190
-                    // handle the edge cases where last_error might be empty.
191
-                    if (! $error_message) {
192
-                        $error_message = esc_html__('Unknown mysql error occurred.', 'event_espresso');
193
-                    }
194
-                    $this->recordChangeLog($model, $original_offset, $table, $fields_affected, $error_message);
195
-                    break;
196
-                case is_array($result) && ! empty($result):
197
-                    foreach ($result as $field_name => $error_message) {
198
-                        $this->recordChangeLog($model, $original_offset, $table, array($field_name), $error_message);
199
-                    }
200
-                    break;
201
-                default:
202
-                    $this->recordChangeLog($model, $original_offset, $table, $fields_affected);
203
-            }
204
-        }
205
-    }
206
-
207
-
208
-    /**
209
-     * Does the query on each $inner_query individually.
210
-     *
211
-     * @param string              $query
212
-     * @param array               $inner_query
213
-     * @param DbSafeDateTime|null $start_date_range
214
-     * @param DbSafeDateTime|null $end_date_range
215
-     * @return array  An array of any errors encountered and the fields they were for.
216
-     */
217
-    private function doQueryForEachField($query, array $inner_query, $start_date_range, $end_date_range)
218
-    {
219
-        global $wpdb;
220
-        $errors = array();
221
-        foreach ($inner_query as $field_name => $field_query) {
222
-            $query_to_run = $query;
223
-            $where_conditions = array();
224
-            $query_to_run .= ' SET ' . $field_query;
225
-            if ($start_date_range instanceof DbSafeDateTime) {
226
-                $start_date = $start_date_range->format(EE_Datetime_Field::mysql_timestamp_format);
227
-                $where_conditions[] = "{$field_name} > '{$start_date}'";
228
-            }
229
-            if ($end_date_range instanceof DbSafeDateTime) {
230
-                $end_date = $end_date_range->format(EE_Datetime_Field::mysql_timestamp_format);
231
-                $where_conditions[] = "{$field_name} < '{$end_date}'";
232
-            }
233
-            if ($where_conditions) {
234
-                $query_to_run .= ' WHERE ' . implode(' AND ', $where_conditions);
235
-            }
236
-            $result = $wpdb->query($query_to_run);
237
-            if ($result === false) {
238
-                // record error.
239
-                $error_message = $wpdb->last_error;
240
-                // handle the edgecases where last_error might be empty.
241
-                if (! $error_message) {
242
-                    $error_message = esc_html__('Unknown mysql error occured.', 'event_espresso');
243
-                }
244
-                $errors[ $field_name ] = $error_message;
245
-            }
246
-        }
247
-        return $errors;
248
-    }
249
-
250
-
251
-    /**
252
-     * Performs the query for all fields within the inner_query
253
-     *
254
-     * @param string $query
255
-     * @param array  $inner_query
256
-     * @return false|int
257
-     */
258
-    private function doQueryForAllFields($query, array $inner_query)
259
-    {
260
-        global $wpdb;
261
-        $query .= ' SET ' . implode(',', $inner_query);
262
-        return $wpdb->query($query);
263
-    }
264
-
265
-
266
-    /**
267
-     * Records a changelog entry using the given information.
268
-     *
269
-     * @param EEM_Base              $model
270
-     * @param float                 $offset
271
-     * @param EE_Table_Base         $table
272
-     * @param EE_Model_Field_Base[] $model_fields_affected
273
-     * @param string                $error_message If present then there was an error so let's record that instead.
274
-     * @throws EE_Error
275
-     */
276
-    private function recordChangeLog(
277
-        EEM_Base $model,
278
-        $offset,
279
-        EE_Table_Base $table,
280
-        $model_fields_affected,
281
-        $error_message = ''
282
-    ) {
283
-        // setup $fields list.
284
-        $fields = array();
285
-        /** @var EE_Datetime_Field $model_field */
286
-        foreach ($model_fields_affected as $model_field) {
287
-            if (! $model_field instanceof EE_Datetime_Field) {
288
-                continue;
289
-            }
290
-            $fields[] = $model_field->get_name();
291
-        }
292
-        // setup the message for the changelog entry.
293
-        $message = $error_message
294
-            ? sprintf(
295
-                esc_html__(
296
-                    'The %1$s table for the %2$s model did not have the offset of %3$f applied to its fields (%4$s), because of the following error:%5$s',
297
-                    'event_espresso'
298
-                ),
299
-                $table->get_table_name(),
300
-                $model->get_this_model_name(),
301
-                $offset,
302
-                implode(',', $fields),
303
-                $error_message
304
-            )
305
-            : sprintf(
306
-                esc_html__(
307
-                    'The %1$s table for the %2$s model has had the offset of %3$f applied to its following fields: %4$s',
308
-                    'event_espresso'
309
-                ),
310
-                $table->get_table_name(),
311
-                $model->get_this_model_name(),
312
-                $offset,
313
-                implode(',', $fields)
314
-            );
315
-        // write to the log
316
-        $changelog = EE_Change_Log::new_instance(array(
317
-            'LOG_type'    => $error_message
318
-                ? self::DATETIME_OFFSET_FIX_CHANGELOG_ERROR_TYPE
319
-                : self::DATETIME_OFFSET_FIX_CHANGELOG_TYPE,
320
-            'LOG_message' => $message,
321
-        ));
322
-        $changelog->save();
323
-    }
324
-
325
-
326
-    /**
327
-     * Returns an array of models that have datetime fields.
328
-     * This array is added to a short lived transient cache to keep having to build this list to a minimum.
329
-     *
330
-     * @return array an array of model class names.
331
-     * @throws EE_Error
332
-     * @throws InvalidDataTypeException
333
-     * @throws InvalidInterfaceException
334
-     * @throws InvalidArgumentException
335
-     */
336
-    private function getModelsWithDatetimeFields()
337
-    {
338
-        $this->getModelsToProcess();
339
-        if (! empty($this->models_with_datetime_fields)) {
340
-            return $this->models_with_datetime_fields;
341
-        }
342
-
343
-        $all_non_abstract_models = EE_Registry::instance()->non_abstract_db_models;
344
-        foreach ($all_non_abstract_models as $non_abstract_model) {
345
-            // get model instance
346
-            /** @var EEM_Base $non_abstract_model */
347
-            $non_abstract_model = $non_abstract_model::instance();
348
-            if ($non_abstract_model->get_a_field_of_type('EE_Datetime_Field') instanceof EE_Datetime_Field) {
349
-                $this->models_with_datetime_fields[] = get_class($non_abstract_model);
350
-            }
351
-        }
352
-        $this->setModelsToProcess($this->models_with_datetime_fields);
353
-        return $this->models_with_datetime_fields;
354
-    }
355
-
356
-
357
-    /**
358
-     * This simply records the models that have been processed with our tracking option.
359
-     *
360
-     * @param array $models_to_set array of model class names.
361
-     */
362
-    private function setModelsToProcess($models_to_set)
363
-    {
364
-        update_option(self::MODELS_TO_PROCESS_OPTION_KEY, $models_to_set);
365
-    }
366
-
367
-
368
-    /**
369
-     * Used to keep track of how many models have been processed for the batch
370
-     *
371
-     * @param $count
372
-     */
373
-    private function updateCountOfModelsProcessed($count = 1)
374
-    {
375
-        $count = $this->getCountOfModelsProcessed() + (int) $count;
376
-        update_option(self::COUNT_OF_MODELS_PROCESSED, $count);
377
-    }
378
-
379
-
380
-    /**
381
-     * Retrieve the tracked number of models processed between requests.
382
-     *
383
-     * @return int
384
-     */
385
-    private function getCountOfModelsProcessed()
386
-    {
387
-        return (int) get_option(self::COUNT_OF_MODELS_PROCESSED, 0);
388
-    }
389
-
390
-
391
-    /**
392
-     * Returns the models that are left to process.
393
-     *
394
-     * @return array  an array of model class names.
395
-     */
396
-    private function getModelsToProcess()
397
-    {
398
-        if (empty($this->models_with_datetime_fields)) {
399
-            $this->models_with_datetime_fields = get_option(self::MODELS_TO_PROCESS_OPTION_KEY, array());
400
-        }
401
-        return $this->models_with_datetime_fields;
402
-    }
403
-
404
-
405
-    /**
406
-     * Used to record the offset that will be applied to dates and times for EE_Datetime_Field columns.
407
-     *
408
-     * @param float $offset
409
-     */
410
-    public static function updateOffset($offset)
411
-    {
412
-        update_option(self::OFFSET_TO_APPLY_OPTION_KEY, $offset);
413
-    }
414
-
415
-
416
-    /**
417
-     * Used to retrieve the saved offset that will be applied to dates and times for EE_Datetime_Field columns.
418
-     *
419
-     * @return float
420
-     */
421
-    public static function getOffset()
422
-    {
423
-        return (float) get_option(self::OFFSET_TO_APPLY_OPTION_KEY, 0);
424
-    }
425
-
426
-
427
-    /**
428
-     * Used to set the saved offset range start date.
429
-     *
430
-     * @param DbSafeDateTime|null $start_date
431
-     */
432
-    public static function updateStartDateRange(DbSafeDateTime $start_date = null)
433
-    {
434
-        $date_to_save = $start_date instanceof DbSafeDateTime
435
-            ? $start_date->format('U')
436
-            : '';
437
-        update_option(self::OPTION_KEY_OFFSET_RANGE_START_DATE, $date_to_save);
438
-    }
439
-
440
-
441
-    /**
442
-     * Used to get the saved offset range start date.
443
-     *
444
-     * @return DbSafeDateTime|null
445
-     */
446
-    public static function getStartDateRange()
447
-    {
448
-        $start_date = get_option(self::OPTION_KEY_OFFSET_RANGE_START_DATE, null);
449
-        try {
450
-            $datetime = DateTime::createFromFormat('U', $start_date, new DateTimeZone('UTC'));
451
-            $start_date = $datetime instanceof DateTime
452
-                ? DbSafeDateTime::createFromDateTime($datetime)
453
-                : null;
454
-        } catch (Exception $e) {
455
-            $start_date = null;
456
-        }
457
-        return $start_date;
458
-    }
459
-
460
-
461
-    /**
462
-     * Used to set the saved offset range end date.
463
-     *
464
-     * @param DbSafeDateTime|null $end_date
465
-     */
466
-    public static function updateEndDateRange(DbSafeDateTime $end_date = null)
467
-    {
468
-        $date_to_save = $end_date instanceof DbSafeDateTime
469
-            ? $end_date->format('U')
470
-            : '';
471
-        update_option(self::OPTION_KEY_OFFSET_RANGE_END_DATE, $date_to_save);
472
-    }
473
-
474
-
475
-    /**
476
-     * Used to get the saved offset range end date.
477
-     *
478
-     * @return DbSafeDateTime|null
479
-     */
480
-    public static function getEndDateRange()
481
-    {
482
-        $end_date = get_option(self::OPTION_KEY_OFFSET_RANGE_END_DATE, null);
483
-        try {
484
-            $datetime = DateTime::createFromFormat('U', $end_date, new DateTimeZone('UTC'));
485
-            $end_date = $datetime instanceof Datetime
486
-                ? DbSafeDateTime::createFromDateTime($datetime)
487
-                : null;
488
-        } catch (Exception $e) {
489
-            $end_date = null;
490
-        }
491
-        return $end_date;
492
-    }
26
+	/**
27
+	 * Key for the option used to track which models have been processed when doing the batches.
28
+	 */
29
+	const MODELS_TO_PROCESS_OPTION_KEY = 'ee_models_processed_for_datetime_offset_fix';
30
+
31
+
32
+	const COUNT_OF_MODELS_PROCESSED = 'ee_count_of_ee_models_processed_for_datetime_offset_fixed';
33
+
34
+	/**
35
+	 * Key for the option used to track what the current offset is that will be applied when this tool is executed.
36
+	 */
37
+	const OFFSET_TO_APPLY_OPTION_KEY = 'ee_datetime_offset_fix_offset_to_apply';
38
+
39
+
40
+	const OPTION_KEY_OFFSET_RANGE_START_DATE = 'ee_datetime_offset_start_date_range';
41
+
42
+
43
+	const OPTION_KEY_OFFSET_RANGE_END_DATE = 'ee_datetime_offset_end_date_range';
44
+
45
+
46
+	/**
47
+	 * String labelling the datetime offset fix type for change-log entries.
48
+	 */
49
+	const DATETIME_OFFSET_FIX_CHANGELOG_TYPE = 'datetime_offset_fix';
50
+
51
+
52
+	/**
53
+	 * String labelling a datetime offset fix error for change-log entries.
54
+	 */
55
+	const DATETIME_OFFSET_FIX_CHANGELOG_ERROR_TYPE = 'datetime_offset_fix_error';
56
+
57
+	/**
58
+	 * @var EEM_Base[]
59
+	 */
60
+	protected $models_with_datetime_fields = array();
61
+
62
+	// phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
63
+
64
+	/**
65
+	 * Performs any necessary setup for starting the job. This is also a good
66
+	 * place to setup the $job_arguments which will be used for subsequent HTTP requests
67
+	 * when continue_job will be called
68
+	 *
69
+	 * @param JobParameters $job_parameters
70
+	 * @return JobStepResponse
71
+	 * @throws EE_Error
72
+	 * @throws InvalidArgumentException
73
+	 * @throws InvalidDataTypeException
74
+	 * @throws InvalidInterfaceException
75
+	 */
76
+	public function create_job(JobParameters $job_parameters)
77
+	{
78
+		$models_with_datetime_fields = $this->getModelsWithDatetimeFields();
79
+		// we'll be doing each model as a batch.
80
+		$job_parameters->set_job_size(count($models_with_datetime_fields));
81
+		return new JobStepResponse(
82
+			$job_parameters,
83
+			esc_html__('Starting Datetime Offset Fix', 'event_espresso')
84
+		);
85
+	}
86
+
87
+	/**
88
+	 * Performs another step of the job
89
+	 *
90
+	 * @param JobParameters $job_parameters
91
+	 * @param int           $batch_size
92
+	 * @return JobStepResponse
93
+	 * @throws EE_Error
94
+	 * @throws InvalidArgumentException
95
+	 * @throws InvalidDataTypeException
96
+	 * @throws InvalidInterfaceException
97
+	 */
98
+	public function continue_job(JobParameters $job_parameters, $batch_size = 50)
99
+	{
100
+		$models_to_process = $this->getModelsWithDatetimeFields();
101
+		// let's pop off the a model and do the query to apply the offset.
102
+		$model_to_process = array_pop($models_to_process);
103
+		// update our record
104
+		$this->setModelsToProcess($models_to_process);
105
+		$this->processModel($model_to_process);
106
+		$this->updateCountOfModelsProcessed();
107
+		$job_parameters->set_units_processed($this->getCountOfModelsProcessed());
108
+		if (count($models_to_process) > 0) {
109
+			$job_parameters->set_status(JobParameters::status_continue);
110
+		} else {
111
+			$job_parameters->set_status(JobParameters::status_complete);
112
+		}
113
+		return new JobStepResponse(
114
+			$job_parameters,
115
+			sprintf(
116
+				esc_html__('Updated the offset for all datetime fields on the %s model.', 'event_espresso'),
117
+				$model_to_process
118
+			)
119
+		);
120
+	}
121
+
122
+	/**
123
+	 * Performs any clean-up logic when we know the job is completed
124
+	 *
125
+	 * @param JobParameters $job_parameters
126
+	 * @return JobStepResponse
127
+	 * @throws BatchRequestException
128
+	 */
129
+	public function cleanup_job(JobParameters $job_parameters)
130
+	{
131
+		// delete important saved options.
132
+		delete_option(self::MODELS_TO_PROCESS_OPTION_KEY);
133
+		delete_option(self::COUNT_OF_MODELS_PROCESSED);
134
+		delete_option(self::OPTION_KEY_OFFSET_RANGE_START_DATE);
135
+		delete_option(self::OPTION_KEY_OFFSET_RANGE_END_DATE);
136
+		return new JobStepResponse($job_parameters, esc_html__(
137
+			'Offset has been applied to all affected fields.',
138
+			'event_espresso'
139
+		));
140
+	}
141
+
142
+
143
+	/**
144
+	 * Contains the logic for processing a model and applying the datetime offset to affected fields on that model.
145
+	 *
146
+	 * @param string $model_class_name
147
+	 * @throws EE_Error
148
+	 */
149
+	protected function processModel($model_class_name)
150
+	{
151
+		global $wpdb;
152
+		/** @var EEM_Base $model */
153
+		$model = $model_class_name::instance();
154
+		$original_offset = self::getOffset();
155
+		$start_date_range = self::getStartDateRange();
156
+		$end_date_range = self::getEndDateRange();
157
+		$sql_date_function = $original_offset > 0 ? 'DATE_ADD' : 'DATE_SUB';
158
+		$offset = abs($original_offset) * 60;
159
+		$date_ranges = array();
160
+		// since some affected models might have two tables, we have to get our tables and set up a query for each table.
161
+		foreach ($model->get_tables() as $table) {
162
+			$query = 'UPDATE ' . $table->get_table_name();
163
+			$fields_affected = array();
164
+			$inner_query = array();
165
+			foreach ($model->_get_fields_for_table($table->get_table_alias()) as $model_field) {
166
+				if ($model_field instanceof EE_Datetime_Field) {
167
+					$inner_query[ $model_field->get_table_column() ] = $model_field->get_table_column() . ' = '
168
+																	   . $sql_date_function . '('
169
+																	   . $model_field->get_table_column()
170
+																	   . ", INTERVAL {$offset} MINUTE)";
171
+					$fields_affected[] = $model_field;
172
+				}
173
+			}
174
+			if (! $fields_affected) {
175
+				continue;
176
+			}
177
+			// do we do one query per column/field or one query for all fields on the model? It all depends on whether
178
+			// there is a date range applied or not.
179
+			if ($start_date_range instanceof DbSafeDateTime || $end_date_range instanceof DbSafeDateTime) {
180
+				$result = $this->doQueryForEachField($query, $inner_query, $start_date_range, $end_date_range);
181
+			} else {
182
+				$result = $this->doQueryForAllFields($query, $inner_query);
183
+			}
184
+
185
+			// record appropriate logs for the query
186
+			switch (true) {
187
+				case $result === false:
188
+					// record error.
189
+					$error_message = $wpdb->last_error;
190
+					// handle the edge cases where last_error might be empty.
191
+					if (! $error_message) {
192
+						$error_message = esc_html__('Unknown mysql error occurred.', 'event_espresso');
193
+					}
194
+					$this->recordChangeLog($model, $original_offset, $table, $fields_affected, $error_message);
195
+					break;
196
+				case is_array($result) && ! empty($result):
197
+					foreach ($result as $field_name => $error_message) {
198
+						$this->recordChangeLog($model, $original_offset, $table, array($field_name), $error_message);
199
+					}
200
+					break;
201
+				default:
202
+					$this->recordChangeLog($model, $original_offset, $table, $fields_affected);
203
+			}
204
+		}
205
+	}
206
+
207
+
208
+	/**
209
+	 * Does the query on each $inner_query individually.
210
+	 *
211
+	 * @param string              $query
212
+	 * @param array               $inner_query
213
+	 * @param DbSafeDateTime|null $start_date_range
214
+	 * @param DbSafeDateTime|null $end_date_range
215
+	 * @return array  An array of any errors encountered and the fields they were for.
216
+	 */
217
+	private function doQueryForEachField($query, array $inner_query, $start_date_range, $end_date_range)
218
+	{
219
+		global $wpdb;
220
+		$errors = array();
221
+		foreach ($inner_query as $field_name => $field_query) {
222
+			$query_to_run = $query;
223
+			$where_conditions = array();
224
+			$query_to_run .= ' SET ' . $field_query;
225
+			if ($start_date_range instanceof DbSafeDateTime) {
226
+				$start_date = $start_date_range->format(EE_Datetime_Field::mysql_timestamp_format);
227
+				$where_conditions[] = "{$field_name} > '{$start_date}'";
228
+			}
229
+			if ($end_date_range instanceof DbSafeDateTime) {
230
+				$end_date = $end_date_range->format(EE_Datetime_Field::mysql_timestamp_format);
231
+				$where_conditions[] = "{$field_name} < '{$end_date}'";
232
+			}
233
+			if ($where_conditions) {
234
+				$query_to_run .= ' WHERE ' . implode(' AND ', $where_conditions);
235
+			}
236
+			$result = $wpdb->query($query_to_run);
237
+			if ($result === false) {
238
+				// record error.
239
+				$error_message = $wpdb->last_error;
240
+				// handle the edgecases where last_error might be empty.
241
+				if (! $error_message) {
242
+					$error_message = esc_html__('Unknown mysql error occured.', 'event_espresso');
243
+				}
244
+				$errors[ $field_name ] = $error_message;
245
+			}
246
+		}
247
+		return $errors;
248
+	}
249
+
250
+
251
+	/**
252
+	 * Performs the query for all fields within the inner_query
253
+	 *
254
+	 * @param string $query
255
+	 * @param array  $inner_query
256
+	 * @return false|int
257
+	 */
258
+	private function doQueryForAllFields($query, array $inner_query)
259
+	{
260
+		global $wpdb;
261
+		$query .= ' SET ' . implode(',', $inner_query);
262
+		return $wpdb->query($query);
263
+	}
264
+
265
+
266
+	/**
267
+	 * Records a changelog entry using the given information.
268
+	 *
269
+	 * @param EEM_Base              $model
270
+	 * @param float                 $offset
271
+	 * @param EE_Table_Base         $table
272
+	 * @param EE_Model_Field_Base[] $model_fields_affected
273
+	 * @param string                $error_message If present then there was an error so let's record that instead.
274
+	 * @throws EE_Error
275
+	 */
276
+	private function recordChangeLog(
277
+		EEM_Base $model,
278
+		$offset,
279
+		EE_Table_Base $table,
280
+		$model_fields_affected,
281
+		$error_message = ''
282
+	) {
283
+		// setup $fields list.
284
+		$fields = array();
285
+		/** @var EE_Datetime_Field $model_field */
286
+		foreach ($model_fields_affected as $model_field) {
287
+			if (! $model_field instanceof EE_Datetime_Field) {
288
+				continue;
289
+			}
290
+			$fields[] = $model_field->get_name();
291
+		}
292
+		// setup the message for the changelog entry.
293
+		$message = $error_message
294
+			? sprintf(
295
+				esc_html__(
296
+					'The %1$s table for the %2$s model did not have the offset of %3$f applied to its fields (%4$s), because of the following error:%5$s',
297
+					'event_espresso'
298
+				),
299
+				$table->get_table_name(),
300
+				$model->get_this_model_name(),
301
+				$offset,
302
+				implode(',', $fields),
303
+				$error_message
304
+			)
305
+			: sprintf(
306
+				esc_html__(
307
+					'The %1$s table for the %2$s model has had the offset of %3$f applied to its following fields: %4$s',
308
+					'event_espresso'
309
+				),
310
+				$table->get_table_name(),
311
+				$model->get_this_model_name(),
312
+				$offset,
313
+				implode(',', $fields)
314
+			);
315
+		// write to the log
316
+		$changelog = EE_Change_Log::new_instance(array(
317
+			'LOG_type'    => $error_message
318
+				? self::DATETIME_OFFSET_FIX_CHANGELOG_ERROR_TYPE
319
+				: self::DATETIME_OFFSET_FIX_CHANGELOG_TYPE,
320
+			'LOG_message' => $message,
321
+		));
322
+		$changelog->save();
323
+	}
324
+
325
+
326
+	/**
327
+	 * Returns an array of models that have datetime fields.
328
+	 * This array is added to a short lived transient cache to keep having to build this list to a minimum.
329
+	 *
330
+	 * @return array an array of model class names.
331
+	 * @throws EE_Error
332
+	 * @throws InvalidDataTypeException
333
+	 * @throws InvalidInterfaceException
334
+	 * @throws InvalidArgumentException
335
+	 */
336
+	private function getModelsWithDatetimeFields()
337
+	{
338
+		$this->getModelsToProcess();
339
+		if (! empty($this->models_with_datetime_fields)) {
340
+			return $this->models_with_datetime_fields;
341
+		}
342
+
343
+		$all_non_abstract_models = EE_Registry::instance()->non_abstract_db_models;
344
+		foreach ($all_non_abstract_models as $non_abstract_model) {
345
+			// get model instance
346
+			/** @var EEM_Base $non_abstract_model */
347
+			$non_abstract_model = $non_abstract_model::instance();
348
+			if ($non_abstract_model->get_a_field_of_type('EE_Datetime_Field') instanceof EE_Datetime_Field) {
349
+				$this->models_with_datetime_fields[] = get_class($non_abstract_model);
350
+			}
351
+		}
352
+		$this->setModelsToProcess($this->models_with_datetime_fields);
353
+		return $this->models_with_datetime_fields;
354
+	}
355
+
356
+
357
+	/**
358
+	 * This simply records the models that have been processed with our tracking option.
359
+	 *
360
+	 * @param array $models_to_set array of model class names.
361
+	 */
362
+	private function setModelsToProcess($models_to_set)
363
+	{
364
+		update_option(self::MODELS_TO_PROCESS_OPTION_KEY, $models_to_set);
365
+	}
366
+
367
+
368
+	/**
369
+	 * Used to keep track of how many models have been processed for the batch
370
+	 *
371
+	 * @param $count
372
+	 */
373
+	private function updateCountOfModelsProcessed($count = 1)
374
+	{
375
+		$count = $this->getCountOfModelsProcessed() + (int) $count;
376
+		update_option(self::COUNT_OF_MODELS_PROCESSED, $count);
377
+	}
378
+
379
+
380
+	/**
381
+	 * Retrieve the tracked number of models processed between requests.
382
+	 *
383
+	 * @return int
384
+	 */
385
+	private function getCountOfModelsProcessed()
386
+	{
387
+		return (int) get_option(self::COUNT_OF_MODELS_PROCESSED, 0);
388
+	}
389
+
390
+
391
+	/**
392
+	 * Returns the models that are left to process.
393
+	 *
394
+	 * @return array  an array of model class names.
395
+	 */
396
+	private function getModelsToProcess()
397
+	{
398
+		if (empty($this->models_with_datetime_fields)) {
399
+			$this->models_with_datetime_fields = get_option(self::MODELS_TO_PROCESS_OPTION_KEY, array());
400
+		}
401
+		return $this->models_with_datetime_fields;
402
+	}
403
+
404
+
405
+	/**
406
+	 * Used to record the offset that will be applied to dates and times for EE_Datetime_Field columns.
407
+	 *
408
+	 * @param float $offset
409
+	 */
410
+	public static function updateOffset($offset)
411
+	{
412
+		update_option(self::OFFSET_TO_APPLY_OPTION_KEY, $offset);
413
+	}
414
+
415
+
416
+	/**
417
+	 * Used to retrieve the saved offset that will be applied to dates and times for EE_Datetime_Field columns.
418
+	 *
419
+	 * @return float
420
+	 */
421
+	public static function getOffset()
422
+	{
423
+		return (float) get_option(self::OFFSET_TO_APPLY_OPTION_KEY, 0);
424
+	}
425
+
426
+
427
+	/**
428
+	 * Used to set the saved offset range start date.
429
+	 *
430
+	 * @param DbSafeDateTime|null $start_date
431
+	 */
432
+	public static function updateStartDateRange(DbSafeDateTime $start_date = null)
433
+	{
434
+		$date_to_save = $start_date instanceof DbSafeDateTime
435
+			? $start_date->format('U')
436
+			: '';
437
+		update_option(self::OPTION_KEY_OFFSET_RANGE_START_DATE, $date_to_save);
438
+	}
439
+
440
+
441
+	/**
442
+	 * Used to get the saved offset range start date.
443
+	 *
444
+	 * @return DbSafeDateTime|null
445
+	 */
446
+	public static function getStartDateRange()
447
+	{
448
+		$start_date = get_option(self::OPTION_KEY_OFFSET_RANGE_START_DATE, null);
449
+		try {
450
+			$datetime = DateTime::createFromFormat('U', $start_date, new DateTimeZone('UTC'));
451
+			$start_date = $datetime instanceof DateTime
452
+				? DbSafeDateTime::createFromDateTime($datetime)
453
+				: null;
454
+		} catch (Exception $e) {
455
+			$start_date = null;
456
+		}
457
+		return $start_date;
458
+	}
459
+
460
+
461
+	/**
462
+	 * Used to set the saved offset range end date.
463
+	 *
464
+	 * @param DbSafeDateTime|null $end_date
465
+	 */
466
+	public static function updateEndDateRange(DbSafeDateTime $end_date = null)
467
+	{
468
+		$date_to_save = $end_date instanceof DbSafeDateTime
469
+			? $end_date->format('U')
470
+			: '';
471
+		update_option(self::OPTION_KEY_OFFSET_RANGE_END_DATE, $date_to_save);
472
+	}
473
+
474
+
475
+	/**
476
+	 * Used to get the saved offset range end date.
477
+	 *
478
+	 * @return DbSafeDateTime|null
479
+	 */
480
+	public static function getEndDateRange()
481
+	{
482
+		$end_date = get_option(self::OPTION_KEY_OFFSET_RANGE_END_DATE, null);
483
+		try {
484
+			$datetime = DateTime::createFromFormat('U', $end_date, new DateTimeZone('UTC'));
485
+			$end_date = $datetime instanceof Datetime
486
+				? DbSafeDateTime::createFromDateTime($datetime)
487
+				: null;
488
+		} catch (Exception $e) {
489
+			$end_date = null;
490
+		}
491
+		return $end_date;
492
+	}
493 493
 }
Please login to merge, or discard this patch.
Spacing   +12 added lines, -12 removed lines patch added patch discarded remove patch
@@ -159,19 +159,19 @@  discard block
 block discarded – undo
159 159
         $date_ranges = array();
160 160
         // since some affected models might have two tables, we have to get our tables and set up a query for each table.
161 161
         foreach ($model->get_tables() as $table) {
162
-            $query = 'UPDATE ' . $table->get_table_name();
162
+            $query = 'UPDATE '.$table->get_table_name();
163 163
             $fields_affected = array();
164 164
             $inner_query = array();
165 165
             foreach ($model->_get_fields_for_table($table->get_table_alias()) as $model_field) {
166 166
                 if ($model_field instanceof EE_Datetime_Field) {
167
-                    $inner_query[ $model_field->get_table_column() ] = $model_field->get_table_column() . ' = '
168
-                                                                       . $sql_date_function . '('
167
+                    $inner_query[$model_field->get_table_column()] = $model_field->get_table_column().' = '
168
+                                                                       . $sql_date_function.'('
169 169
                                                                        . $model_field->get_table_column()
170 170
                                                                        . ", INTERVAL {$offset} MINUTE)";
171 171
                     $fields_affected[] = $model_field;
172 172
                 }
173 173
             }
174
-            if (! $fields_affected) {
174
+            if ( ! $fields_affected) {
175 175
                 continue;
176 176
             }
177 177
             // do we do one query per column/field or one query for all fields on the model? It all depends on whether
@@ -188,7 +188,7 @@  discard block
 block discarded – undo
188 188
                     // record error.
189 189
                     $error_message = $wpdb->last_error;
190 190
                     // handle the edge cases where last_error might be empty.
191
-                    if (! $error_message) {
191
+                    if ( ! $error_message) {
192 192
                         $error_message = esc_html__('Unknown mysql error occurred.', 'event_espresso');
193 193
                     }
194 194
                     $this->recordChangeLog($model, $original_offset, $table, $fields_affected, $error_message);
@@ -221,7 +221,7 @@  discard block
 block discarded – undo
221 221
         foreach ($inner_query as $field_name => $field_query) {
222 222
             $query_to_run = $query;
223 223
             $where_conditions = array();
224
-            $query_to_run .= ' SET ' . $field_query;
224
+            $query_to_run .= ' SET '.$field_query;
225 225
             if ($start_date_range instanceof DbSafeDateTime) {
226 226
                 $start_date = $start_date_range->format(EE_Datetime_Field::mysql_timestamp_format);
227 227
                 $where_conditions[] = "{$field_name} > '{$start_date}'";
@@ -231,17 +231,17 @@  discard block
 block discarded – undo
231 231
                 $where_conditions[] = "{$field_name} < '{$end_date}'";
232 232
             }
233 233
             if ($where_conditions) {
234
-                $query_to_run .= ' WHERE ' . implode(' AND ', $where_conditions);
234
+                $query_to_run .= ' WHERE '.implode(' AND ', $where_conditions);
235 235
             }
236 236
             $result = $wpdb->query($query_to_run);
237 237
             if ($result === false) {
238 238
                 // record error.
239 239
                 $error_message = $wpdb->last_error;
240 240
                 // handle the edgecases where last_error might be empty.
241
-                if (! $error_message) {
241
+                if ( ! $error_message) {
242 242
                     $error_message = esc_html__('Unknown mysql error occured.', 'event_espresso');
243 243
                 }
244
-                $errors[ $field_name ] = $error_message;
244
+                $errors[$field_name] = $error_message;
245 245
             }
246 246
         }
247 247
         return $errors;
@@ -258,7 +258,7 @@  discard block
 block discarded – undo
258 258
     private function doQueryForAllFields($query, array $inner_query)
259 259
     {
260 260
         global $wpdb;
261
-        $query .= ' SET ' . implode(',', $inner_query);
261
+        $query .= ' SET '.implode(',', $inner_query);
262 262
         return $wpdb->query($query);
263 263
     }
264 264
 
@@ -284,7 +284,7 @@  discard block
 block discarded – undo
284 284
         $fields = array();
285 285
         /** @var EE_Datetime_Field $model_field */
286 286
         foreach ($model_fields_affected as $model_field) {
287
-            if (! $model_field instanceof EE_Datetime_Field) {
287
+            if ( ! $model_field instanceof EE_Datetime_Field) {
288 288
                 continue;
289 289
             }
290 290
             $fields[] = $model_field->get_name();
@@ -336,7 +336,7 @@  discard block
 block discarded – undo
336 336
     private function getModelsWithDatetimeFields()
337 337
     {
338 338
         $this->getModelsToProcess();
339
-        if (! empty($this->models_with_datetime_fields)) {
339
+        if ( ! empty($this->models_with_datetime_fields)) {
340 340
             return $this->models_with_datetime_fields;
341 341
         }
342 342
 
Please login to merge, or discard this patch.
core/helpers/EEH_Form_Fields.helper.php 2 patches
Indentation   +2064 added lines, -2064 removed lines patch added patch discarded remove patch
@@ -27,1057 +27,1057 @@  discard block
 block discarded – undo
27 27
  */
28 28
 class EEH_Form_Fields
29 29
 {
30
-    /**
31
-     *  Generates HTML for the forms used on admin pages
32
-     *
33
-     *
34
-     * @static
35
-     * @access public
36
-     * @param array $input_vars - array of input field details
37
-     *                          format:
38
-     *                          $template_form_fields['field-id'] = array(
39
-     *                          'name' => 'name_attribute',
40
-     *                          'label' => esc_html__('Field Label', 'event_espresso'), //or false
41
-     *                          'input' => 'hidden', //field input type can be 'text', 'select', 'textarea', 'hidden',
42
-     *                          'checkbox', 'wp_editor'
43
-     *                          'type' => 'int', //what "type" the value is (i.e. string, int etc)
44
-     *                          'required' => false, //boolean for whether the field is required
45
-     *                          'validation' => true, //boolean, whether to validate the field (todo)
46
-     *                          'value' => 'some_value_for_field', //what value is used for field
47
-     *                          'format' => '%d', //what format the value is (%d, %f, or %s)
48
-     *                          'db-col' => 'column_in_db' //used to indicate which column the field corresponds with
49
-     *                          in the db
50
-     *                          'options' => optiona, optionb || array('value' => 'label', '') //if the input type is
51
-     *                          "select", this allows you to set the args for the different <option> tags.
52
-     *                          'tabindex' => 1 //this allows you to set the tabindex for the field.
53
-     *                          'append_content' => '' //this allows you to send in html content to append to the
54
-     *                          field.
55
-     *                          )
56
-     * @param array $form_id    - used for defining unique identifiers for the form.
57
-     * @return string
58
-     * @todo   : at some point we can break this down into other static methods to abstract it a bit better.
59
-     */
60
-    public static function get_form_fields($input_vars = [], $form_id = false)
61
-    {
62
-
63
-        if (empty($input_vars)) {
64
-            EE_Error::add_error(
65
-                esc_html__('missing required variables for the form field generator', 'event_espresso'),
66
-                __FILE__,
67
-                __FUNCTION__,
68
-                __LINE__
69
-            );
70
-            return false;
71
-        }
72
-
73
-        $output        = "";
74
-        $inputs        = [];
75
-        $hidden_inputs = [];
76
-
77
-        // cycle thru inputs
78
-        foreach ($input_vars as $input_key => $input_value) {
79
-            $defaults = [
80
-                'append_content' => '',
81
-                'css_class'      => '',
82
-                'cols'           => 80,
83
-                'db-col'         => 'column_in_db',
84
-                'format'         => '%d',
85
-                'input'          => 'hidden',
86
-                'label'          => esc_html__('No label', 'event_espresso'),
87
-                'name'           => $input_key,
88
-                'options'        => [],
89
-                'required'       => false,
90
-                'tabindex'       => 0,
91
-                'rows'           => 10,
92
-                'type'           => 'int',
93
-                'validation'     => true,
94
-                'value'          => 'some_value_for_field',
95
-            ];
96
-
97
-            $input_value = wp_parse_args($input_value, $defaults);
98
-
99
-            $append_content = $input_value['append_content'];
100
-            $css_class      = $input_value['css_class'];
101
-            $cols           = $input_value['cols'];
102
-            $label          = $input_value['label'];
103
-            $name           = $input_value['name'];
104
-            $options        = $input_value['options'];
105
-            $required       = $input_value['required'];
106
-            $tab_index      = $input_value['tabindex'];
107
-            $rows           = $input_value['rows'];
108
-            $type           = $input_value['input'];
109
-            $value          = $input_value['value'];
110
-
111
-            $id    = $form_id ? $form_id . '-' . $input_key : $input_key;
112
-            $class = $required ? 'required ' . $css_class : $css_class;
113
-
114
-            // what type of input are we dealing with ?
115
-            switch ($type) {
116
-                case 'checkbox':
117
-                case 'radio':
118
-                    $field = self::adminMulti($value, $class, $id, $name, $required, $tab_index, $type, 1, $label);
119
-                    $field .= $append_content ?: '';
120
-                    break;
121
-
122
-                case 'hidden':
123
-                    $field           = null;
124
-                    $hidden_inputs[] = self::adminHidden($css_class, $id, $name, $value);
125
-                    break;
126
-
127
-                case 'select':
128
-                    $options = is_array($options) ? $options : explode(',', $options);
129
-                    $field   = self::adminLabel($id, $label, $required);
130
-                    $field   .= self::adminSelect($value, $class, $id, $name, $required, $tab_index, $options);
131
-                    $field   .= $append_content ?: '';
132
-                    break;
133
-
134
-                case 'textarea':
135
-                    $field = self::adminLabel($id, $label, $required);
136
-                    $field .= self::adminTextarea($class, $cols, $id, $name, $required, $rows, $tab_index, $value);
137
-                    $field .= $append_content ?: '';
138
-                    break;
139
-
140
-                case 'wp_editor':
141
-                    $label = esc_html($label);
142
-                    $field = "<h4>{$label}</h4>";
143
-                    $field .= $append_content ?: '';
144
-                    $field .= self::adminWpEditor(
145
-                        $class,
146
-                        $id,
147
-                        $name,
148
-                        $rows,
149
-                        $tab_index,
150
-                        $value
151
-                    );
152
-                    break;
153
-
154
-                default:
155
-                    $field = self::adminLabel($id, $label, $required);
156
-                    $field .= self::adminText($class, $id, $name, $required, $tab_index, $value);
157
-                    $field .= $append_content ?: '';
158
-            }
159
-            if ($field) {
160
-                $inputs[] = $field;
161
-            }
162
-        } // end foreach( $input_vars as $input_key => $input_value )
163
-
164
-        if (! empty($inputs)) {
165
-            $glue   = "
30
+	/**
31
+	 *  Generates HTML for the forms used on admin pages
32
+	 *
33
+	 *
34
+	 * @static
35
+	 * @access public
36
+	 * @param array $input_vars - array of input field details
37
+	 *                          format:
38
+	 *                          $template_form_fields['field-id'] = array(
39
+	 *                          'name' => 'name_attribute',
40
+	 *                          'label' => esc_html__('Field Label', 'event_espresso'), //or false
41
+	 *                          'input' => 'hidden', //field input type can be 'text', 'select', 'textarea', 'hidden',
42
+	 *                          'checkbox', 'wp_editor'
43
+	 *                          'type' => 'int', //what "type" the value is (i.e. string, int etc)
44
+	 *                          'required' => false, //boolean for whether the field is required
45
+	 *                          'validation' => true, //boolean, whether to validate the field (todo)
46
+	 *                          'value' => 'some_value_for_field', //what value is used for field
47
+	 *                          'format' => '%d', //what format the value is (%d, %f, or %s)
48
+	 *                          'db-col' => 'column_in_db' //used to indicate which column the field corresponds with
49
+	 *                          in the db
50
+	 *                          'options' => optiona, optionb || array('value' => 'label', '') //if the input type is
51
+	 *                          "select", this allows you to set the args for the different <option> tags.
52
+	 *                          'tabindex' => 1 //this allows you to set the tabindex for the field.
53
+	 *                          'append_content' => '' //this allows you to send in html content to append to the
54
+	 *                          field.
55
+	 *                          )
56
+	 * @param array $form_id    - used for defining unique identifiers for the form.
57
+	 * @return string
58
+	 * @todo   : at some point we can break this down into other static methods to abstract it a bit better.
59
+	 */
60
+	public static function get_form_fields($input_vars = [], $form_id = false)
61
+	{
62
+
63
+		if (empty($input_vars)) {
64
+			EE_Error::add_error(
65
+				esc_html__('missing required variables for the form field generator', 'event_espresso'),
66
+				__FILE__,
67
+				__FUNCTION__,
68
+				__LINE__
69
+			);
70
+			return false;
71
+		}
72
+
73
+		$output        = "";
74
+		$inputs        = [];
75
+		$hidden_inputs = [];
76
+
77
+		// cycle thru inputs
78
+		foreach ($input_vars as $input_key => $input_value) {
79
+			$defaults = [
80
+				'append_content' => '',
81
+				'css_class'      => '',
82
+				'cols'           => 80,
83
+				'db-col'         => 'column_in_db',
84
+				'format'         => '%d',
85
+				'input'          => 'hidden',
86
+				'label'          => esc_html__('No label', 'event_espresso'),
87
+				'name'           => $input_key,
88
+				'options'        => [],
89
+				'required'       => false,
90
+				'tabindex'       => 0,
91
+				'rows'           => 10,
92
+				'type'           => 'int',
93
+				'validation'     => true,
94
+				'value'          => 'some_value_for_field',
95
+			];
96
+
97
+			$input_value = wp_parse_args($input_value, $defaults);
98
+
99
+			$append_content = $input_value['append_content'];
100
+			$css_class      = $input_value['css_class'];
101
+			$cols           = $input_value['cols'];
102
+			$label          = $input_value['label'];
103
+			$name           = $input_value['name'];
104
+			$options        = $input_value['options'];
105
+			$required       = $input_value['required'];
106
+			$tab_index      = $input_value['tabindex'];
107
+			$rows           = $input_value['rows'];
108
+			$type           = $input_value['input'];
109
+			$value          = $input_value['value'];
110
+
111
+			$id    = $form_id ? $form_id . '-' . $input_key : $input_key;
112
+			$class = $required ? 'required ' . $css_class : $css_class;
113
+
114
+			// what type of input are we dealing with ?
115
+			switch ($type) {
116
+				case 'checkbox':
117
+				case 'radio':
118
+					$field = self::adminMulti($value, $class, $id, $name, $required, $tab_index, $type, 1, $label);
119
+					$field .= $append_content ?: '';
120
+					break;
121
+
122
+				case 'hidden':
123
+					$field           = null;
124
+					$hidden_inputs[] = self::adminHidden($css_class, $id, $name, $value);
125
+					break;
126
+
127
+				case 'select':
128
+					$options = is_array($options) ? $options : explode(',', $options);
129
+					$field   = self::adminLabel($id, $label, $required);
130
+					$field   .= self::adminSelect($value, $class, $id, $name, $required, $tab_index, $options);
131
+					$field   .= $append_content ?: '';
132
+					break;
133
+
134
+				case 'textarea':
135
+					$field = self::adminLabel($id, $label, $required);
136
+					$field .= self::adminTextarea($class, $cols, $id, $name, $required, $rows, $tab_index, $value);
137
+					$field .= $append_content ?: '';
138
+					break;
139
+
140
+				case 'wp_editor':
141
+					$label = esc_html($label);
142
+					$field = "<h4>{$label}</h4>";
143
+					$field .= $append_content ?: '';
144
+					$field .= self::adminWpEditor(
145
+						$class,
146
+						$id,
147
+						$name,
148
+						$rows,
149
+						$tab_index,
150
+						$value
151
+					);
152
+					break;
153
+
154
+				default:
155
+					$field = self::adminLabel($id, $label, $required);
156
+					$field .= self::adminText($class, $id, $name, $required, $tab_index, $value);
157
+					$field .= $append_content ?: '';
158
+			}
159
+			if ($field) {
160
+				$inputs[] = $field;
161
+			}
162
+		} // end foreach( $input_vars as $input_key => $input_value )
163
+
164
+		if (! empty($inputs)) {
165
+			$glue   = "
166 166
                 </li>
167 167
                 <li>
168 168
                     ";
169
-            $inputs = implode($glue, $inputs);
170
-            $output = "
169
+			$inputs = implode($glue, $inputs);
170
+			$output = "
171 171
             <ul>
172 172
                 <li>
173 173
                 {$inputs}
174 174
                 </li>
175 175
             </ul>
176 176
             ";
177
-        }
178
-        return $output . implode("\n", $hidden_inputs);
179
-    }
180
-
181
-
182
-    /**
183
-     * form_fields_array
184
-     * This utility function assembles form fields from a given structured array with field information.
185
-     * //TODO: This is an alternate generator that we may want to use instead.
186
-     *
187
-     * @param array $fields structured array of fields to assemble in the following format:
188
-     *                      [field_name] => array(
189
-     *                      ['label'] => 'label for field',
190
-     *                      ['labels'] => array('label_1', 'label_2'); //optional - if the field type is a multi select
191
-     *                      type of field you can indicated the labels for each option via this index
192
-     *                      ['extra_desc'] => 'extra description for the field', //optional
193
-     *                      ['type'] => 'textarea'|'text'|'wp_editor'|'checkbox'|'radio'|'hidden'|'select', //defaults
194
-     *                      to text
195
-     *                      ['value'] => 'value that goes in the field', //(if multi then this is an array of values
196
-     *                      and the 'default' paramater will be used for what is selected)
197
-     *                      ['default'] => 'default if the field type is multi (i.e. select or radios or checkboxes)',
198
-     *                      ['class'] => 'name-of-class(es)-for-input',
199
-     *                      ['classes'] => array('class_1', 'class_2'); //optional - if the field type is a multi
200
-     *                      select type of field you can indicate the css class for each option via this index.
201
-     *                      ['id'] => 'css-id-for-input') //defaults to 'field_name'
202
-     *                      ['unique_id'] => 1 //defaults to empty string.  This is useful for when the fields
203
-     *                      generated are going to be used in a loop and you want to make sure that the field
204
-     *                      identifiers are unique from each other.
205
-     *                      ['dimensions'] => array(100,300), //defaults to empty array.  This is used by field types
206
-     *                      such as textarea to indicate cols/rows.
207
-     *                      ['tabindex'] => '' //this allows you to set the tabindex for the field.
208
-     *                      ['wpeditor_args'] => array() //if the type of field is wpeditor then this can optionally
209
-     *                      contain an array of arguments for the editor setup.
210
-     *
211
-     * @return array         an array of inputs for form indexed by field name, and in the following structure:
212
-     *     [field_name] => array( 'label' => '{label_html}', 'field' => '{input_html}'
213
-     */
214
-    public static function get_form_fields_array($fields)
215
-    {
216
-
217
-        $form_fields = [];
218
-        $fields      = (array) $fields;
219
-
220
-        foreach ($fields as $field_name => $field_atts) {
221
-            // defaults:
222
-            $defaults = [
223
-                'class'         => '',
224
-                'classes'       => '',
225
-                'default'       => '',
226
-                'dimensions'    => ['10', '5'],
227
-                'extra_desc'    => '',
228
-                'id'            => $field_name,
229
-                'label'         => '',
230
-                'labels'        => '',
231
-                'required'      => false,
232
-                'tabindex'      => 0,
233
-                'type'          => 'text',
234
-                'unique_id'     => '',
235
-                'value'         => '',
236
-                'wpeditor_args' => [],
237
-            ];
238
-            // merge defaults with passed arguments
239
-            $_fields = wp_parse_args($field_atts, $defaults);
240
-
241
-            $class          = $_fields['class'];
242
-            $classes        = $_fields['classes'];
243
-            $default        = $_fields['default'];
244
-            $dims           = $_fields['dimensions'];
245
-            $extra_desc     = $_fields['extra_desc'];
246
-            $id             = $_fields['id'];
247
-            $label          = $_fields['label'];
248
-            $labels         = $_fields['labels'];
249
-            $required       = $_fields['required'];
250
-            $tab_index      = $_fields['tabindex'];
251
-            $type           = $_fields['type'];
252
-            $unique_id      = $_fields['unique_id'];
253
-            $value          = $_fields['value'];
254
-            $wp_editor_args = $_fields['wpeditor_args'];
255
-
256
-            // generate label
257
-            $label = ! empty($label) ? self::adminLabel($id, $label, $required) : '';
258
-            // generate field name
259
-            $name = ! empty($unique_id) ? $field_name . '[' . $unique_id . ']' : $field_name;
260
-
261
-            // we determine what we're building based on the type
262
-            switch ($type) {
263
-                case 'checkbox':
264
-                case 'radio':
265
-                    if (is_array($value)) {
266
-                        $c_input = '';
267
-                        foreach ($value as $key => $val) {
268
-                            $c_input .= self::adminMulti(
269
-                                $default,
270
-                                isset($classes[ $key ]) ? $classes[ $key ] : '',
271
-                                $field_name . '_' . $value,
272
-                                $name,
273
-                                $required,
274
-                                $tab_index,
275
-                                $type,
276
-                                $val,
277
-                                isset($labels[ $key ]) ? $labels[ $key ] : ''
278
-                            );
279
-                        }
280
-                        $field = $c_input;
281
-                    } else {
282
-                        $field = self::adminMulti(
283
-                            $default,
284
-                            $class,
285
-                            $id,
286
-                            $name,
287
-                            $required,
288
-                            $tab_index,
289
-                            $type,
290
-                            $value,
291
-                            $_fields['label']
292
-                        );
293
-                    }
294
-                    break;
295
-
296
-                case 'hidden':
297
-                    $field = self::adminHidden($class, $id, $name, $value);
298
-                    break;
299
-
300
-                case 'select':
301
-                    $options = [];
302
-                    foreach ($value as $key => $val) {
303
-                        $options[ $val ] = isset($labels[ $key ]) ? $labels[ $key ] : '';
304
-                    }
305
-                    $field = self::adminSelect($default, $class, $id, $name, $required, $tab_index, $options);
306
-                    break;
307
-
308
-                case 'textarea':
309
-                    $field =
310
-                        self::adminTextarea($class, $dims[0], $id, $name, $required, $dims[1], $tab_index, $value);
311
-                    break;
312
-
313
-                case 'wp_editor':
314
-                    $field = self::adminWpEditor(
315
-                        $class,
316
-                        $_fields['id'],
317
-                        $name,
318
-                        $dims[1],
319
-                        $tab_index,
320
-                        $value,
321
-                        $wp_editor_args
322
-                    );
323
-                    break;
324
-
325
-                default:
326
-                    $field = self::adminText($class, $id, $name, $required, $tab_index, $value);
327
-            }
328
-
329
-            $form_fields[ $field_name ] = ['label' => $label, 'field' => $field . $extra_desc];
330
-        }
331
-
332
-        return $form_fields;
333
-    }
334
-
335
-
336
-    /**
337
-     * @param string $class
338
-     * @param string $id
339
-     * @param string $name
340
-     * @param string $value
341
-     * @return string
342
-     * @since   4.10.14.p
343
-     */
344
-    private static function adminHidden($class, $id, $name, $value)
345
-    {
346
-        $id    = esc_attr($id);
347
-        $name  = esc_attr($name);
348
-        $class = esc_attr($class);
349
-        return "
177
+		}
178
+		return $output . implode("\n", $hidden_inputs);
179
+	}
180
+
181
+
182
+	/**
183
+	 * form_fields_array
184
+	 * This utility function assembles form fields from a given structured array with field information.
185
+	 * //TODO: This is an alternate generator that we may want to use instead.
186
+	 *
187
+	 * @param array $fields structured array of fields to assemble in the following format:
188
+	 *                      [field_name] => array(
189
+	 *                      ['label'] => 'label for field',
190
+	 *                      ['labels'] => array('label_1', 'label_2'); //optional - if the field type is a multi select
191
+	 *                      type of field you can indicated the labels for each option via this index
192
+	 *                      ['extra_desc'] => 'extra description for the field', //optional
193
+	 *                      ['type'] => 'textarea'|'text'|'wp_editor'|'checkbox'|'radio'|'hidden'|'select', //defaults
194
+	 *                      to text
195
+	 *                      ['value'] => 'value that goes in the field', //(if multi then this is an array of values
196
+	 *                      and the 'default' paramater will be used for what is selected)
197
+	 *                      ['default'] => 'default if the field type is multi (i.e. select or radios or checkboxes)',
198
+	 *                      ['class'] => 'name-of-class(es)-for-input',
199
+	 *                      ['classes'] => array('class_1', 'class_2'); //optional - if the field type is a multi
200
+	 *                      select type of field you can indicate the css class for each option via this index.
201
+	 *                      ['id'] => 'css-id-for-input') //defaults to 'field_name'
202
+	 *                      ['unique_id'] => 1 //defaults to empty string.  This is useful for when the fields
203
+	 *                      generated are going to be used in a loop and you want to make sure that the field
204
+	 *                      identifiers are unique from each other.
205
+	 *                      ['dimensions'] => array(100,300), //defaults to empty array.  This is used by field types
206
+	 *                      such as textarea to indicate cols/rows.
207
+	 *                      ['tabindex'] => '' //this allows you to set the tabindex for the field.
208
+	 *                      ['wpeditor_args'] => array() //if the type of field is wpeditor then this can optionally
209
+	 *                      contain an array of arguments for the editor setup.
210
+	 *
211
+	 * @return array         an array of inputs for form indexed by field name, and in the following structure:
212
+	 *     [field_name] => array( 'label' => '{label_html}', 'field' => '{input_html}'
213
+	 */
214
+	public static function get_form_fields_array($fields)
215
+	{
216
+
217
+		$form_fields = [];
218
+		$fields      = (array) $fields;
219
+
220
+		foreach ($fields as $field_name => $field_atts) {
221
+			// defaults:
222
+			$defaults = [
223
+				'class'         => '',
224
+				'classes'       => '',
225
+				'default'       => '',
226
+				'dimensions'    => ['10', '5'],
227
+				'extra_desc'    => '',
228
+				'id'            => $field_name,
229
+				'label'         => '',
230
+				'labels'        => '',
231
+				'required'      => false,
232
+				'tabindex'      => 0,
233
+				'type'          => 'text',
234
+				'unique_id'     => '',
235
+				'value'         => '',
236
+				'wpeditor_args' => [],
237
+			];
238
+			// merge defaults with passed arguments
239
+			$_fields = wp_parse_args($field_atts, $defaults);
240
+
241
+			$class          = $_fields['class'];
242
+			$classes        = $_fields['classes'];
243
+			$default        = $_fields['default'];
244
+			$dims           = $_fields['dimensions'];
245
+			$extra_desc     = $_fields['extra_desc'];
246
+			$id             = $_fields['id'];
247
+			$label          = $_fields['label'];
248
+			$labels         = $_fields['labels'];
249
+			$required       = $_fields['required'];
250
+			$tab_index      = $_fields['tabindex'];
251
+			$type           = $_fields['type'];
252
+			$unique_id      = $_fields['unique_id'];
253
+			$value          = $_fields['value'];
254
+			$wp_editor_args = $_fields['wpeditor_args'];
255
+
256
+			// generate label
257
+			$label = ! empty($label) ? self::adminLabel($id, $label, $required) : '';
258
+			// generate field name
259
+			$name = ! empty($unique_id) ? $field_name . '[' . $unique_id . ']' : $field_name;
260
+
261
+			// we determine what we're building based on the type
262
+			switch ($type) {
263
+				case 'checkbox':
264
+				case 'radio':
265
+					if (is_array($value)) {
266
+						$c_input = '';
267
+						foreach ($value as $key => $val) {
268
+							$c_input .= self::adminMulti(
269
+								$default,
270
+								isset($classes[ $key ]) ? $classes[ $key ] : '',
271
+								$field_name . '_' . $value,
272
+								$name,
273
+								$required,
274
+								$tab_index,
275
+								$type,
276
+								$val,
277
+								isset($labels[ $key ]) ? $labels[ $key ] : ''
278
+							);
279
+						}
280
+						$field = $c_input;
281
+					} else {
282
+						$field = self::adminMulti(
283
+							$default,
284
+							$class,
285
+							$id,
286
+							$name,
287
+							$required,
288
+							$tab_index,
289
+							$type,
290
+							$value,
291
+							$_fields['label']
292
+						);
293
+					}
294
+					break;
295
+
296
+				case 'hidden':
297
+					$field = self::adminHidden($class, $id, $name, $value);
298
+					break;
299
+
300
+				case 'select':
301
+					$options = [];
302
+					foreach ($value as $key => $val) {
303
+						$options[ $val ] = isset($labels[ $key ]) ? $labels[ $key ] : '';
304
+					}
305
+					$field = self::adminSelect($default, $class, $id, $name, $required, $tab_index, $options);
306
+					break;
307
+
308
+				case 'textarea':
309
+					$field =
310
+						self::adminTextarea($class, $dims[0], $id, $name, $required, $dims[1], $tab_index, $value);
311
+					break;
312
+
313
+				case 'wp_editor':
314
+					$field = self::adminWpEditor(
315
+						$class,
316
+						$_fields['id'],
317
+						$name,
318
+						$dims[1],
319
+						$tab_index,
320
+						$value,
321
+						$wp_editor_args
322
+					);
323
+					break;
324
+
325
+				default:
326
+					$field = self::adminText($class, $id, $name, $required, $tab_index, $value);
327
+			}
328
+
329
+			$form_fields[ $field_name ] = ['label' => $label, 'field' => $field . $extra_desc];
330
+		}
331
+
332
+		return $form_fields;
333
+	}
334
+
335
+
336
+	/**
337
+	 * @param string $class
338
+	 * @param string $id
339
+	 * @param string $name
340
+	 * @param string $value
341
+	 * @return string
342
+	 * @since   4.10.14.p
343
+	 */
344
+	private static function adminHidden($class, $id, $name, $value)
345
+	{
346
+		$id    = esc_attr($id);
347
+		$name  = esc_attr($name);
348
+		$class = esc_attr($class);
349
+		return "
350 350
         <input name='{$name}' type='hidden' id='{$id}' class='{$class}' value='{$value}' />";
351
-    }
352
-
353
-
354
-    /**
355
-     * @param string $id
356
-     * @param string $label
357
-     * @param string $required
358
-     * @return string
359
-     * @since   4.10.14.p
360
-     */
361
-    private static function adminLabel($id, $label, $required)
362
-    {
363
-        $id       = esc_attr($id);
364
-        $label    = esc_html($label);
365
-        $required = filter_var($required, FILTER_VALIDATE_BOOLEAN) ? " <span>*</span>" : '';
366
-        return "<label for='{$id}'>{$label}{$required}</label>";
367
-    }
368
-
369
-
370
-    /**
371
-     * @param string $default
372
-     * @param string $class
373
-     * @param string $id
374
-     * @param string $name
375
-     * @param string $required
376
-     * @param int    $tab_index
377
-     * @param string $type
378
-     * @param string $value
379
-     * @param string $label
380
-     * @return string
381
-     * @since   4.10.14.p
382
-     */
383
-    private static function adminMulti($default, $class, $id, $name, $required, $tab_index, $type, $value, $label = '')
384
-    {
385
-        $id        = esc_attr($id);
386
-        $name      = esc_attr($name);
387
-        $class     = esc_attr($class);
388
-        $tab_index = absint($tab_index);
389
-        $checked   = ! empty($default) && $default == $value ? 'checked ' : '';
390
-        $required  = filter_var($required, FILTER_VALIDATE_BOOLEAN) ? 'required' : '';
391
-        $input     = "
351
+	}
352
+
353
+
354
+	/**
355
+	 * @param string $id
356
+	 * @param string $label
357
+	 * @param string $required
358
+	 * @return string
359
+	 * @since   4.10.14.p
360
+	 */
361
+	private static function adminLabel($id, $label, $required)
362
+	{
363
+		$id       = esc_attr($id);
364
+		$label    = esc_html($label);
365
+		$required = filter_var($required, FILTER_VALIDATE_BOOLEAN) ? " <span>*</span>" : '';
366
+		return "<label for='{$id}'>{$label}{$required}</label>";
367
+	}
368
+
369
+
370
+	/**
371
+	 * @param string $default
372
+	 * @param string $class
373
+	 * @param string $id
374
+	 * @param string $name
375
+	 * @param string $required
376
+	 * @param int    $tab_index
377
+	 * @param string $type
378
+	 * @param string $value
379
+	 * @param string $label
380
+	 * @return string
381
+	 * @since   4.10.14.p
382
+	 */
383
+	private static function adminMulti($default, $class, $id, $name, $required, $tab_index, $type, $value, $label = '')
384
+	{
385
+		$id        = esc_attr($id);
386
+		$name      = esc_attr($name);
387
+		$class     = esc_attr($class);
388
+		$tab_index = absint($tab_index);
389
+		$checked   = ! empty($default) && $default == $value ? 'checked ' : '';
390
+		$required  = filter_var($required, FILTER_VALIDATE_BOOLEAN) ? 'required' : '';
391
+		$input     = "
392 392
         <input name='{$name}[]' type='{$type}' id='{$id}' class='{$class}' value='{$value}' {$checked} {$required} tabindex='{$tab_index}'/>";
393
-        if ($label === '') {
394
-            return $input;
395
-        }
396
-        $label = esc_html($label);
397
-        $label_class = self::appendInputSizeClass('', $label);
398
-        $label_class = $label_class ? ' class="' . $label_class . '"' : '';
399
-        return "
393
+		if ($label === '') {
394
+			return $input;
395
+		}
396
+		$label = esc_html($label);
397
+		$label_class = self::appendInputSizeClass('', $label);
398
+		$label_class = $label_class ? ' class="' . $label_class . '"' : '';
399
+		return "
400 400
         <label for='$id'{$label_class}>
401 401
             {$input}
402 402
             {$label}
403 403
         </label>";
404
-    }
405
-
406
-
407
-    /**
408
-     * @param string $default
409
-     * @param string $class
410
-     * @param string $id
411
-     * @param string $name
412
-     * @param string $required
413
-     * @param int    $tab_index
414
-     * @param array  $options
415
-     * @return string
416
-     * @since   4.10.14.p
417
-     */
418
-    private static function adminSelect($default, $class, $id, $name, $required, $tab_index, $options = [])
419
-    {
420
-        $options_array = [];
421
-        foreach ($options as $value => $label) {
422
-            $selected        = ! empty($default) && $default == $value ? 'selected' : '';
423
-            $value           = esc_attr($value);
424
-            $label           = wp_strip_all_tags($label);
425
-            $options_array[] = "<option value='{$value}' {$selected}>{$label}</option>";
426
-        }
427
-        $options_html = implode($options_array, "\n");
428
-        $id           = esc_attr($id);
429
-        $name         = esc_attr($name);
430
-        $class        = esc_attr($class);
431
-        $tab_index    = absint($tab_index);
432
-        $required     = filter_var($required, FILTER_VALIDATE_BOOLEAN) ? 'required' : '';
433
-
434
-        $class = self::appendInputSizeClass($class, $options);
435
-
436
-        return "
404
+	}
405
+
406
+
407
+	/**
408
+	 * @param string $default
409
+	 * @param string $class
410
+	 * @param string $id
411
+	 * @param string $name
412
+	 * @param string $required
413
+	 * @param int    $tab_index
414
+	 * @param array  $options
415
+	 * @return string
416
+	 * @since   4.10.14.p
417
+	 */
418
+	private static function adminSelect($default, $class, $id, $name, $required, $tab_index, $options = [])
419
+	{
420
+		$options_array = [];
421
+		foreach ($options as $value => $label) {
422
+			$selected        = ! empty($default) && $default == $value ? 'selected' : '';
423
+			$value           = esc_attr($value);
424
+			$label           = wp_strip_all_tags($label);
425
+			$options_array[] = "<option value='{$value}' {$selected}>{$label}</option>";
426
+		}
427
+		$options_html = implode($options_array, "\n");
428
+		$id           = esc_attr($id);
429
+		$name         = esc_attr($name);
430
+		$class        = esc_attr($class);
431
+		$tab_index    = absint($tab_index);
432
+		$required     = filter_var($required, FILTER_VALIDATE_BOOLEAN) ? 'required' : '';
433
+
434
+		$class = self::appendInputSizeClass($class, $options);
435
+
436
+		return "
437 437
         <select name='{$name}' id='{$id}' class='{$class}' {$required} tabindex='{$tab_index}'>
438 438
             {$options_html}
439 439
         </select>";
440
-    }
441
-
442
-
443
-    /**
444
-     * @param string $class
445
-     * @param string $id
446
-     * @param string $name
447
-     * @param string $required
448
-     * @param int    $tab_index
449
-     * @param string $value
450
-     * @return string
451
-     * @since   4.10.14.p
452
-     */
453
-    private static function adminText($class, $id, $name, $required, $tab_index, $value)
454
-    {
455
-        $id        = esc_attr($id);
456
-        $name      = esc_attr($name);
457
-        $class     = esc_attr($class);
458
-        $tab_index = absint($tab_index);
459
-        $required  = filter_var($required, FILTER_VALIDATE_BOOLEAN) ? 'required' : '';
460
-        $class     = self::appendInputSizeClass($class, $value);
461
-        return "
440
+	}
441
+
442
+
443
+	/**
444
+	 * @param string $class
445
+	 * @param string $id
446
+	 * @param string $name
447
+	 * @param string $required
448
+	 * @param int    $tab_index
449
+	 * @param string $value
450
+	 * @return string
451
+	 * @since   4.10.14.p
452
+	 */
453
+	private static function adminText($class, $id, $name, $required, $tab_index, $value)
454
+	{
455
+		$id        = esc_attr($id);
456
+		$name      = esc_attr($name);
457
+		$class     = esc_attr($class);
458
+		$tab_index = absint($tab_index);
459
+		$required  = filter_var($required, FILTER_VALIDATE_BOOLEAN) ? 'required' : '';
460
+		$class     = self::appendInputSizeClass($class, $value);
461
+		return "
462 462
         <input name='{$name}' type='text' id='{$id}' class='{$class}' value='{$value}' {$required} tabindex='{$tab_index}'/>";
463
-    }
464
-
465
-
466
-    /**
467
-     * @param string $class
468
-     * @param int    $cols
469
-     * @param string $id
470
-     * @param string $name
471
-     * @param string $required
472
-     * @param int    $rows
473
-     * @param int    $tab_index
474
-     * @param string $value
475
-     * @return string
476
-     * @since   4.10.14.p
477
-     */
478
-    private static function adminTextarea($class, $cols, $id, $name, $required, $rows, $tab_index, $value)
479
-    {
480
-        $id        = esc_attr($id);
481
-        $name      = esc_attr($name);
482
-        $class     = esc_attr($class);
483
-        $cols      = absint($cols);
484
-        $rows      = absint($rows);
485
-        $value     = esc_textarea($value);
486
-        $tab_index = absint($tab_index);
487
-        $required  = filter_var($required, FILTER_VALIDATE_BOOLEAN) ? 'required' : '';
488
-        return "
463
+	}
464
+
465
+
466
+	/**
467
+	 * @param string $class
468
+	 * @param int    $cols
469
+	 * @param string $id
470
+	 * @param string $name
471
+	 * @param string $required
472
+	 * @param int    $rows
473
+	 * @param int    $tab_index
474
+	 * @param string $value
475
+	 * @return string
476
+	 * @since   4.10.14.p
477
+	 */
478
+	private static function adminTextarea($class, $cols, $id, $name, $required, $rows, $tab_index, $value)
479
+	{
480
+		$id        = esc_attr($id);
481
+		$name      = esc_attr($name);
482
+		$class     = esc_attr($class);
483
+		$cols      = absint($cols);
484
+		$rows      = absint($rows);
485
+		$value     = esc_textarea($value);
486
+		$tab_index = absint($tab_index);
487
+		$required  = filter_var($required, FILTER_VALIDATE_BOOLEAN) ? 'required' : '';
488
+		return "
489 489
         <textarea name='{$name}' id='{$id}' class='{$class}' rows='{$rows}' cols='{$cols}' {$required} tabindex='{$tab_index}'>{$value}</textarea>";
490
-    }
491
-
492
-
493
-    /**
494
-     * @param string $class
495
-     * @param string $id
496
-     * @param string $name
497
-     * @param int    $rows
498
-     * @param int    $tab_index
499
-     * @param string $value
500
-     * @param array  $wp_editor_args
501
-     * @return false|string
502
-     * @since   4.10.14.p
503
-     */
504
-    private static function adminWpEditor($class, $id, $name, $rows, $tab_index, $value, $wp_editor_args = [])
505
-    {
506
-        $editor_settings = $wp_editor_args + [
507
-                'textarea_name' => esc_attr($name),
508
-                'textarea_rows' => absint($rows),
509
-                'editor_class'  => esc_attr($class),
510
-                'tabindex'      => absint($tab_index),
511
-            ];
512
-        ob_start();
513
-        wp_editor($value, esc_attr($id), $editor_settings);
514
-        return ob_get_clean();
515
-    }
516
-
517
-
518
-    /**
519
-     * espresso admin page select_input
520
-     * Turns an array into a select fields
521
-     *
522
-     * @static
523
-     * @access public
524
-     * @param string  $name       field name
525
-     * @param array   $values     option values, numbered array starting at 0, where each value is an array with a key
526
-     *                            'text' (meaning text to display' and 'id' (meaning the internal value) eg:
527
-     *                            array(1=>array('text'=>'Monday','id'=>1),2=>array('text'=>'Tuesday','id'=>2)...). or
528
-     *                            as an array of key-value pairs, where the key is to be used for the select input's
529
-     *                            name, and the value will be the text shown to the user.  Optionally you can also
530
-     *                            include an additional key of "class" which will add a specific class to the option
531
-     *                            for that value.
532
-     * @param string  $default    default value
533
-     * @param string  $parameters extra parameters
534
-     * @param string  $class      css class
535
-     * @param boolean $autosize   whether to autosize the select or not
536
-     * @return string              html string for the select input
537
-     */
538
-    public static function select_input(
539
-        $name,
540
-        $values,
541
-        $default = '',
542
-        $parameters = '',
543
-        $class = '',
544
-        $autosize = true
545
-    ) {
546
-        // if $values was submitted in the wrong format, convert it over
547
-        if (! empty($values) && (! array_key_exists(0, $values) || ! is_array($values[0]))) {
548
-            $converted_values = [];
549
-            foreach ($values as $id => $text) {
550
-                $converted_values[] = ['id' => $id, 'text' => $text];
551
-            }
552
-            $values = $converted_values;
553
-        }
554
-
555
-        $field =
556
-            '<select id="' . EEH_Formatter::ee_tep_output_string($name)
557
-            . '" name="' . EEH_Formatter::ee_tep_output_string($name)
558
-            . '"';
559
-
560
-        if (EEH_Formatter::ee_tep_not_null($parameters)) {
561
-            $field .= ' ' . $parameters;
562
-        }
563
-        $class = $autosize ? self::appendInputSizeClass($class, $values) : '';
564
-
565
-        $field .= ' class="' . $class . '">';
566
-
567
-        if (empty($default) && isset($GLOBALS[ $name ])) {
568
-            $default = stripslashes($GLOBALS[ $name ]);
569
-        }
570
-
571
-        $field .= self::selectInputOption($values, $default);
572
-        $field .= '</select>';
573
-
574
-        return $field;
575
-    }
576
-
577
-
578
-    private static function selectInputOption(array $values, $default): string
579
-    {
580
-        if (isset($values['id'], $values['text'])) {
581
-            $id = is_scalar($values['id']) ? $values['id'] : '';
582
-            $text = is_scalar($values['text']) ? $values['text'] : '';
583
-            $selected = $default == $values['id'] ? ' selected = "selected"' : '';
584
-            $html_class = isset($values['class']) ? ' class="' . $values['class'] . '"' : '';
585
-            return "<option value='{$id}'{$selected}{$html_class}>{$text}</option>";
586
-        }
587
-        $options = '';
588
-        foreach ($values as $value) {
589
-            $options .= self::selectInputOption($value, $default);
590
-        }
591
-        return $options;
592
-    }
593
-
594
-
595
-    /**
596
-     * @param mixed $value
597
-     * @return int
598
-     * @since   $VID:$
599
-     */
600
-    private static function getInputValueLength($value): int
601
-    {
602
-        if ($value instanceof EE_Question_Option) {
603
-            return self::getInputValueLength($value->desc());
604
-        }
605
-        if (is_array($value)) {
606
-            $chars = 0;
607
-            foreach ($value as $val) {
608
-                $length = self::getInputValueLength($val);
609
-                $chars = max($length, $chars);
610
-            }
611
-            return $chars;
612
-        }
613
-        // not a primitive? return something big
614
-        if (! is_scalar($value)) {
615
-            return 500;
616
-        }
617
-        return strlen((string) $value);
618
-    }
619
-
620
-
621
-    /**
622
-     * @param string $class
623
-     * @param mixed $value
624
-     * @return string
625
-     * @since   $VID:$
626
-     */
627
-    private static function appendInputSizeClass(string $class, $value): string
628
-    {
629
-        if (strpos($class, 'ee-input-width--') !== false) {
630
-            return $class;
631
-        }
632
-        $chars = self::getInputValueLength($value);
633
-        if ($chars && $chars < 5) {
634
-            return "{$class} ee-input-width--tiny";
635
-        }
636
-        if ($chars && $chars < 25) {
637
-            return "{$class} ee-input-width--small";
638
-        }
639
-        if ($chars && $chars > 100) {
640
-            return "{$class} ee-input-width--big";
641
-        }
642
-        return "{$class} ee-input-width--reg";
643
-    }
644
-
645
-
646
-    /**
647
-     * generate_question_groups_html
648
-     *
649
-     * @param array  $question_groups
650
-     * @param string $group_wrapper
651
-     * @return string HTML
652
-     * @throws EE_Error
653
-     * @throws ReflectionException
654
-     */
655
-    public static function generate_question_groups_html($question_groups = [], $group_wrapper = 'fieldset')
656
-    {
657
-
658
-        $html                            = '';
659
-        $before_question_group_questions =
660
-            apply_filters('FHEE__EEH_Form_Fields__generate_question_groups_html__before_question_group_questions', '');
661
-        $after_question_group_questions  =
662
-            apply_filters('FHEE__EEH_Form_Fields__generate_question_groups_html__after_question_group_questions', '');
663
-
664
-        if (! empty($question_groups)) {
665
-            // loop thru question groups
666
-            foreach ($question_groups as $QSG) {
667
-                // check that questions exist
668
-                if (! empty($QSG['QSG_questions'])) {
669
-                    // use fieldsets
670
-                    $html .= "\n\t"
671
-                             . '<'
672
-                             . $group_wrapper
673
-                             . ' class="espresso-question-group-wrap" id="'
674
-                             . $QSG['QSG_identifier']
675
-                             . '">';
676
-                    // group_name
677
-                    $html .= $QSG['QSG_show_group_name']
678
-                        ? "\n\t\t"
679
-                          . '<h5 class="espresso-question-group-title-h5 section-title">'
680
-                          . self::prep_answer($QSG['QSG_name'])
681
-                          . '</h5>'
682
-                        : '';
683
-                    // group_desc
684
-                    $html .= $QSG['QSG_show_group_desc'] && ! empty($QSG['QSG_desc'])
685
-                        ? '<div class="espresso-question-group-desc-pg">'
686
-                          . self::prep_answer($QSG['QSG_desc'])
687
-                          . '</div>'
688
-                        : '';
689
-
690
-                    $html .= $before_question_group_questions;
691
-                    // loop thru questions
692
-                    foreach ($QSG['QSG_questions'] as $question) {
693
-                        $QFI  = new EE_Question_Form_Input(
694
-                            $question['qst_obj'],
695
-                            $question['ans_obj'],
696
-                            $question
697
-                        );
698
-                        $html .= self::generate_form_input($QFI);
699
-                    }
700
-                    $html .= $after_question_group_questions;
701
-                    $html .= "\n\t" . '</' . $group_wrapper . '>';
702
-                }
703
-            }
704
-        }
705
-
706
-        return $html;
707
-    }
708
-
709
-
710
-    /**
711
-     * generate_question_groups_html
712
-     *
713
-     * @param array  $question_groups
714
-     * @param array  $q_meta
715
-     * @param bool   $from_admin
716
-     * @param string $group_wrapper
717
-     * @return string HTML
718
-     * @throws EE_Error
719
-     * @throws ReflectionException
720
-     */
721
-    public static function generate_question_groups_html2(
722
-        $question_groups = [],
723
-        $q_meta = [],
724
-        $from_admin = false,
725
-        $group_wrapper = 'fieldset'
726
-    ) {
727
-
728
-        $html                            = '';
729
-        $before_question_group_questions =
730
-            apply_filters('FHEE__EEH_Form_Fields__generate_question_groups_html__before_question_group_questions', '');
731
-        $after_question_group_questions  =
732
-            apply_filters('FHEE__EEH_Form_Fields__generate_question_groups_html__after_question_group_questions', '');
733
-
734
-        $default_q_meta = [
735
-            'att_nmbr'    => 1,
736
-            'ticket_id'   => '',
737
-            'input_name'  => '',
738
-            'input_id'    => '',
739
-            'input_class' => '',
740
-        ];
741
-        $q_meta         = array_merge($default_q_meta, $q_meta);
742
-
743
-        if (! empty($question_groups)) {
744
-            // loop thru question groups
745
-            foreach ($question_groups as $QSG) {
746
-                if ($QSG instanceof EE_Question_Group) {
747
-                    // check that questions exist
748
-
749
-                    $where = ['QST_deleted' => 0];
750
-                    if (! $from_admin) {
751
-                        $where['QST_admin_only'] = 0;
752
-                    }
753
-                    $questions =
754
-                        $QSG->questions([$where, 'order_by' => ['Question_Group_Question.QGQ_order' => 'ASC']]);
755
-                    if (! empty($questions)) {
756
-                        // use fieldsets
757
-                        $html .= "\n\t"
758
-                                 . '<' . $group_wrapper . ' class="espresso-question-group-wrap" '
759
-                                 . 'id="' . $QSG->get('QSG_identifier') . '">';
760
-                        // group_name
761
-                        if ($QSG->show_group_name()) {
762
-                            $html .= "\n\t\t"
763
-                                     . '<h5 class="espresso-question-group-title-h5 section-title">'
764
-                                     . $QSG->get_pretty('QSG_name')
765
-                                     . '</h5>';
766
-                        }
767
-                        // group_desc
768
-                        if ($QSG->show_group_desc()) {
769
-                            $html .= '<div class="espresso-question-group-desc-pg">'
770
-                                     . $QSG->get_pretty('QSG_desc')
771
-                                     . '</div>';
772
-                        }
773
-
774
-                        $html .= $before_question_group_questions;
775
-                        // loop thru questions
776
-                        foreach ($questions as $QST) {
777
-                            $qstn_id = $QST->is_system_question() ? $QST->system_ID() : $QST->ID();
778
-
779
-                            $answer = null;
780
-
781
-                            /** @var RequestInterface $request */
782
-                            $request      = LoaderFactory::getLoader()->getShared(RequestInterface::class);
783
-                            $request_qstn = $request->getRequestParam('qstn', [], 'string', true);
784
-                            if (! empty($request_qstn) && isset($q_meta['input_id']) && isset($q_meta['att_nmbr'])) {
785
-                                // check for answer in $request_qstn in case we are reprocessing a form after an error
786
-                                if (isset($request_qstn[ $q_meta['input_id'] ][ $qstn_id ])) {
787
-                                    $answer = is_array($request_qstn[ $q_meta['input_id'] ][ $qstn_id ])
788
-                                        ? $request_qstn[ $q_meta['input_id'] ][ $qstn_id ]
789
-                                        : sanitize_text_field($request_qstn[ $q_meta['input_id'] ][ $qstn_id ]);
790
-                                }
791
-                            } elseif (isset($q_meta['attendee']) && $q_meta['attendee']) {
792
-                                // attendee data from the session
793
-                                $answer =
794
-                                    isset($q_meta['attendee'][ $qstn_id ]) ? $q_meta['attendee'][ $qstn_id ] : null;
795
-                            }
796
-
797
-
798
-                            $QFI  = new EE_Question_Form_Input(
799
-                                $QST,
800
-                                EE_Answer::new_instance(
801
-                                    [
802
-                                        'ANS_ID'    => 0,
803
-                                        'QST_ID'    => 0,
804
-                                        'REG_ID'    => 0,
805
-                                        'ANS_value' => $answer,
806
-                                    ]
807
-                                ),
808
-                                $q_meta
809
-                            );
810
-                            $html .= self::generate_form_input($QFI);
811
-                        }
812
-                        $html .= $after_question_group_questions;
813
-                        $html .= "\n\t" . '</' . $group_wrapper . '>';
814
-                    }
815
-                }
816
-            }
817
-        }
818
-        return $html;
819
-    }
820
-
821
-
822
-    /**
823
-     * generate_form_input
824
-     *
825
-     * @param EE_Question_Form_Input $QFI
826
-     * @return string HTML
827
-     * @throws EE_Error
828
-     * @throws ReflectionException
829
-     */
830
-    public static function generate_form_input(EE_Question_Form_Input $QFI)
831
-    {
832
-        if (isset($QFI->QST_admin_only) && $QFI->QST_admin_only && ! is_admin()) {
833
-            return '';
834
-        }
835
-        /** @var RequestInterface $request */
836
-        $request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
837
-
838
-        $QFI = self::_load_system_dropdowns($QFI);
839
-        $QFI = self::_load_specialized_dropdowns($QFI);
840
-
841
-        // we also need to verify
842
-
843
-        $display_text = $QFI->get('QST_display_text');
844
-        $input_name   = $QFI->get('QST_input_name');
845
-        $answer       = $request->getRequestParam($input_name, $QFI->get('ANS_value'));
846
-        $input_id     = $QFI->get('QST_input_id');
847
-        $input_class  = $QFI->get('QST_input_class');
848
-        //      $disabled = $QFI->get('QST_disabled') ? ' disabled="disabled"' : '';
849
-        $disabled          = $QFI->get('QST_disabled');
850
-        $required_label    = apply_filters(' FHEE__EEH_Form_Fields__generate_form_input__required_label', '<em>*</em>');
851
-        $QST_required      = $QFI->get('QST_required');
852
-        $required          =
853
-            $QST_required
854
-                ? ['label' => $required_label, 'class' => 'required needs-value', 'title' => $QST_required]
855
-                : [];
856
-        $use_html_entities = $QFI->get_meta('htmlentities');
857
-        $required_text     =
858
-            $QFI->get('QST_required_text') != ''
859
-                ? $QFI->get('QST_required_text')
860
-                : esc_html__('This field is required', 'event_espresso');
861
-        $required_text     = $QST_required
862
-            ? "\n\t\t\t"
863
-              . '<div class="required-text hidden">'
864
-              . self::prep_answer($required_text, $use_html_entities)
865
-              . '</div>'
866
-            : '';
867
-        $label_class       = $QFI->get('label_class');
868
-        $label_class       = $label_class ? "{$label_class} espresso-form-input-lbl" : 'espresso-form-input-lbl';
869
-        $QST_options       = $QFI->options(true, $answer);
870
-        $options           = is_array($QST_options) ? self::prep_answer_options($QST_options) : [];
871
-        $system_ID         = $QFI->get('QST_system');
872
-        $label_b4          = $QFI->get_meta('label_b4');
873
-        $use_desc_4_label  = $QFI->get_meta('use_desc_4_label');
874
-        $add_mobile_label  = $QFI->get_meta('add_mobile_label');
875
-
876
-
877
-        switch ($QFI->get('QST_type')) {
878
-            case 'TEXTAREA':
879
-                return EEH_Form_Fields::textarea(
880
-                    $display_text,
881
-                    $answer,
882
-                    $input_name,
883
-                    $input_id,
884
-                    $input_class,
885
-                    [],
886
-                    $required,
887
-                    $required_text,
888
-                    $label_class,
889
-                    $disabled,
890
-                    $system_ID,
891
-                    $use_html_entities,
892
-                    $add_mobile_label
893
-                );
894
-
895
-            case 'DROPDOWN':
896
-                return EEH_Form_Fields::select(
897
-                    $display_text,
898
-                    $answer,
899
-                    $options,
900
-                    $input_name,
901
-                    $input_id,
902
-                    $input_class,
903
-                    $required,
904
-                    $required_text,
905
-                    $label_class,
906
-                    $disabled,
907
-                    $system_ID,
908
-                    $use_html_entities,
909
-                    true,
910
-                    $add_mobile_label
911
-                );
912
-
913
-
914
-            case 'RADIO_BTN':
915
-                return EEH_Form_Fields::radio(
916
-                    $display_text,
917
-                    $answer,
918
-                    $options,
919
-                    $input_name,
920
-                    $input_id,
921
-                    $input_class,
922
-                    $required,
923
-                    $required_text,
924
-                    $label_class,
925
-                    $disabled,
926
-                    $system_ID,
927
-                    $use_html_entities,
928
-                    $label_b4,
929
-                    $use_desc_4_label,
930
-                    $add_mobile_label
931
-                );
932
-
933
-            case 'CHECKBOX':
934
-                return EEH_Form_Fields::checkbox(
935
-                    $display_text,
936
-                    $answer,
937
-                    $options,
938
-                    $input_name,
939
-                    $input_id,
940
-                    $input_class,
941
-                    $required,
942
-                    $required_text,
943
-                    $label_class,
944
-                    $disabled,
945
-                    $label_b4,
946
-                    $system_ID,
947
-                    $use_html_entities,
948
-                    $add_mobile_label
949
-                );
950
-
951
-            case 'DATE':
952
-                return EEH_Form_Fields::datepicker(
953
-                    $display_text,
954
-                    $answer,
955
-                    $input_name,
956
-                    $input_id,
957
-                    $input_class,
958
-                    $required,
959
-                    $required_text,
960
-                    $label_class,
961
-                    $disabled,
962
-                    $system_ID,
963
-                    $use_html_entities,
964
-                    $add_mobile_label
965
-                );
966
-
967
-            case 'TEXT':
968
-            default:
969
-                return EEH_Form_Fields::text(
970
-                    $display_text,
971
-                    $answer,
972
-                    $input_name,
973
-                    $input_id,
974
-                    $input_class,
975
-                    $required,
976
-                    $required_text,
977
-                    $label_class,
978
-                    $disabled,
979
-                    $system_ID,
980
-                    $use_html_entities,
981
-                    $add_mobile_label
982
-                );
983
-        }
984
-    }
985
-
986
-
987
-    public static function label(
988
-        string $question,
989
-        string $required_text = '',
990
-        string $required_label = '',
991
-        string $name = '',
992
-        string $label_class = '',
993
-        bool $filter = true
994
-    ): string {
995
-        $for   = ! empty($name) ? " for='{$name}'" : '';
996
-        $class = ! empty($label_class) ? " class='{$label_class}'" : '';
997
-        $label = self::prep_question($question) . $required_label;
998
-        $label_html = "
490
+	}
491
+
492
+
493
+	/**
494
+	 * @param string $class
495
+	 * @param string $id
496
+	 * @param string $name
497
+	 * @param int    $rows
498
+	 * @param int    $tab_index
499
+	 * @param string $value
500
+	 * @param array  $wp_editor_args
501
+	 * @return false|string
502
+	 * @since   4.10.14.p
503
+	 */
504
+	private static function adminWpEditor($class, $id, $name, $rows, $tab_index, $value, $wp_editor_args = [])
505
+	{
506
+		$editor_settings = $wp_editor_args + [
507
+				'textarea_name' => esc_attr($name),
508
+				'textarea_rows' => absint($rows),
509
+				'editor_class'  => esc_attr($class),
510
+				'tabindex'      => absint($tab_index),
511
+			];
512
+		ob_start();
513
+		wp_editor($value, esc_attr($id), $editor_settings);
514
+		return ob_get_clean();
515
+	}
516
+
517
+
518
+	/**
519
+	 * espresso admin page select_input
520
+	 * Turns an array into a select fields
521
+	 *
522
+	 * @static
523
+	 * @access public
524
+	 * @param string  $name       field name
525
+	 * @param array   $values     option values, numbered array starting at 0, where each value is an array with a key
526
+	 *                            'text' (meaning text to display' and 'id' (meaning the internal value) eg:
527
+	 *                            array(1=>array('text'=>'Monday','id'=>1),2=>array('text'=>'Tuesday','id'=>2)...). or
528
+	 *                            as an array of key-value pairs, where the key is to be used for the select input's
529
+	 *                            name, and the value will be the text shown to the user.  Optionally you can also
530
+	 *                            include an additional key of "class" which will add a specific class to the option
531
+	 *                            for that value.
532
+	 * @param string  $default    default value
533
+	 * @param string  $parameters extra parameters
534
+	 * @param string  $class      css class
535
+	 * @param boolean $autosize   whether to autosize the select or not
536
+	 * @return string              html string for the select input
537
+	 */
538
+	public static function select_input(
539
+		$name,
540
+		$values,
541
+		$default = '',
542
+		$parameters = '',
543
+		$class = '',
544
+		$autosize = true
545
+	) {
546
+		// if $values was submitted in the wrong format, convert it over
547
+		if (! empty($values) && (! array_key_exists(0, $values) || ! is_array($values[0]))) {
548
+			$converted_values = [];
549
+			foreach ($values as $id => $text) {
550
+				$converted_values[] = ['id' => $id, 'text' => $text];
551
+			}
552
+			$values = $converted_values;
553
+		}
554
+
555
+		$field =
556
+			'<select id="' . EEH_Formatter::ee_tep_output_string($name)
557
+			. '" name="' . EEH_Formatter::ee_tep_output_string($name)
558
+			. '"';
559
+
560
+		if (EEH_Formatter::ee_tep_not_null($parameters)) {
561
+			$field .= ' ' . $parameters;
562
+		}
563
+		$class = $autosize ? self::appendInputSizeClass($class, $values) : '';
564
+
565
+		$field .= ' class="' . $class . '">';
566
+
567
+		if (empty($default) && isset($GLOBALS[ $name ])) {
568
+			$default = stripslashes($GLOBALS[ $name ]);
569
+		}
570
+
571
+		$field .= self::selectInputOption($values, $default);
572
+		$field .= '</select>';
573
+
574
+		return $field;
575
+	}
576
+
577
+
578
+	private static function selectInputOption(array $values, $default): string
579
+	{
580
+		if (isset($values['id'], $values['text'])) {
581
+			$id = is_scalar($values['id']) ? $values['id'] : '';
582
+			$text = is_scalar($values['text']) ? $values['text'] : '';
583
+			$selected = $default == $values['id'] ? ' selected = "selected"' : '';
584
+			$html_class = isset($values['class']) ? ' class="' . $values['class'] . '"' : '';
585
+			return "<option value='{$id}'{$selected}{$html_class}>{$text}</option>";
586
+		}
587
+		$options = '';
588
+		foreach ($values as $value) {
589
+			$options .= self::selectInputOption($value, $default);
590
+		}
591
+		return $options;
592
+	}
593
+
594
+
595
+	/**
596
+	 * @param mixed $value
597
+	 * @return int
598
+	 * @since   $VID:$
599
+	 */
600
+	private static function getInputValueLength($value): int
601
+	{
602
+		if ($value instanceof EE_Question_Option) {
603
+			return self::getInputValueLength($value->desc());
604
+		}
605
+		if (is_array($value)) {
606
+			$chars = 0;
607
+			foreach ($value as $val) {
608
+				$length = self::getInputValueLength($val);
609
+				$chars = max($length, $chars);
610
+			}
611
+			return $chars;
612
+		}
613
+		// not a primitive? return something big
614
+		if (! is_scalar($value)) {
615
+			return 500;
616
+		}
617
+		return strlen((string) $value);
618
+	}
619
+
620
+
621
+	/**
622
+	 * @param string $class
623
+	 * @param mixed $value
624
+	 * @return string
625
+	 * @since   $VID:$
626
+	 */
627
+	private static function appendInputSizeClass(string $class, $value): string
628
+	{
629
+		if (strpos($class, 'ee-input-width--') !== false) {
630
+			return $class;
631
+		}
632
+		$chars = self::getInputValueLength($value);
633
+		if ($chars && $chars < 5) {
634
+			return "{$class} ee-input-width--tiny";
635
+		}
636
+		if ($chars && $chars < 25) {
637
+			return "{$class} ee-input-width--small";
638
+		}
639
+		if ($chars && $chars > 100) {
640
+			return "{$class} ee-input-width--big";
641
+		}
642
+		return "{$class} ee-input-width--reg";
643
+	}
644
+
645
+
646
+	/**
647
+	 * generate_question_groups_html
648
+	 *
649
+	 * @param array  $question_groups
650
+	 * @param string $group_wrapper
651
+	 * @return string HTML
652
+	 * @throws EE_Error
653
+	 * @throws ReflectionException
654
+	 */
655
+	public static function generate_question_groups_html($question_groups = [], $group_wrapper = 'fieldset')
656
+	{
657
+
658
+		$html                            = '';
659
+		$before_question_group_questions =
660
+			apply_filters('FHEE__EEH_Form_Fields__generate_question_groups_html__before_question_group_questions', '');
661
+		$after_question_group_questions  =
662
+			apply_filters('FHEE__EEH_Form_Fields__generate_question_groups_html__after_question_group_questions', '');
663
+
664
+		if (! empty($question_groups)) {
665
+			// loop thru question groups
666
+			foreach ($question_groups as $QSG) {
667
+				// check that questions exist
668
+				if (! empty($QSG['QSG_questions'])) {
669
+					// use fieldsets
670
+					$html .= "\n\t"
671
+							 . '<'
672
+							 . $group_wrapper
673
+							 . ' class="espresso-question-group-wrap" id="'
674
+							 . $QSG['QSG_identifier']
675
+							 . '">';
676
+					// group_name
677
+					$html .= $QSG['QSG_show_group_name']
678
+						? "\n\t\t"
679
+						  . '<h5 class="espresso-question-group-title-h5 section-title">'
680
+						  . self::prep_answer($QSG['QSG_name'])
681
+						  . '</h5>'
682
+						: '';
683
+					// group_desc
684
+					$html .= $QSG['QSG_show_group_desc'] && ! empty($QSG['QSG_desc'])
685
+						? '<div class="espresso-question-group-desc-pg">'
686
+						  . self::prep_answer($QSG['QSG_desc'])
687
+						  . '</div>'
688
+						: '';
689
+
690
+					$html .= $before_question_group_questions;
691
+					// loop thru questions
692
+					foreach ($QSG['QSG_questions'] as $question) {
693
+						$QFI  = new EE_Question_Form_Input(
694
+							$question['qst_obj'],
695
+							$question['ans_obj'],
696
+							$question
697
+						);
698
+						$html .= self::generate_form_input($QFI);
699
+					}
700
+					$html .= $after_question_group_questions;
701
+					$html .= "\n\t" . '</' . $group_wrapper . '>';
702
+				}
703
+			}
704
+		}
705
+
706
+		return $html;
707
+	}
708
+
709
+
710
+	/**
711
+	 * generate_question_groups_html
712
+	 *
713
+	 * @param array  $question_groups
714
+	 * @param array  $q_meta
715
+	 * @param bool   $from_admin
716
+	 * @param string $group_wrapper
717
+	 * @return string HTML
718
+	 * @throws EE_Error
719
+	 * @throws ReflectionException
720
+	 */
721
+	public static function generate_question_groups_html2(
722
+		$question_groups = [],
723
+		$q_meta = [],
724
+		$from_admin = false,
725
+		$group_wrapper = 'fieldset'
726
+	) {
727
+
728
+		$html                            = '';
729
+		$before_question_group_questions =
730
+			apply_filters('FHEE__EEH_Form_Fields__generate_question_groups_html__before_question_group_questions', '');
731
+		$after_question_group_questions  =
732
+			apply_filters('FHEE__EEH_Form_Fields__generate_question_groups_html__after_question_group_questions', '');
733
+
734
+		$default_q_meta = [
735
+			'att_nmbr'    => 1,
736
+			'ticket_id'   => '',
737
+			'input_name'  => '',
738
+			'input_id'    => '',
739
+			'input_class' => '',
740
+		];
741
+		$q_meta         = array_merge($default_q_meta, $q_meta);
742
+
743
+		if (! empty($question_groups)) {
744
+			// loop thru question groups
745
+			foreach ($question_groups as $QSG) {
746
+				if ($QSG instanceof EE_Question_Group) {
747
+					// check that questions exist
748
+
749
+					$where = ['QST_deleted' => 0];
750
+					if (! $from_admin) {
751
+						$where['QST_admin_only'] = 0;
752
+					}
753
+					$questions =
754
+						$QSG->questions([$where, 'order_by' => ['Question_Group_Question.QGQ_order' => 'ASC']]);
755
+					if (! empty($questions)) {
756
+						// use fieldsets
757
+						$html .= "\n\t"
758
+								 . '<' . $group_wrapper . ' class="espresso-question-group-wrap" '
759
+								 . 'id="' . $QSG->get('QSG_identifier') . '">';
760
+						// group_name
761
+						if ($QSG->show_group_name()) {
762
+							$html .= "\n\t\t"
763
+									 . '<h5 class="espresso-question-group-title-h5 section-title">'
764
+									 . $QSG->get_pretty('QSG_name')
765
+									 . '</h5>';
766
+						}
767
+						// group_desc
768
+						if ($QSG->show_group_desc()) {
769
+							$html .= '<div class="espresso-question-group-desc-pg">'
770
+									 . $QSG->get_pretty('QSG_desc')
771
+									 . '</div>';
772
+						}
773
+
774
+						$html .= $before_question_group_questions;
775
+						// loop thru questions
776
+						foreach ($questions as $QST) {
777
+							$qstn_id = $QST->is_system_question() ? $QST->system_ID() : $QST->ID();
778
+
779
+							$answer = null;
780
+
781
+							/** @var RequestInterface $request */
782
+							$request      = LoaderFactory::getLoader()->getShared(RequestInterface::class);
783
+							$request_qstn = $request->getRequestParam('qstn', [], 'string', true);
784
+							if (! empty($request_qstn) && isset($q_meta['input_id']) && isset($q_meta['att_nmbr'])) {
785
+								// check for answer in $request_qstn in case we are reprocessing a form after an error
786
+								if (isset($request_qstn[ $q_meta['input_id'] ][ $qstn_id ])) {
787
+									$answer = is_array($request_qstn[ $q_meta['input_id'] ][ $qstn_id ])
788
+										? $request_qstn[ $q_meta['input_id'] ][ $qstn_id ]
789
+										: sanitize_text_field($request_qstn[ $q_meta['input_id'] ][ $qstn_id ]);
790
+								}
791
+							} elseif (isset($q_meta['attendee']) && $q_meta['attendee']) {
792
+								// attendee data from the session
793
+								$answer =
794
+									isset($q_meta['attendee'][ $qstn_id ]) ? $q_meta['attendee'][ $qstn_id ] : null;
795
+							}
796
+
797
+
798
+							$QFI  = new EE_Question_Form_Input(
799
+								$QST,
800
+								EE_Answer::new_instance(
801
+									[
802
+										'ANS_ID'    => 0,
803
+										'QST_ID'    => 0,
804
+										'REG_ID'    => 0,
805
+										'ANS_value' => $answer,
806
+									]
807
+								),
808
+								$q_meta
809
+							);
810
+							$html .= self::generate_form_input($QFI);
811
+						}
812
+						$html .= $after_question_group_questions;
813
+						$html .= "\n\t" . '</' . $group_wrapper . '>';
814
+					}
815
+				}
816
+			}
817
+		}
818
+		return $html;
819
+	}
820
+
821
+
822
+	/**
823
+	 * generate_form_input
824
+	 *
825
+	 * @param EE_Question_Form_Input $QFI
826
+	 * @return string HTML
827
+	 * @throws EE_Error
828
+	 * @throws ReflectionException
829
+	 */
830
+	public static function generate_form_input(EE_Question_Form_Input $QFI)
831
+	{
832
+		if (isset($QFI->QST_admin_only) && $QFI->QST_admin_only && ! is_admin()) {
833
+			return '';
834
+		}
835
+		/** @var RequestInterface $request */
836
+		$request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
837
+
838
+		$QFI = self::_load_system_dropdowns($QFI);
839
+		$QFI = self::_load_specialized_dropdowns($QFI);
840
+
841
+		// we also need to verify
842
+
843
+		$display_text = $QFI->get('QST_display_text');
844
+		$input_name   = $QFI->get('QST_input_name');
845
+		$answer       = $request->getRequestParam($input_name, $QFI->get('ANS_value'));
846
+		$input_id     = $QFI->get('QST_input_id');
847
+		$input_class  = $QFI->get('QST_input_class');
848
+		//      $disabled = $QFI->get('QST_disabled') ? ' disabled="disabled"' : '';
849
+		$disabled          = $QFI->get('QST_disabled');
850
+		$required_label    = apply_filters(' FHEE__EEH_Form_Fields__generate_form_input__required_label', '<em>*</em>');
851
+		$QST_required      = $QFI->get('QST_required');
852
+		$required          =
853
+			$QST_required
854
+				? ['label' => $required_label, 'class' => 'required needs-value', 'title' => $QST_required]
855
+				: [];
856
+		$use_html_entities = $QFI->get_meta('htmlentities');
857
+		$required_text     =
858
+			$QFI->get('QST_required_text') != ''
859
+				? $QFI->get('QST_required_text')
860
+				: esc_html__('This field is required', 'event_espresso');
861
+		$required_text     = $QST_required
862
+			? "\n\t\t\t"
863
+			  . '<div class="required-text hidden">'
864
+			  . self::prep_answer($required_text, $use_html_entities)
865
+			  . '</div>'
866
+			: '';
867
+		$label_class       = $QFI->get('label_class');
868
+		$label_class       = $label_class ? "{$label_class} espresso-form-input-lbl" : 'espresso-form-input-lbl';
869
+		$QST_options       = $QFI->options(true, $answer);
870
+		$options           = is_array($QST_options) ? self::prep_answer_options($QST_options) : [];
871
+		$system_ID         = $QFI->get('QST_system');
872
+		$label_b4          = $QFI->get_meta('label_b4');
873
+		$use_desc_4_label  = $QFI->get_meta('use_desc_4_label');
874
+		$add_mobile_label  = $QFI->get_meta('add_mobile_label');
875
+
876
+
877
+		switch ($QFI->get('QST_type')) {
878
+			case 'TEXTAREA':
879
+				return EEH_Form_Fields::textarea(
880
+					$display_text,
881
+					$answer,
882
+					$input_name,
883
+					$input_id,
884
+					$input_class,
885
+					[],
886
+					$required,
887
+					$required_text,
888
+					$label_class,
889
+					$disabled,
890
+					$system_ID,
891
+					$use_html_entities,
892
+					$add_mobile_label
893
+				);
894
+
895
+			case 'DROPDOWN':
896
+				return EEH_Form_Fields::select(
897
+					$display_text,
898
+					$answer,
899
+					$options,
900
+					$input_name,
901
+					$input_id,
902
+					$input_class,
903
+					$required,
904
+					$required_text,
905
+					$label_class,
906
+					$disabled,
907
+					$system_ID,
908
+					$use_html_entities,
909
+					true,
910
+					$add_mobile_label
911
+				);
912
+
913
+
914
+			case 'RADIO_BTN':
915
+				return EEH_Form_Fields::radio(
916
+					$display_text,
917
+					$answer,
918
+					$options,
919
+					$input_name,
920
+					$input_id,
921
+					$input_class,
922
+					$required,
923
+					$required_text,
924
+					$label_class,
925
+					$disabled,
926
+					$system_ID,
927
+					$use_html_entities,
928
+					$label_b4,
929
+					$use_desc_4_label,
930
+					$add_mobile_label
931
+				);
932
+
933
+			case 'CHECKBOX':
934
+				return EEH_Form_Fields::checkbox(
935
+					$display_text,
936
+					$answer,
937
+					$options,
938
+					$input_name,
939
+					$input_id,
940
+					$input_class,
941
+					$required,
942
+					$required_text,
943
+					$label_class,
944
+					$disabled,
945
+					$label_b4,
946
+					$system_ID,
947
+					$use_html_entities,
948
+					$add_mobile_label
949
+				);
950
+
951
+			case 'DATE':
952
+				return EEH_Form_Fields::datepicker(
953
+					$display_text,
954
+					$answer,
955
+					$input_name,
956
+					$input_id,
957
+					$input_class,
958
+					$required,
959
+					$required_text,
960
+					$label_class,
961
+					$disabled,
962
+					$system_ID,
963
+					$use_html_entities,
964
+					$add_mobile_label
965
+				);
966
+
967
+			case 'TEXT':
968
+			default:
969
+				return EEH_Form_Fields::text(
970
+					$display_text,
971
+					$answer,
972
+					$input_name,
973
+					$input_id,
974
+					$input_class,
975
+					$required,
976
+					$required_text,
977
+					$label_class,
978
+					$disabled,
979
+					$system_ID,
980
+					$use_html_entities,
981
+					$add_mobile_label
982
+				);
983
+		}
984
+	}
985
+
986
+
987
+	public static function label(
988
+		string $question,
989
+		string $required_text = '',
990
+		string $required_label = '',
991
+		string $name = '',
992
+		string $label_class = '',
993
+		bool $filter = true
994
+	): string {
995
+		$for   = ! empty($name) ? " for='{$name}'" : '';
996
+		$class = ! empty($label_class) ? " class='{$label_class}'" : '';
997
+		$label = self::prep_question($question) . $required_label;
998
+		$label_html = "
999 999
             {$required_text}
1000 1000
             <label{$for}{$class}>{$label}</label>";
1001
-        // filter label but ensure required text comes before it
1002
-        return $filter
1003
-            ? apply_filters('FHEE__EEH_Form_Fields__label_html', $label_html, $required_text)
1004
-            : $label_html;
1005
-    }
1006
-
1007
-
1008
-
1009
-    public static function mobileLabel(
1010
-        bool $add_mobile_label,
1011
-        string $question,
1012
-        string $required_text = '',
1013
-        string $required_label = '',
1014
-        string $label_class = '',
1015
-        string $name = ''
1016
-    ): string {
1017
-        return $add_mobile_label
1018
-            ? self::label($question, $required_text, $required_label, $name, $label_class, false)
1019
-            : '';
1020
-    }
1021
-
1022
-
1023
-    /**
1024
-     * generates HTML for a form text input
1025
-     *
1026
-     * @param string $question    label content
1027
-     * @param string $answer      form input value attribute
1028
-     * @param string $name        form input name attribute
1029
-     * @param string $id          form input css id attribute
1030
-     * @param string $class       form input css class attribute
1031
-     * @param array  $required    'label', 'class', and 'msg' - array of values for required "label" content, css
1032
-     *                            required 'class', and required 'msg' attribute
1033
-     * @param string $label_class css class attribute for the label
1034
-     * @param string $disabled    disabled="disabled" or null
1035
-     * @return string HTML
1036
-     */
1037
-    public static function text(
1038
-        $question = false,
1039
-        $answer = null,
1040
-        $name = false,
1041
-        $id = '',
1042
-        $class = '',
1043
-        $required = false,
1044
-        $required_text = '',
1045
-        $label_class = '',
1046
-        $disabled = false,
1047
-        $system_ID = false,
1048
-        $use_html_entities = true,
1049
-        $add_mobile_label = false,
1050
-        $extra_attributes = ''
1051
-    ) {
1052
-        // need these
1053
-        if (! $question || ! $name) {
1054
-            return null;
1055
-        }
1056
-        // prep the answer
1057
-        $answer = is_array($answer) ? '' : self::prep_answer($answer, $use_html_entities);
1058
-        // prep the required array
1059
-        $required = self::prep_required($required);
1060
-        // set disabled tag
1061
-        $disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1062
-        // ya gots ta have style man!!!
1063
-        $txt_class = is_admin() ? 'regular-text' : 'espresso-text-inp';
1064
-        $class     = empty($class) ? $txt_class : $class;
1065
-        $class     .= ! empty($system_ID) ? ' ' . $system_ID : '';
1066
-        $class = self::appendInputSizeClass($class, $answer);
1067
-        $class .= ! empty($required['class']) ? ' ' . $required['class'] : '';
1068
-        $extra_attributes = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', $extra_attributes);
1069
-
1070
-        $label_html = self::label($question, $required_text, $required['label'], $name, $label_class);
1071
-        $mobile_label = self::mobileLabel(
1072
-            $add_mobile_label,
1073
-            $question,
1074
-            $required_text,
1075
-            $required['label'],
1076
-            $label_class,
1077
-            $name
1078
-        );
1079
-
1080
-        $input_html = $mobile_label . '
1001
+		// filter label but ensure required text comes before it
1002
+		return $filter
1003
+			? apply_filters('FHEE__EEH_Form_Fields__label_html', $label_html, $required_text)
1004
+			: $label_html;
1005
+	}
1006
+
1007
+
1008
+
1009
+	public static function mobileLabel(
1010
+		bool $add_mobile_label,
1011
+		string $question,
1012
+		string $required_text = '',
1013
+		string $required_label = '',
1014
+		string $label_class = '',
1015
+		string $name = ''
1016
+	): string {
1017
+		return $add_mobile_label
1018
+			? self::label($question, $required_text, $required_label, $name, $label_class, false)
1019
+			: '';
1020
+	}
1021
+
1022
+
1023
+	/**
1024
+	 * generates HTML for a form text input
1025
+	 *
1026
+	 * @param string $question    label content
1027
+	 * @param string $answer      form input value attribute
1028
+	 * @param string $name        form input name attribute
1029
+	 * @param string $id          form input css id attribute
1030
+	 * @param string $class       form input css class attribute
1031
+	 * @param array  $required    'label', 'class', and 'msg' - array of values for required "label" content, css
1032
+	 *                            required 'class', and required 'msg' attribute
1033
+	 * @param string $label_class css class attribute for the label
1034
+	 * @param string $disabled    disabled="disabled" or null
1035
+	 * @return string HTML
1036
+	 */
1037
+	public static function text(
1038
+		$question = false,
1039
+		$answer = null,
1040
+		$name = false,
1041
+		$id = '',
1042
+		$class = '',
1043
+		$required = false,
1044
+		$required_text = '',
1045
+		$label_class = '',
1046
+		$disabled = false,
1047
+		$system_ID = false,
1048
+		$use_html_entities = true,
1049
+		$add_mobile_label = false,
1050
+		$extra_attributes = ''
1051
+	) {
1052
+		// need these
1053
+		if (! $question || ! $name) {
1054
+			return null;
1055
+		}
1056
+		// prep the answer
1057
+		$answer = is_array($answer) ? '' : self::prep_answer($answer, $use_html_entities);
1058
+		// prep the required array
1059
+		$required = self::prep_required($required);
1060
+		// set disabled tag
1061
+		$disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1062
+		// ya gots ta have style man!!!
1063
+		$txt_class = is_admin() ? 'regular-text' : 'espresso-text-inp';
1064
+		$class     = empty($class) ? $txt_class : $class;
1065
+		$class     .= ! empty($system_ID) ? ' ' . $system_ID : '';
1066
+		$class = self::appendInputSizeClass($class, $answer);
1067
+		$class .= ! empty($required['class']) ? ' ' . $required['class'] : '';
1068
+		$extra_attributes = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', $extra_attributes);
1069
+
1070
+		$label_html = self::label($question, $required_text, $required['label'], $name, $label_class);
1071
+		$mobile_label = self::mobileLabel(
1072
+			$add_mobile_label,
1073
+			$question,
1074
+			$required_text,
1075
+			$required['label'],
1076
+			$label_class,
1077
+			$name
1078
+		);
1079
+
1080
+		$input_html = $mobile_label . '
1081 1081
             <input  type="text"
1082 1082
                     name="' . $name . '"
1083 1083
                     id="' . $id . '"
@@ -1087,1039 +1087,1039 @@  discard block
 block discarded – undo
1087 1087
                     ' . $disabled . ' ' . $extra_attributes . '
1088 1088
             />';
1089 1089
 
1090
-        $input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1091
-        return $label_html . $input_html;
1092
-    }
1093
-
1094
-
1095
-    /**
1096
-     * generates HTML for a form textarea
1097
-     *
1098
-     * @param string $question    label content
1099
-     * @param string $answer      form input value attribute
1100
-     * @param string $name        form input name attribute
1101
-     * @param string $id          form input css id attribute
1102
-     * @param string $class       form input css class attribute
1103
-     * @param array  $dimensions  array of form input rows and cols attributes : array( 'rows' => 3, 'cols' => 40 )
1104
-     * @param array  $required    'label', 'class', and 'msg' - array of values for required "label" content, css
1105
-     *                            required 'class', and required 'msg' attribute
1106
-     * @param string $label_class css class attribute for the label
1107
-     * @param string $disabled    disabled="disabled" or null
1108
-     * @return string HTML
1109
-     */
1110
-    public static function textarea(
1111
-        $question = false,
1112
-        $answer = null,
1113
-        $name = false,
1114
-        $id = '',
1115
-        $class = '',
1116
-        $dimensions = false,
1117
-        $required = false,
1118
-        $required_text = '',
1119
-        $label_class = '',
1120
-        $disabled = false,
1121
-        $system_ID = false,
1122
-        $use_html_entities = true,
1123
-        $add_mobile_label = false
1124
-    ) {
1125
-        // need these
1126
-        if (! $question || ! $name) {
1127
-            return null;
1128
-        }
1129
-        // prep the answer
1130
-        $answer = is_array($answer) ? '' : self::prep_answer($answer, $use_html_entities);
1131
-        // prep the required array
1132
-        $required = self::prep_required($required);
1133
-        // make sure $dimensions is an array
1134
-        $dimensions = is_array($dimensions) ? $dimensions : [];
1135
-        // and set some defaults
1136
-        $dimensions = array_merge(['rows' => 3, 'cols' => 40], $dimensions);
1137
-        // set disabled tag
1138
-        $disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1139
-        // ya gots ta have style man!!!
1140
-        $class     .= ! empty($system_ID) ? ' ' . $system_ID : '';
1141
-        $class     .= ! empty($required['class']) ? ' ' . $required['class'] : '';
1142
-        $extra     = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1143
-
1144
-        $label_html   = self::label($question, $required_text, $required['label'], $name, $label_class);
1145
-        $mobile_label = self::mobileLabel(
1146
-            $add_mobile_label,
1147
-            $question,
1148
-            $required_text,
1149
-            $required['label'],
1150
-            $label_class,
1151
-            $name
1152
-        );
1153
-
1154
-        $input_html = $mobile_label
1155
-            . '<textarea name="' . $name . '" id="' . $id . '" class="' . trim($class) . '" '
1156
-            . 'rows="' . $dimensions['rows'] . '" cols="' . $dimensions['cols'] . '"  '
1157
-            . 'aria-label="' . $required['msg'] . '" ' . $disabled . ' ' . $extra . '>'
1158
-             . esc_textarea($answer)
1159
-              . '</textarea>';
1160
-
1161
-        $input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1162
-        return $label_html . $input_html;
1163
-    }
1164
-
1165
-
1166
-    /**
1167
-     * generates HTML for a form select input
1168
-     *
1169
-     * @param string $question    label content
1170
-     * @param string $answer      form input value attribute
1171
-     * @param array  $options     array of answer options where array key = option value and array value = option
1172
-     *                            display text
1173
-     * @param string $name        form input name attribute
1174
-     * @param string $id          form input css id attribute
1175
-     * @param string $class       form input css class attribute
1176
-     * @param array  $required    'label', 'class', and 'msg' - array of values for required "label" content, css
1177
-     *                            required 'class', and required 'msg' attribute
1178
-     * @param string $label_class css class attribute for the label
1179
-     * @param string $disabled    disabled="disabled" or null
1180
-     * @return string HTML
1181
-     */
1182
-    public static function select(
1183
-        $question = false,
1184
-        $answer = null,
1185
-        $options = false,
1186
-        $name = false,
1187
-        $id = '',
1188
-        $class = '',
1189
-        $required = false,
1190
-        $required_text = '',
1191
-        $label_class = '',
1192
-        $disabled = false,
1193
-        $system_ID = false,
1194
-        $use_html_entities = true,
1195
-        $add_please_select_option = false,
1196
-        $add_mobile_label = false
1197
-    ) {
1198
-
1199
-        // need these
1200
-        if (! $question || ! $name || ! $options || empty($options) || ! is_array($options)) {
1201
-            return null;
1202
-        }
1203
-        // prep the answer
1204
-        $answer = is_array($answer)
1205
-            ? self::prep_answer(array_shift($answer), $use_html_entities)
1206
-            : self::prep_answer($answer, $use_html_entities);
1207
-        // prep the required array
1208
-        $required = self::prep_required($required);
1209
-        // set disabled tag
1210
-        $disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1211
-        // ya gots ta have style man!!!
1212
-        $class     .= ! empty($system_ID) ? ' ' . $system_ID : '';
1213
-        $class = self::appendInputSizeClass($class, $options);
1214
-        $extra     = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1215
-
1216
-        $label_html   = self::label($question, $required_text, $required['label'], $name, $label_class);
1217
-        $mobile_label = self::mobileLabel(
1218
-            $add_mobile_label,
1219
-            $question,
1220
-            $required_text,
1221
-            $required['label'],
1222
-            $label_class,
1223
-            $name
1224
-        );
1225
-
1226
-        $input_html = $mobile_label
1227
-            . '<select name="' . $name . '" id="' . $id . '" class="' . trim($class) . ' ' . $required['class'] . '" '
1228
-            . 'aria-label="' . esc_attr($required['msg']) . '"' . $disabled . ' ' . $extra . '>';
1229
-        // recursively count array elements, to determine total number of options
1230
-        $only_option = count($options, 1) == 1;
1231
-        if (! $only_option) {
1232
-            // if there is NO answer set and there are multiple options to choose from, then set the "please select" message as selected
1233
-            $selected   = $answer === null ? ' selected' : '';
1234
-            $input_html .= $add_please_select_option
1235
-                ? "\n\t\t\t\t"
1236
-                  . '<option value=""' . $selected . '>'
1237
-                  . esc_html__(' - please select - ', 'event_espresso')
1238
-                  . '</option>'
1239
-                : '';
1240
-        }
1241
-        foreach ($options as $key => $value) {
1242
-            // if value is an array, then create option groups, else create regular ol' options
1243
-            $input_html .= is_array($value)
1244
-                ? self::_generate_select_option_group(
1245
-                    $key,
1246
-                    $value,
1247
-                    $answer,
1248
-                    $use_html_entities
1249
-                )
1250
-                : self::_generate_select_option(
1251
-                    $value->value(),
1252
-                    $value->desc(),
1253
-                    $answer,
1254
-                    $only_option,
1255
-                    $use_html_entities
1256
-                );
1257
-        }
1258
-
1259
-        $input_html .= "\n\t\t\t" . '</select>';
1260
-
1261
-        $input_html =
1262
-            apply_filters(
1263
-                'FHEE__EEH_Form_Fields__select__before_end_wrapper',
1264
-                $input_html,
1265
-                $question,
1266
-                $answer,
1267
-                $name,
1268
-                $id,
1269
-                $class,
1270
-                $system_ID
1271
-            );
1272
-
1273
-        $input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1274
-        return $label_html . $input_html;
1275
-    }
1276
-
1277
-
1278
-    /**
1279
-     *  _generate_select_option_group
1280
-     *
1281
-     *  if  $value for a select box is an array, then the key will be used as the optgroup label
1282
-     *  and the value array will be looped thru and the elements sent to _generate_select_option
1283
-     *
1284
-     * @param mixed   $opt_group
1285
-     * @param mixed   $QSOs
1286
-     * @param mixed   $answer
1287
-     * @param boolean $use_html_entities
1288
-     * @return string
1289
-     */
1290
-    private static function _generate_select_option_group($opt_group, $QSOs, $answer, $use_html_entities = true)
1291
-    {
1292
-        $html = "\n\t\t\t\t" . '<optgroup label="' . self::prep_option_value($opt_group) . '">';
1293
-        foreach ($QSOs as $QSO) {
1294
-            $html .= self::_generate_select_option($QSO->value(), $QSO->desc(), $answer, false, $use_html_entities);
1295
-        }
1296
-        $html .= "\n\t\t\t\t" . '</optgroup>';
1297
-        return $html;
1298
-    }
1299
-
1300
-
1301
-    /**
1302
-     *  _generate_select_option
1303
-     *
1304
-     * @param mixed   $key
1305
-     * @param mixed   $value
1306
-     * @param mixed   $answer
1307
-     * @param int     $only_option
1308
-     * @param boolean $use_html_entities
1309
-     * @return string
1310
-     */
1311
-    private static function _generate_select_option(
1312
-        $key,
1313
-        $value,
1314
-        $answer,
1315
-        $only_option = false,
1316
-        $use_html_entities = true
1317
-    ) {
1318
-        $key      = self::prep_answer($key, $use_html_entities);
1319
-        $value    = self::prep_answer($value, $use_html_entities);
1320
-        $value    = ! empty($value) ? $value : $key;
1321
-        $selected = ($answer == $key || $only_option) ? 'selected' : '';
1322
-        return "\n\t\t\t\t"
1323
-               . '<option value="' . self::prep_option_value($key) . '" ' . $selected . '> '
1324
-               . $value
1325
-               . '&nbsp;&nbsp;&nbsp;</option>';
1326
-    }
1327
-
1328
-
1329
-    /**
1330
-     * generates HTML for form radio button inputs
1331
-     *
1332
-     * @param bool|string $question    label content
1333
-     * @param string      $answer      form input value attribute
1334
-     * @param array|bool  $options     array of answer options where array key = option value and array value = option
1335
-     *                                 display text
1336
-     * @param bool|string $name        form input name attribute
1337
-     * @param string      $id          form input css id attribute
1338
-     * @param string      $class       form input css class attribute
1339
-     * @param array|bool  $required    'label', 'class', and 'msg' - array of values for required "label" content, css
1340
-     *                                 required 'class', and required 'msg' attribute
1341
-     * @param string      $required_text
1342
-     * @param string      $label_class css class attribute for the label
1343
-     * @param bool|string $disabled    disabled="disabled" or null
1344
-     * @param bool        $system_ID
1345
-     * @param bool        $use_html_entities
1346
-     * @param bool        $label_b4
1347
-     * @param bool        $use_desc_4_label
1348
-     * @return string HTML
1349
-     */
1350
-    public static function radio(
1351
-        $question = false,
1352
-        $answer = null,
1353
-        $options = false,
1354
-        $name = false,
1355
-        $id = '',
1356
-        $class = '',
1357
-        $required = false,
1358
-        $required_text = '',
1359
-        $label_class = '',
1360
-        $disabled = false,
1361
-        $system_ID = false,
1362
-        $use_html_entities = true,
1363
-        $label_b4 = false,
1364
-        $use_desc_4_label = false,
1365
-        $add_mobile_label = false
1366
-    ) {
1367
-        // need these
1368
-        if (! $question || ! $name || ! $options || empty($options) || ! is_array($options)) {
1369
-            return null;
1370
-        }
1371
-        // prep the answer
1372
-        $answer = is_array($answer) ? '' : self::prep_answer($answer, $use_html_entities);
1373
-        // prep the required array
1374
-        $required = self::prep_required($required);
1375
-        // set disabled tag
1376
-        $disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1377
-        // ya gots ta have style man!!!
1378
-        $radio_class = is_admin() ? 'ee-admin-radio-lbl' : $label_class;
1379
-        $class       = ! empty($class) ? $class : 'espresso-radio-btn-inp';
1380
-        $extra       = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1381
-
1382
-        $label_html = self::label($question, $required_text, $required['label'], '', $label_class);
1383
-        $mobile_label = self::mobileLabel(
1384
-            $add_mobile_label,
1385
-            $question,
1386
-            $required_text,
1387
-            $required['label'],
1388
-            $label_class
1389
-        );
1390
-
1391
-        $input_html = $mobile_label
1392
-            . '<ul id="' . $id . '-ul" class="espresso-radio-btn-options-ul ' . $class . '-ul">';
1393
-
1394
-        $class .= ! empty($system_ID) ? ' ' . $system_ID : '';
1395
-        $class .= ! empty($required['class']) ? ' ' . $required['class'] : '';
1396
-
1397
-        foreach ($options as $OPT) {
1398
-            if ($OPT instanceof EE_Question_Option) {
1399
-                $value   = self::prep_option_value($OPT->value());
1400
-                $label   = $use_desc_4_label ? $OPT->desc() : $OPT->value();
1401
-                $size    = $use_desc_4_label
1402
-                    ? self::get_label_size_class($OPT->value() . ' ' . $OPT->desc())
1403
-                    : self::get_label_size_class($OPT->value());
1404
-                $desc    = $OPT->desc();// no self::prep_answer
1405
-                $answer  = is_numeric($value) && empty($answer) ? 0 : $answer;
1406
-                $checked = (string) $value == (string) $answer ? ' checked' : '';
1407
-                $opt     = '-' . sanitize_key($value);
1408
-
1409
-                $input_html .= "\n\t\t\t\t" . '<li' . $size . '>';
1410
-                $input_html .= "\n\t\t\t\t\t" . '<label class="' . $radio_class . ' espresso-radio-btn-lbl">';
1411
-                $input_html .= $label_b4 ? "\n\t\t\t\t\t\t" . '<span>' . $label . '</span>&nbsp;&nbsp;' : '';
1412
-                $input_html .= "\n\t\t\t\t\t\t"
1413
-                               . '<input type="radio" name="' . $name . '" id="' . $id . $opt . '" '
1414
-                               . 'class="' . $class . '" value="' . $value . '" '
1415
-                               . 'aria-label="' . esc_attr($required['msg']) . '" ' . $disabled
1416
-                               . $checked . ' ' . $extra . '/>';
1417
-                $input_html .= ! $label_b4
1418
-                    ? "\n\t\t\t\t\t\t"
1419
-                      . '&nbsp;&nbsp;<span class="espresso-radio-btn-desc">'
1420
-                      . $label
1421
-                      . '</span>'
1422
-                    : '';
1423
-                $input_html .= "\n\t\t\t\t\t" . '</label>';
1424
-                $input_html .= $use_desc_4_label
1425
-                    ? ''
1426
-                    : '<span class="espresso-radio-btn-option-desc small-text grey-text">' . $desc . '</span>';
1427
-                $input_html .= "\n\t\t\t\t" . '</li>';
1428
-            }
1429
-        }
1430
-
1431
-        $input_html .= "\n\t\t\t" . '</ul>';
1432
-
1433
-        $input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1434
-        return $label_html . $input_html;
1435
-    }
1436
-
1437
-
1438
-    /**
1439
-     * generates HTML for form checkbox inputs
1440
-     *
1441
-     * @param string $question    label content
1442
-     * @param string $answer      form input value attribute
1443
-     * @param array  $options     array of options where array key = option value and array value = option display text
1444
-     * @param string $name        form input name attribute
1445
-     * @param string $id          form input css id attribute
1446
-     * @param string $class       form input css class attribute
1447
-     * @param array  $required    'label', 'class', and 'msg' - array of values for required "label" content, css
1448
-     *                            required 'class', and required 'msg' attribute
1449
-     * @param string $label_class css class attribute for the label
1450
-     * @param string $disabled    disabled="disabled" or null
1451
-     * @return string HTML
1452
-     */
1453
-    public static function checkbox(
1454
-        $question = false,
1455
-        $answer = null,
1456
-        $options = false,
1457
-        $name = false,
1458
-        $id = '',
1459
-        $class = '',
1460
-        $required = false,
1461
-        $required_text = '',
1462
-        $label_class = '',
1463
-        $disabled = false,
1464
-        $label_b4 = false,
1465
-        $system_ID = false,
1466
-        $use_html_entities = true,
1467
-        $add_mobile_label = false
1468
-    ) {
1469
-        // need these
1470
-        if (! $question || ! $name || ! $options || empty($options) || ! is_array($options)) {
1471
-            return null;
1472
-        }
1473
-        $answer = maybe_unserialize($answer);
1474
-
1475
-        // prep the answer(s)
1476
-        $answer = is_array($answer) ? $answer : [sanitize_key($answer) => $answer];
1477
-
1478
-        foreach ($answer as $key => $value) {
1479
-            $key            = self::prep_option_value($key);
1480
-            $answer[ $key ] = self::prep_answer($value, $use_html_entities);
1481
-        }
1482
-
1483
-        // prep the required array
1484
-        $required = self::prep_required($required);
1485
-        // set disabled tag
1486
-        $disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1487
-        // ya gots ta have style man!!!
1488
-        $radio_class = is_admin() ? 'ee-admin-radio-lbl' : $label_class;
1489
-        $class       = empty($class) ? 'espresso-radio-btn-inp' : $class;
1490
-        $extra       = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1491
-
1492
-        $label_html   = self::label($question, $required_text, $required['label'], '', $label_class);
1493
-        $mobile_label = self::mobileLabel(
1494
-            $add_mobile_label,
1495
-            $question,
1496
-            $required_text,
1497
-            $required['label'],
1498
-            $label_class
1499
-        );
1500
-
1501
-        $input_html = $mobile_label
1502
-            . '<ul id="' . $id . '-ul" class="espresso-checkbox-options-ul ' . $class . '-ul">';
1503
-
1504
-        $class .= ! empty($system_ID) ? ' ' . $system_ID : '';
1505
-        $class .= ! empty($required['class']) ? ' ' . $required['class'] : '';
1506
-
1507
-        foreach ($options as $OPT) {
1508
-            $value = $OPT->value();// self::prep_option_value( $OPT->value() );
1509
-            $size  = self::get_label_size_class($OPT->value() . ' ' . $OPT->desc());
1510
-            $text  = self::prep_answer($OPT->value());
1511
-            $desc  = $OPT->desc();
1512
-            $opt   = '-' . sanitize_key($value);
1513
-
1514
-            $checked = is_array($answer) && in_array($text, $answer) ? ' checked' : '';
1515
-
1516
-            $input_html .= "\n\t\t\t\t" . '<li' . $size . '>';
1517
-            $input_html .= "\n\t\t\t\t\t" . '<label class="' . $radio_class . ' espresso-checkbox-lbl">';
1518
-            $input_html .= $label_b4 ? "\n\t\t\t\t\t\t" . '<span>' . $text . '</span>&nbsp;&nbsp;' : '';
1519
-            $input_html .= "\n\t\t\t\t\t\t"
1520
-                           . '<input type="checkbox" name="' . $name . '[' . $OPT->ID() . ']" '
1521
-                           . 'id="' . $id . $opt . '" class="' . $class . '" value="' . $value . '" '
1522
-                           . 'aria-label="' . esc_attr($required['msg']) . '" ' . $disabled . $checked . ' ' . $extra . '/>';
1523
-            $input_html .= ! $label_b4 ? "\n\t\t\t\t\t\t" . '&nbsp;&nbsp;<span>' . $text . '</span>' : '';
1524
-            $input_html .= "\n\t\t\t\t\t" . '</label>';
1525
-            if (! empty($desc) && $desc != $text) {
1526
-                $input_html .= "\n\t\t\t\t\t"
1527
-                               . ' &nbsp; <br/><div class="espresso-checkbox-option-desc small-text grey-text">'
1528
-                               . $desc
1529
-                               . '</div>';
1530
-            }
1531
-            $input_html .= "\n\t\t\t\t" . '</li>';
1532
-        }
1533
-
1534
-        $input_html .= "\n\t\t\t" . '</ul>';
1535
-
1536
-        $input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1537
-        return $label_html . $input_html;
1538
-    }
1539
-
1540
-
1541
-    /**
1542
-     * generates HTML for a form datepicker input
1543
-     *
1544
-     * @param string $question    label content
1545
-     * @param string $answer      form input value attribute
1546
-     * @param string $name        form input name attribute
1547
-     * @param string $id          form input css id attribute
1548
-     * @param string $class       form input css class attribute
1549
-     * @param array  $required    'label', 'class', and 'msg' - array of values for required "label" content, css
1550
-     *                            required 'class', and required 'msg' attribute
1551
-     * @param string $label_class css class attribute for the label
1552
-     * @param string $disabled    disabled="disabled" or null
1553
-     * @return string HTML
1554
-     */
1555
-    public static function datepicker(
1556
-        $question = false,
1557
-        $answer = null,
1558
-        $name = false,
1559
-        $id = '',
1560
-        $class = '',
1561
-        $required = false,
1562
-        $required_text = '',
1563
-        $label_class = '',
1564
-        $disabled = false,
1565
-        $system_ID = false,
1566
-        $use_html_entities = true,
1567
-        $add_mobile_label = false
1568
-    ) {
1569
-        // need these
1570
-        if (! $question || ! $name) {
1571
-            return null;
1572
-        }
1573
-        // prep the answer
1574
-        $answer = is_array($answer) ? '' : self::prep_answer($answer, $use_html_entities);
1575
-        // prep the required array
1576
-        $required = self::prep_required($required);
1577
-        // set disabled tag
1578
-        $disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1579
-        // ya gots ta have style man!!!
1580
-        $txt_class = is_admin() ? 'regular-text' : 'espresso-datepicker-inp';
1581
-        $class     = empty($class) ? $txt_class : $class;
1582
-        $class     .= ! empty($system_ID) ? ' ' . $system_ID : '';
1583
-        $class = self::appendInputSizeClass($class, $answer);
1584
-        $extra     = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1585
-
1586
-        $label_html   = self::label($question, $required_text, $required['label'], '', $label_class);
1587
-        $mobile_label = self::mobileLabel(
1588
-            $add_mobile_label,
1589
-            $question,
1590
-            $required_text,
1591
-            $required['label'],
1592
-            $label_class,
1593
-            $name
1594
-        );
1595
-
1596
-        $input_html = $mobile_label
1597
-            . '<input type="text" name="' . $name . '" id="' . $id . '" '
1598
-            . 'class="' . $class . ' ' . $required['class'] . ' datepicker" value="' . $answer . '"  '
1599
-            . 'aria-label="' . esc_attr($required['msg']) . '" ' . $disabled . ' ' . $extra . '/>';
1600
-
1601
-        // enqueue scripts
1602
-        wp_register_style(
1603
-            'espresso-ui-theme',
1604
-            EE_GLOBAL_ASSETS_URL . 'css/espresso-ui-theme/jquery-ui-1.10.3.custom.min.css',
1605
-            [],
1606
-            EVENT_ESPRESSO_VERSION
1607
-        );
1608
-        wp_enqueue_style('espresso-ui-theme');
1609
-        wp_enqueue_script('jquery-ui-datepicker');
1610
-
1611
-        $input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1612
-        return $label_html . $input_html;
1613
-    }
1614
-
1615
-
1616
-    /**
1617
-     *  remove_label_keep_required_msg
1618
-     *  this will strip out a form input's label HTML while keeping the required text HTML that MUST be before the label
1619
-     *
1620
-     * @access public
1621
-     * @return     string
1622
-     */
1623
-    public static function remove_label_keep_required_msg($label_html, $required_text)
1624
-    {
1625
-        return $required_text;
1626
-    }
1627
-
1628
-
1629
-    /**
1630
-     * Simply returns the HTML for a hidden input of the given name and value.
1631
-     *
1632
-     * @param string $name
1633
-     * @param string $value
1634
-     * @return string HTML
1635
-     */
1636
-    public static function hidden_input($name, $value, $id = '')
1637
-    {
1638
-        $id = ! empty($id) ? $id : $name;
1639
-        return '<input id="' . $id . '" type="hidden" name="' . $name . '" value="' . $value . '"/>';
1640
-    }
1641
-
1642
-
1643
-    /**
1644
-     * prep_question
1645
-     *
1646
-     * @param string $question
1647
-     * @return string
1648
-     */
1649
-    public static function prep_question($question)
1650
-    {
1651
-        return $question;
1652
-    }
1653
-
1654
-
1655
-    /**
1656
-     *  prep_answer
1657
-     *
1658
-     * @param mixed $answer
1659
-     * @return string
1660
-     */
1661
-    public static function prep_answer($answer, $use_html_entities = true)
1662
-    {
1663
-        // make sure we convert bools first.  Otherwise (bool) false becomes an empty string which is NOT desired,
1664
-        // we want "0".
1665
-        if (is_bool($answer)) {
1666
-            $answer = $answer ? 1 : 0;
1667
-        }
1668
-        $answer = trim(stripslashes(str_replace('&#039;', "'", $answer)));
1669
-        return $use_html_entities ? htmlentities($answer, ENT_QUOTES, 'UTF-8') : $answer;
1670
-    }
1671
-
1672
-
1673
-    /**
1674
-     *  prep_answer_options
1675
-     *
1676
-     * @param array $QSOs array of EE_Question_Option objects
1677
-     * @return array
1678
-     */
1679
-    public static function prep_answer_options($QSOs = [])
1680
-    {
1681
-        $prepped_answer_options = [];
1682
-        if (is_array($QSOs) && ! empty($QSOs)) {
1683
-            foreach ($QSOs as $key => $QSO) {
1684
-                if (! $QSO instanceof EE_Question_Option) {
1685
-                    $QSO = EE_Question_Option::new_instance(
1686
-                        [
1687
-                            'QSO_value' => is_array($QSO) && isset($QSO['id'])
1688
-                                ? (string) $QSO['id']
1689
-                                : (string) $key,
1690
-                            'QSO_desc'  => is_array($QSO) && isset($QSO['text'])
1691
-                                ? (string) $QSO['text']
1692
-                                : (string) $QSO,
1693
-                        ]
1694
-                    );
1695
-                }
1696
-                if ($QSO->opt_group()) {
1697
-                    $prepped_answer_options[ $QSO->opt_group() ][] = $QSO;
1698
-                } else {
1699
-                    $prepped_answer_options[] = $QSO;
1700
-                }
1701
-            }
1702
-        }
1703
-        //      d( $prepped_answer_options );
1704
-        return $prepped_answer_options;
1705
-    }
1706
-
1707
-
1708
-    /**
1709
-     *  prep_option_value
1710
-     *
1711
-     * @param string $option_value
1712
-     * @return string
1713
-     */
1714
-    public static function prep_option_value($option_value)
1715
-    {
1716
-        return esc_attr(trim(stripslashes($option_value)));
1717
-    }
1718
-
1719
-
1720
-    /**
1721
-     *  prep_required
1722
-     *
1723
-     * @param string|array $required
1724
-     * @return array
1725
-     */
1726
-    public static function prep_required($required = [])
1727
-    {
1728
-        // make sure required is an array
1729
-        $required = is_array($required) ? $required : [];
1730
-        // and set some defaults
1731
-        return array_merge(['label' => '', 'class' => '', 'msg' => ''], $required);
1732
-    }
1733
-
1734
-
1735
-    /**
1736
-     *  get_label_size_class
1737
-     *
1738
-     * @param string $value
1739
-     * @return string
1740
-     */
1741
-    public static function get_label_size_class($value = false)
1742
-    {
1743
-        if ($value === false || $value === '') {
1744
-            return ' class="medium-lbl"';
1745
-        }
1746
-        // determine length of option value
1747
-        $val_size = strlen($value);
1748
-        switch ($val_size) {
1749
-            case $val_size < 3:
1750
-                $size = ' class="nano-lbl"';
1751
-                break;
1752
-            case $val_size < 6:
1753
-                $size = ' class="micro-lbl"';
1754
-                break;
1755
-            case $val_size < 12:
1756
-                $size = ' class="tiny-lbl"';
1757
-                break;
1758
-            case $val_size < 25:
1759
-                $size = ' class="small-lbl"';
1760
-                break;
1761
-            case $val_size > 100:
1762
-                $size = ' class="big-lbl"';
1763
-                break;
1764
-            default:
1765
-                $size = ' class="medium-lbl"';
1766
-                break;
1767
-        }
1768
-        return $size;
1769
-    }
1770
-
1771
-
1772
-    /**
1773
-     *  _load_system_dropdowns
1774
-     *
1775
-     * @param EE_Question_Form_Input $QFI
1776
-     * @return array
1777
-     * @throws EE_Error
1778
-     * @throws ReflectionException
1779
-     */
1780
-    private static function _load_system_dropdowns($QFI)
1781
-    {
1782
-        $QST_system = $QFI->get('QST_system');
1783
-        switch ($QST_system) {
1784
-            case 'state':
1785
-                $QFI = self::generate_state_dropdown($QFI);
1786
-                break;
1787
-            case 'country':
1788
-                $QFI = self::generate_country_dropdown($QFI);
1789
-                break;
1790
-            case 'admin-state':
1791
-                $QFI = self::generate_state_dropdown($QFI, true);
1792
-                break;
1793
-            case 'admin-country':
1794
-                $QFI = self::generate_country_dropdown($QFI, true);
1795
-                break;
1796
-        }
1797
-        return $QFI;
1798
-    }
1799
-
1800
-
1801
-    /**
1802
-     * This preps dropdowns that are specialized.
1803
-     *
1804
-     * @param EE_Question_Form_Input $QFI
1805
-     *
1806
-     * @return EE_Question_Form_Input
1807
-     * @throws EE_Error
1808
-     * @throws ReflectionException
1809
-     * @since  4.6.0
1810
-     */
1811
-    protected static function _load_specialized_dropdowns($QFI)
1812
-    {
1813
-        switch ($QFI->get('QST_type')) {
1814
-            case 'STATE':
1815
-                $QFI = self::generate_state_dropdown($QFI);
1816
-                break;
1817
-            case 'COUNTRY':
1818
-                $QFI = self::generate_country_dropdown($QFI);
1819
-                break;
1820
-        }
1821
-        return $QFI;
1822
-    }
1823
-
1824
-
1825
-    /**
1826
-     *    generate_state_dropdown
1827
-     *
1828
-     * @param EE_Question_Form_Input $QST
1829
-     * @param bool                   $get_all
1830
-     * @return EE_Question_Form_Input
1831
-     * @throws EE_Error
1832
-     * @throws ReflectionException
1833
-     */
1834
-    public static function generate_state_dropdown($QST, $get_all = false)
1835
-    {
1836
-        $states = $get_all
1837
-            ? EEM_State::instance()->get_all_states()
1838
-            : EEM_State::instance()->get_all_states_of_active_countries();
1839
-        if ($states && count($states) != count($QST->options())) {
1840
-            $QST->set('QST_type', 'DROPDOWN');
1841
-            // if multiple countries, we'll create option groups within the dropdown
1842
-            foreach ($states as $state) {
1843
-                if ($state instanceof EE_State) {
1844
-                    $QSO = EE_Question_Option::new_instance(
1845
-                        [
1846
-                            'QSO_value'   => $state->ID(),
1847
-                            'QSO_desc'    => $state->name(),
1848
-                            'QST_ID'      => $QST->get('QST_ID'),
1849
-                            'QSO_deleted' => false,
1850
-                        ]
1851
-                    );
1852
-                    // set option group
1853
-                    $QSO->set_opt_group($state->country()->name());
1854
-                    // add option to question
1855
-                    $QST->add_temp_option($QSO);
1856
-                }
1857
-            }
1858
-        }
1859
-        return $QST;
1860
-    }
1861
-
1862
-
1863
-    /**
1864
-     *    generate_country_dropdown
1865
-     *
1866
-     * @param      $QST
1867
-     * @param bool $get_all
1868
-     * @return array
1869
-     * @throws EE_Error
1870
-     * @throws ReflectionException
1871
-     * @internal param array $question
1872
-     */
1873
-    public static function generate_country_dropdown($QST, $get_all = false)
1874
-    {
1875
-        $countries = $get_all
1876
-            ? EEM_Country::instance()->get_all_countries()
1877
-            : EEM_Country::instance()->get_all_active_countries();
1878
-        if ($countries && count($countries) != count($QST->options())) {
1879
-            $QST->set('QST_type', 'DROPDOWN');
1880
-            // now add countries
1881
-            foreach ($countries as $country) {
1882
-                if ($country instanceof EE_Country) {
1883
-                    $QSO = EE_Question_Option::new_instance(
1884
-                        [
1885
-                            'QSO_value'   => $country->ID(),
1886
-                            'QSO_desc'    => $country->name(),
1887
-                            'QST_ID'      => $QST->get('QST_ID'),
1888
-                            'QSO_deleted' => false,
1889
-                        ]
1890
-                    );
1891
-                    $QST->add_temp_option($QSO);
1892
-                }
1893
-            }
1894
-        }
1895
-        return $QST;
1896
-    }
1897
-
1898
-
1899
-    /**
1900
-     *  generates options for a month dropdown selector with numbers from 01 to 12
1901
-     *
1902
-     * @return array()
1903
-     */
1904
-    public static function two_digit_months_dropdown_options()
1905
-    {
1906
-        $options = [];
1907
-        for ($x = 1; $x <= 12; $x++) {
1908
-            $mm             = str_pad($x, 2, '0', STR_PAD_LEFT);
1909
-            $options[ $mm ] = $mm;
1910
-        }
1911
-        return EEH_Form_Fields::prep_answer_options($options);
1912
-    }
1913
-
1914
-
1915
-    /**
1916
-     *  generates a year dropdown selector with numbers for the next ten years
1917
-     *
1918
-     * @return array
1919
-     */
1920
-    public static function next_decade_two_digit_year_dropdown_options()
1921
-    {
1922
-        $options      = [];
1923
-        $current_year = date('y');
1924
-        $next_decade  = $current_year + 10;
1925
-        for ($x = $current_year; $x <= $next_decade; $x++) {
1926
-            $yy             = str_pad($x, 2, '0', STR_PAD_LEFT);
1927
-            $options[ $yy ] = $yy;
1928
-        }
1929
-        return EEH_Form_Fields::prep_answer_options($options);
1930
-    }
1931
-
1932
-
1933
-    /**
1934
-     * generates a month/year dropdown selector for all registrations matching the given criteria.  Typically used for
1935
-     * list table filter.
1936
-     *
1937
-     * @param string  $cur_date     any currently selected date can be entered here.
1938
-     * @param string  $status       Registration status
1939
-     * @param integer $evt_category Event Category ID if the Event Category filter is selected
1940
-     * @return string                html
1941
-     * @throws EE_Error
1942
-     */
1943
-    public static function generate_registration_months_dropdown($cur_date = '', $status = '', $evt_category = 0)
1944
-    {
1945
-        $_where = [];
1946
-        if (! empty($status)) {
1947
-            $_where['STS_ID'] = $status;
1948
-        }
1949
-
1950
-        if ($evt_category > 0) {
1951
-            $_where['Event.Term_Taxonomy.term_id'] = $evt_category;
1952
-        }
1953
-
1954
-        $regdtts = EEM_Registration::instance()->get_reg_months_and_years($_where);
1955
-
1956
-        // setup vals for select input helper
1957
-        $options = [
1958
-            0 => [
1959
-                'text' => esc_html__('Select a Month/Year', 'event_espresso'),
1960
-                'id'   => '',
1961
-            ],
1962
-        ];
1963
-
1964
-        foreach ($regdtts as $regdtt) {
1965
-            $date      = $regdtt->reg_month . ' ' . $regdtt->reg_year;
1966
-            $options[] = [
1967
-                'text' => $date,
1968
-                'id'   => $date,
1969
-            ];
1970
-        }
1971
-
1972
-        return self::select_input('month_range', $options, $cur_date);
1973
-    }
1974
-
1975
-
1976
-    /**
1977
-     * generates a month/year dropdown selector for all events matching the given criteria
1978
-     * Typically used for list table filter
1979
-     *
1980
-     * @param string $cur_date          any currently selected date can be entered here.
1981
-     * @param string $status            "view" (i.e. all, today, month, draft)
1982
-     * @param int    $evt_category      category event belongs to
1983
-     * @param string $evt_active_status "upcoming", "expired", "active", or "inactive"
1984
-     * @return string                    html
1985
-     * @throws EE_Error
1986
-     */
1987
-    public static function generate_event_months_dropdown(
1988
-        $cur_date = '',
1989
-        $status = null,
1990
-        $evt_category = null,
1991
-        $evt_active_status = null
1992
-    ) {
1993
-        // determine what post_status our condition will have for the query.
1994
-        // phpcs:disable PSR2.ControlStructures.SwitchDeclaration.TerminatingComment
1995
-        switch ($status) {
1996
-            case 'month':
1997
-            case 'today':
1998
-            case null:
1999
-            case 'all':
2000
-                $where['Event.status'] = ['NOT IN', ['trash']];
2001
-                break;
2002
-            case 'draft':
2003
-                $where['Event.status'] = ['IN', ['draft', 'auto-draft']];
2004
-                break;
2005
-            default:
2006
-                $where['Event.status'] = $status;
2007
-        }
2008
-
2009
-        // phpcs:enable
2010
-
2011
-        // categories?
2012
-
2013
-
2014
-        if (! empty($evt_category)) {
2015
-            $where['Event.Term_Taxonomy.taxonomy'] = 'espresso_event_categories';
2016
-            $where['Event.Term_Taxonomy.term_id']  = $evt_category;
2017
-        }
2018
-
2019
-
2020
-        //      $where['DTT_is_primary'] = 1;
2021
-
2022
-        $DTTS = EEM_Datetime::instance()->get_dtt_months_and_years($where, $evt_active_status);
2023
-
2024
-        // let's setup vals for select input helper
2025
-        $options = [
2026
-            0 => [
2027
-                'text' => esc_html__('Select a Month/Year', 'event_espresso'),
2028
-                'id'   => "",
2029
-            ],
2030
-        ];
2031
-
2032
-
2033
-        // translate month and date
2034
-        global $wp_locale;
2035
-
2036
-        foreach ($DTTS as $DTT) {
2037
-            $localized_date = $wp_locale->get_month($DTT->dtt_month_num) . ' ' . $DTT->dtt_year;
2038
-            $id             = $DTT->dtt_month . ' ' . $DTT->dtt_year;
2039
-            $options[]      = [
2040
-                'text' => $localized_date,
2041
-                'id'   => $id,
2042
-            ];
2043
-        }
2044
-
2045
-
2046
-        return self::select_input('month_range', $options, $cur_date);
2047
-    }
2048
-
2049
-
2050
-    /**
2051
-     * generates the dropdown selector for event categories
2052
-     * typically used as a filter on list tables.
2053
-     *
2054
-     * @param integer $current_cat currently selected category
2055
-     * @return string               html for dropdown
2056
-     * @throws EE_Error
2057
-     * @throws ReflectionException
2058
-     */
2059
-    public static function generate_event_category_dropdown($current_cat = -1)
2060
-    {
2061
-        $categories = EEM_Term::instance()->get_all_ee_categories(true);
2062
-        $options    = [
2063
-            '0' => [
2064
-                'text' => esc_html__('All Categories', 'event_espresso'),
2065
-                'id'   => -1,
2066
-            ],
2067
-        ];
2068
-
2069
-        // setup categories for dropdown
2070
-        foreach ($categories as $category) {
2071
-            $options[] = [
2072
-                'text' => $category->get('name'),
2073
-                'id'   => $category->ID(),
2074
-            ];
2075
-        }
2076
-
2077
-        return self::select_input('EVT_CAT', $options, $current_cat);
2078
-    }
2079
-
2080
-
2081
-    /**
2082
-     *    generate a submit button with or without it's own microform
2083
-     *    this is the only way to create buttons that are compatible across all themes
2084
-     *
2085
-     * @access    public
2086
-     * @param string      $url              - the form action
2087
-     * @param string      $ID               - some kind of unique ID, appended with "-sbmt" for the input and "-frm"
2088
-     *                                      for the form
2089
-     * @param string      $class            - css classes (separated by spaces if more than one)
2090
-     * @param string      $text             - what appears on the button
2091
-     * @param string      $nonce_action     - if using nonces
2092
-     * @param bool|string $input_only       - whether to print form header and footer. TRUE returns the input without
2093
-     *                                      the form
2094
-     * @param string      $extra_attributes - any extra attributes that need to be attached to the form input
2095
-     * @return    string
2096
-     */
2097
-    public static function submit_button(
2098
-        $url = '',
2099
-        $ID = '',
2100
-        $class = '',
2101
-        $text = '',
2102
-        $nonce_action = '',
2103
-        $input_only = false,
2104
-        $extra_attributes = ''
2105
-    ) {
2106
-        $btn = '';
2107
-        if (empty($url) || empty($ID)) {
2108
-            return $btn;
2109
-        }
2110
-        $text = ! empty($text) ? $text : esc_html__('Submit', 'event_espresso');
2111
-        $btn  .= '<input id="' . $ID . '-btn" class="' . $class . '" '
2112
-                 . 'type="submit" value="' . $text . '" ' . $extra_attributes . '/>';
2113
-        if (! $input_only) {
2114
-            $btn_frm = '<form id="' . $ID . '-frm" method="POST" action="' . $url . '">';
2115
-            $btn_frm .= ! empty($nonce_action)
2116
-                ? wp_nonce_field($nonce_action, $nonce_action . '_nonce', true, false)
2117
-                : '';
2118
-            $btn_frm .= $btn;
2119
-            $btn_frm .= '</form>';
2120
-            $btn     = $btn_frm;
2121
-            unset($btn_frm);
2122
-        }
2123
-        return $btn;
2124
-    }
1090
+		$input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1091
+		return $label_html . $input_html;
1092
+	}
1093
+
1094
+
1095
+	/**
1096
+	 * generates HTML for a form textarea
1097
+	 *
1098
+	 * @param string $question    label content
1099
+	 * @param string $answer      form input value attribute
1100
+	 * @param string $name        form input name attribute
1101
+	 * @param string $id          form input css id attribute
1102
+	 * @param string $class       form input css class attribute
1103
+	 * @param array  $dimensions  array of form input rows and cols attributes : array( 'rows' => 3, 'cols' => 40 )
1104
+	 * @param array  $required    'label', 'class', and 'msg' - array of values for required "label" content, css
1105
+	 *                            required 'class', and required 'msg' attribute
1106
+	 * @param string $label_class css class attribute for the label
1107
+	 * @param string $disabled    disabled="disabled" or null
1108
+	 * @return string HTML
1109
+	 */
1110
+	public static function textarea(
1111
+		$question = false,
1112
+		$answer = null,
1113
+		$name = false,
1114
+		$id = '',
1115
+		$class = '',
1116
+		$dimensions = false,
1117
+		$required = false,
1118
+		$required_text = '',
1119
+		$label_class = '',
1120
+		$disabled = false,
1121
+		$system_ID = false,
1122
+		$use_html_entities = true,
1123
+		$add_mobile_label = false
1124
+	) {
1125
+		// need these
1126
+		if (! $question || ! $name) {
1127
+			return null;
1128
+		}
1129
+		// prep the answer
1130
+		$answer = is_array($answer) ? '' : self::prep_answer($answer, $use_html_entities);
1131
+		// prep the required array
1132
+		$required = self::prep_required($required);
1133
+		// make sure $dimensions is an array
1134
+		$dimensions = is_array($dimensions) ? $dimensions : [];
1135
+		// and set some defaults
1136
+		$dimensions = array_merge(['rows' => 3, 'cols' => 40], $dimensions);
1137
+		// set disabled tag
1138
+		$disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1139
+		// ya gots ta have style man!!!
1140
+		$class     .= ! empty($system_ID) ? ' ' . $system_ID : '';
1141
+		$class     .= ! empty($required['class']) ? ' ' . $required['class'] : '';
1142
+		$extra     = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1143
+
1144
+		$label_html   = self::label($question, $required_text, $required['label'], $name, $label_class);
1145
+		$mobile_label = self::mobileLabel(
1146
+			$add_mobile_label,
1147
+			$question,
1148
+			$required_text,
1149
+			$required['label'],
1150
+			$label_class,
1151
+			$name
1152
+		);
1153
+
1154
+		$input_html = $mobile_label
1155
+			. '<textarea name="' . $name . '" id="' . $id . '" class="' . trim($class) . '" '
1156
+			. 'rows="' . $dimensions['rows'] . '" cols="' . $dimensions['cols'] . '"  '
1157
+			. 'aria-label="' . $required['msg'] . '" ' . $disabled . ' ' . $extra . '>'
1158
+			 . esc_textarea($answer)
1159
+			  . '</textarea>';
1160
+
1161
+		$input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1162
+		return $label_html . $input_html;
1163
+	}
1164
+
1165
+
1166
+	/**
1167
+	 * generates HTML for a form select input
1168
+	 *
1169
+	 * @param string $question    label content
1170
+	 * @param string $answer      form input value attribute
1171
+	 * @param array  $options     array of answer options where array key = option value and array value = option
1172
+	 *                            display text
1173
+	 * @param string $name        form input name attribute
1174
+	 * @param string $id          form input css id attribute
1175
+	 * @param string $class       form input css class attribute
1176
+	 * @param array  $required    'label', 'class', and 'msg' - array of values for required "label" content, css
1177
+	 *                            required 'class', and required 'msg' attribute
1178
+	 * @param string $label_class css class attribute for the label
1179
+	 * @param string $disabled    disabled="disabled" or null
1180
+	 * @return string HTML
1181
+	 */
1182
+	public static function select(
1183
+		$question = false,
1184
+		$answer = null,
1185
+		$options = false,
1186
+		$name = false,
1187
+		$id = '',
1188
+		$class = '',
1189
+		$required = false,
1190
+		$required_text = '',
1191
+		$label_class = '',
1192
+		$disabled = false,
1193
+		$system_ID = false,
1194
+		$use_html_entities = true,
1195
+		$add_please_select_option = false,
1196
+		$add_mobile_label = false
1197
+	) {
1198
+
1199
+		// need these
1200
+		if (! $question || ! $name || ! $options || empty($options) || ! is_array($options)) {
1201
+			return null;
1202
+		}
1203
+		// prep the answer
1204
+		$answer = is_array($answer)
1205
+			? self::prep_answer(array_shift($answer), $use_html_entities)
1206
+			: self::prep_answer($answer, $use_html_entities);
1207
+		// prep the required array
1208
+		$required = self::prep_required($required);
1209
+		// set disabled tag
1210
+		$disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1211
+		// ya gots ta have style man!!!
1212
+		$class     .= ! empty($system_ID) ? ' ' . $system_ID : '';
1213
+		$class = self::appendInputSizeClass($class, $options);
1214
+		$extra     = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1215
+
1216
+		$label_html   = self::label($question, $required_text, $required['label'], $name, $label_class);
1217
+		$mobile_label = self::mobileLabel(
1218
+			$add_mobile_label,
1219
+			$question,
1220
+			$required_text,
1221
+			$required['label'],
1222
+			$label_class,
1223
+			$name
1224
+		);
1225
+
1226
+		$input_html = $mobile_label
1227
+			. '<select name="' . $name . '" id="' . $id . '" class="' . trim($class) . ' ' . $required['class'] . '" '
1228
+			. 'aria-label="' . esc_attr($required['msg']) . '"' . $disabled . ' ' . $extra . '>';
1229
+		// recursively count array elements, to determine total number of options
1230
+		$only_option = count($options, 1) == 1;
1231
+		if (! $only_option) {
1232
+			// if there is NO answer set and there are multiple options to choose from, then set the "please select" message as selected
1233
+			$selected   = $answer === null ? ' selected' : '';
1234
+			$input_html .= $add_please_select_option
1235
+				? "\n\t\t\t\t"
1236
+				  . '<option value=""' . $selected . '>'
1237
+				  . esc_html__(' - please select - ', 'event_espresso')
1238
+				  . '</option>'
1239
+				: '';
1240
+		}
1241
+		foreach ($options as $key => $value) {
1242
+			// if value is an array, then create option groups, else create regular ol' options
1243
+			$input_html .= is_array($value)
1244
+				? self::_generate_select_option_group(
1245
+					$key,
1246
+					$value,
1247
+					$answer,
1248
+					$use_html_entities
1249
+				)
1250
+				: self::_generate_select_option(
1251
+					$value->value(),
1252
+					$value->desc(),
1253
+					$answer,
1254
+					$only_option,
1255
+					$use_html_entities
1256
+				);
1257
+		}
1258
+
1259
+		$input_html .= "\n\t\t\t" . '</select>';
1260
+
1261
+		$input_html =
1262
+			apply_filters(
1263
+				'FHEE__EEH_Form_Fields__select__before_end_wrapper',
1264
+				$input_html,
1265
+				$question,
1266
+				$answer,
1267
+				$name,
1268
+				$id,
1269
+				$class,
1270
+				$system_ID
1271
+			);
1272
+
1273
+		$input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1274
+		return $label_html . $input_html;
1275
+	}
1276
+
1277
+
1278
+	/**
1279
+	 *  _generate_select_option_group
1280
+	 *
1281
+	 *  if  $value for a select box is an array, then the key will be used as the optgroup label
1282
+	 *  and the value array will be looped thru and the elements sent to _generate_select_option
1283
+	 *
1284
+	 * @param mixed   $opt_group
1285
+	 * @param mixed   $QSOs
1286
+	 * @param mixed   $answer
1287
+	 * @param boolean $use_html_entities
1288
+	 * @return string
1289
+	 */
1290
+	private static function _generate_select_option_group($opt_group, $QSOs, $answer, $use_html_entities = true)
1291
+	{
1292
+		$html = "\n\t\t\t\t" . '<optgroup label="' . self::prep_option_value($opt_group) . '">';
1293
+		foreach ($QSOs as $QSO) {
1294
+			$html .= self::_generate_select_option($QSO->value(), $QSO->desc(), $answer, false, $use_html_entities);
1295
+		}
1296
+		$html .= "\n\t\t\t\t" . '</optgroup>';
1297
+		return $html;
1298
+	}
1299
+
1300
+
1301
+	/**
1302
+	 *  _generate_select_option
1303
+	 *
1304
+	 * @param mixed   $key
1305
+	 * @param mixed   $value
1306
+	 * @param mixed   $answer
1307
+	 * @param int     $only_option
1308
+	 * @param boolean $use_html_entities
1309
+	 * @return string
1310
+	 */
1311
+	private static function _generate_select_option(
1312
+		$key,
1313
+		$value,
1314
+		$answer,
1315
+		$only_option = false,
1316
+		$use_html_entities = true
1317
+	) {
1318
+		$key      = self::prep_answer($key, $use_html_entities);
1319
+		$value    = self::prep_answer($value, $use_html_entities);
1320
+		$value    = ! empty($value) ? $value : $key;
1321
+		$selected = ($answer == $key || $only_option) ? 'selected' : '';
1322
+		return "\n\t\t\t\t"
1323
+			   . '<option value="' . self::prep_option_value($key) . '" ' . $selected . '> '
1324
+			   . $value
1325
+			   . '&nbsp;&nbsp;&nbsp;</option>';
1326
+	}
1327
+
1328
+
1329
+	/**
1330
+	 * generates HTML for form radio button inputs
1331
+	 *
1332
+	 * @param bool|string $question    label content
1333
+	 * @param string      $answer      form input value attribute
1334
+	 * @param array|bool  $options     array of answer options where array key = option value and array value = option
1335
+	 *                                 display text
1336
+	 * @param bool|string $name        form input name attribute
1337
+	 * @param string      $id          form input css id attribute
1338
+	 * @param string      $class       form input css class attribute
1339
+	 * @param array|bool  $required    'label', 'class', and 'msg' - array of values for required "label" content, css
1340
+	 *                                 required 'class', and required 'msg' attribute
1341
+	 * @param string      $required_text
1342
+	 * @param string      $label_class css class attribute for the label
1343
+	 * @param bool|string $disabled    disabled="disabled" or null
1344
+	 * @param bool        $system_ID
1345
+	 * @param bool        $use_html_entities
1346
+	 * @param bool        $label_b4
1347
+	 * @param bool        $use_desc_4_label
1348
+	 * @return string HTML
1349
+	 */
1350
+	public static function radio(
1351
+		$question = false,
1352
+		$answer = null,
1353
+		$options = false,
1354
+		$name = false,
1355
+		$id = '',
1356
+		$class = '',
1357
+		$required = false,
1358
+		$required_text = '',
1359
+		$label_class = '',
1360
+		$disabled = false,
1361
+		$system_ID = false,
1362
+		$use_html_entities = true,
1363
+		$label_b4 = false,
1364
+		$use_desc_4_label = false,
1365
+		$add_mobile_label = false
1366
+	) {
1367
+		// need these
1368
+		if (! $question || ! $name || ! $options || empty($options) || ! is_array($options)) {
1369
+			return null;
1370
+		}
1371
+		// prep the answer
1372
+		$answer = is_array($answer) ? '' : self::prep_answer($answer, $use_html_entities);
1373
+		// prep the required array
1374
+		$required = self::prep_required($required);
1375
+		// set disabled tag
1376
+		$disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1377
+		// ya gots ta have style man!!!
1378
+		$radio_class = is_admin() ? 'ee-admin-radio-lbl' : $label_class;
1379
+		$class       = ! empty($class) ? $class : 'espresso-radio-btn-inp';
1380
+		$extra       = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1381
+
1382
+		$label_html = self::label($question, $required_text, $required['label'], '', $label_class);
1383
+		$mobile_label = self::mobileLabel(
1384
+			$add_mobile_label,
1385
+			$question,
1386
+			$required_text,
1387
+			$required['label'],
1388
+			$label_class
1389
+		);
1390
+
1391
+		$input_html = $mobile_label
1392
+			. '<ul id="' . $id . '-ul" class="espresso-radio-btn-options-ul ' . $class . '-ul">';
1393
+
1394
+		$class .= ! empty($system_ID) ? ' ' . $system_ID : '';
1395
+		$class .= ! empty($required['class']) ? ' ' . $required['class'] : '';
1396
+
1397
+		foreach ($options as $OPT) {
1398
+			if ($OPT instanceof EE_Question_Option) {
1399
+				$value   = self::prep_option_value($OPT->value());
1400
+				$label   = $use_desc_4_label ? $OPT->desc() : $OPT->value();
1401
+				$size    = $use_desc_4_label
1402
+					? self::get_label_size_class($OPT->value() . ' ' . $OPT->desc())
1403
+					: self::get_label_size_class($OPT->value());
1404
+				$desc    = $OPT->desc();// no self::prep_answer
1405
+				$answer  = is_numeric($value) && empty($answer) ? 0 : $answer;
1406
+				$checked = (string) $value == (string) $answer ? ' checked' : '';
1407
+				$opt     = '-' . sanitize_key($value);
1408
+
1409
+				$input_html .= "\n\t\t\t\t" . '<li' . $size . '>';
1410
+				$input_html .= "\n\t\t\t\t\t" . '<label class="' . $radio_class . ' espresso-radio-btn-lbl">';
1411
+				$input_html .= $label_b4 ? "\n\t\t\t\t\t\t" . '<span>' . $label . '</span>&nbsp;&nbsp;' : '';
1412
+				$input_html .= "\n\t\t\t\t\t\t"
1413
+							   . '<input type="radio" name="' . $name . '" id="' . $id . $opt . '" '
1414
+							   . 'class="' . $class . '" value="' . $value . '" '
1415
+							   . 'aria-label="' . esc_attr($required['msg']) . '" ' . $disabled
1416
+							   . $checked . ' ' . $extra . '/>';
1417
+				$input_html .= ! $label_b4
1418
+					? "\n\t\t\t\t\t\t"
1419
+					  . '&nbsp;&nbsp;<span class="espresso-radio-btn-desc">'
1420
+					  . $label
1421
+					  . '</span>'
1422
+					: '';
1423
+				$input_html .= "\n\t\t\t\t\t" . '</label>';
1424
+				$input_html .= $use_desc_4_label
1425
+					? ''
1426
+					: '<span class="espresso-radio-btn-option-desc small-text grey-text">' . $desc . '</span>';
1427
+				$input_html .= "\n\t\t\t\t" . '</li>';
1428
+			}
1429
+		}
1430
+
1431
+		$input_html .= "\n\t\t\t" . '</ul>';
1432
+
1433
+		$input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1434
+		return $label_html . $input_html;
1435
+	}
1436
+
1437
+
1438
+	/**
1439
+	 * generates HTML for form checkbox inputs
1440
+	 *
1441
+	 * @param string $question    label content
1442
+	 * @param string $answer      form input value attribute
1443
+	 * @param array  $options     array of options where array key = option value and array value = option display text
1444
+	 * @param string $name        form input name attribute
1445
+	 * @param string $id          form input css id attribute
1446
+	 * @param string $class       form input css class attribute
1447
+	 * @param array  $required    'label', 'class', and 'msg' - array of values for required "label" content, css
1448
+	 *                            required 'class', and required 'msg' attribute
1449
+	 * @param string $label_class css class attribute for the label
1450
+	 * @param string $disabled    disabled="disabled" or null
1451
+	 * @return string HTML
1452
+	 */
1453
+	public static function checkbox(
1454
+		$question = false,
1455
+		$answer = null,
1456
+		$options = false,
1457
+		$name = false,
1458
+		$id = '',
1459
+		$class = '',
1460
+		$required = false,
1461
+		$required_text = '',
1462
+		$label_class = '',
1463
+		$disabled = false,
1464
+		$label_b4 = false,
1465
+		$system_ID = false,
1466
+		$use_html_entities = true,
1467
+		$add_mobile_label = false
1468
+	) {
1469
+		// need these
1470
+		if (! $question || ! $name || ! $options || empty($options) || ! is_array($options)) {
1471
+			return null;
1472
+		}
1473
+		$answer = maybe_unserialize($answer);
1474
+
1475
+		// prep the answer(s)
1476
+		$answer = is_array($answer) ? $answer : [sanitize_key($answer) => $answer];
1477
+
1478
+		foreach ($answer as $key => $value) {
1479
+			$key            = self::prep_option_value($key);
1480
+			$answer[ $key ] = self::prep_answer($value, $use_html_entities);
1481
+		}
1482
+
1483
+		// prep the required array
1484
+		$required = self::prep_required($required);
1485
+		// set disabled tag
1486
+		$disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1487
+		// ya gots ta have style man!!!
1488
+		$radio_class = is_admin() ? 'ee-admin-radio-lbl' : $label_class;
1489
+		$class       = empty($class) ? 'espresso-radio-btn-inp' : $class;
1490
+		$extra       = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1491
+
1492
+		$label_html   = self::label($question, $required_text, $required['label'], '', $label_class);
1493
+		$mobile_label = self::mobileLabel(
1494
+			$add_mobile_label,
1495
+			$question,
1496
+			$required_text,
1497
+			$required['label'],
1498
+			$label_class
1499
+		);
1500
+
1501
+		$input_html = $mobile_label
1502
+			. '<ul id="' . $id . '-ul" class="espresso-checkbox-options-ul ' . $class . '-ul">';
1503
+
1504
+		$class .= ! empty($system_ID) ? ' ' . $system_ID : '';
1505
+		$class .= ! empty($required['class']) ? ' ' . $required['class'] : '';
1506
+
1507
+		foreach ($options as $OPT) {
1508
+			$value = $OPT->value();// self::prep_option_value( $OPT->value() );
1509
+			$size  = self::get_label_size_class($OPT->value() . ' ' . $OPT->desc());
1510
+			$text  = self::prep_answer($OPT->value());
1511
+			$desc  = $OPT->desc();
1512
+			$opt   = '-' . sanitize_key($value);
1513
+
1514
+			$checked = is_array($answer) && in_array($text, $answer) ? ' checked' : '';
1515
+
1516
+			$input_html .= "\n\t\t\t\t" . '<li' . $size . '>';
1517
+			$input_html .= "\n\t\t\t\t\t" . '<label class="' . $radio_class . ' espresso-checkbox-lbl">';
1518
+			$input_html .= $label_b4 ? "\n\t\t\t\t\t\t" . '<span>' . $text . '</span>&nbsp;&nbsp;' : '';
1519
+			$input_html .= "\n\t\t\t\t\t\t"
1520
+						   . '<input type="checkbox" name="' . $name . '[' . $OPT->ID() . ']" '
1521
+						   . 'id="' . $id . $opt . '" class="' . $class . '" value="' . $value . '" '
1522
+						   . 'aria-label="' . esc_attr($required['msg']) . '" ' . $disabled . $checked . ' ' . $extra . '/>';
1523
+			$input_html .= ! $label_b4 ? "\n\t\t\t\t\t\t" . '&nbsp;&nbsp;<span>' . $text . '</span>' : '';
1524
+			$input_html .= "\n\t\t\t\t\t" . '</label>';
1525
+			if (! empty($desc) && $desc != $text) {
1526
+				$input_html .= "\n\t\t\t\t\t"
1527
+							   . ' &nbsp; <br/><div class="espresso-checkbox-option-desc small-text grey-text">'
1528
+							   . $desc
1529
+							   . '</div>';
1530
+			}
1531
+			$input_html .= "\n\t\t\t\t" . '</li>';
1532
+		}
1533
+
1534
+		$input_html .= "\n\t\t\t" . '</ul>';
1535
+
1536
+		$input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1537
+		return $label_html . $input_html;
1538
+	}
1539
+
1540
+
1541
+	/**
1542
+	 * generates HTML for a form datepicker input
1543
+	 *
1544
+	 * @param string $question    label content
1545
+	 * @param string $answer      form input value attribute
1546
+	 * @param string $name        form input name attribute
1547
+	 * @param string $id          form input css id attribute
1548
+	 * @param string $class       form input css class attribute
1549
+	 * @param array  $required    'label', 'class', and 'msg' - array of values for required "label" content, css
1550
+	 *                            required 'class', and required 'msg' attribute
1551
+	 * @param string $label_class css class attribute for the label
1552
+	 * @param string $disabled    disabled="disabled" or null
1553
+	 * @return string HTML
1554
+	 */
1555
+	public static function datepicker(
1556
+		$question = false,
1557
+		$answer = null,
1558
+		$name = false,
1559
+		$id = '',
1560
+		$class = '',
1561
+		$required = false,
1562
+		$required_text = '',
1563
+		$label_class = '',
1564
+		$disabled = false,
1565
+		$system_ID = false,
1566
+		$use_html_entities = true,
1567
+		$add_mobile_label = false
1568
+	) {
1569
+		// need these
1570
+		if (! $question || ! $name) {
1571
+			return null;
1572
+		}
1573
+		// prep the answer
1574
+		$answer = is_array($answer) ? '' : self::prep_answer($answer, $use_html_entities);
1575
+		// prep the required array
1576
+		$required = self::prep_required($required);
1577
+		// set disabled tag
1578
+		$disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1579
+		// ya gots ta have style man!!!
1580
+		$txt_class = is_admin() ? 'regular-text' : 'espresso-datepicker-inp';
1581
+		$class     = empty($class) ? $txt_class : $class;
1582
+		$class     .= ! empty($system_ID) ? ' ' . $system_ID : '';
1583
+		$class = self::appendInputSizeClass($class, $answer);
1584
+		$extra     = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1585
+
1586
+		$label_html   = self::label($question, $required_text, $required['label'], '', $label_class);
1587
+		$mobile_label = self::mobileLabel(
1588
+			$add_mobile_label,
1589
+			$question,
1590
+			$required_text,
1591
+			$required['label'],
1592
+			$label_class,
1593
+			$name
1594
+		);
1595
+
1596
+		$input_html = $mobile_label
1597
+			. '<input type="text" name="' . $name . '" id="' . $id . '" '
1598
+			. 'class="' . $class . ' ' . $required['class'] . ' datepicker" value="' . $answer . '"  '
1599
+			. 'aria-label="' . esc_attr($required['msg']) . '" ' . $disabled . ' ' . $extra . '/>';
1600
+
1601
+		// enqueue scripts
1602
+		wp_register_style(
1603
+			'espresso-ui-theme',
1604
+			EE_GLOBAL_ASSETS_URL . 'css/espresso-ui-theme/jquery-ui-1.10.3.custom.min.css',
1605
+			[],
1606
+			EVENT_ESPRESSO_VERSION
1607
+		);
1608
+		wp_enqueue_style('espresso-ui-theme');
1609
+		wp_enqueue_script('jquery-ui-datepicker');
1610
+
1611
+		$input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1612
+		return $label_html . $input_html;
1613
+	}
1614
+
1615
+
1616
+	/**
1617
+	 *  remove_label_keep_required_msg
1618
+	 *  this will strip out a form input's label HTML while keeping the required text HTML that MUST be before the label
1619
+	 *
1620
+	 * @access public
1621
+	 * @return     string
1622
+	 */
1623
+	public static function remove_label_keep_required_msg($label_html, $required_text)
1624
+	{
1625
+		return $required_text;
1626
+	}
1627
+
1628
+
1629
+	/**
1630
+	 * Simply returns the HTML for a hidden input of the given name and value.
1631
+	 *
1632
+	 * @param string $name
1633
+	 * @param string $value
1634
+	 * @return string HTML
1635
+	 */
1636
+	public static function hidden_input($name, $value, $id = '')
1637
+	{
1638
+		$id = ! empty($id) ? $id : $name;
1639
+		return '<input id="' . $id . '" type="hidden" name="' . $name . '" value="' . $value . '"/>';
1640
+	}
1641
+
1642
+
1643
+	/**
1644
+	 * prep_question
1645
+	 *
1646
+	 * @param string $question
1647
+	 * @return string
1648
+	 */
1649
+	public static function prep_question($question)
1650
+	{
1651
+		return $question;
1652
+	}
1653
+
1654
+
1655
+	/**
1656
+	 *  prep_answer
1657
+	 *
1658
+	 * @param mixed $answer
1659
+	 * @return string
1660
+	 */
1661
+	public static function prep_answer($answer, $use_html_entities = true)
1662
+	{
1663
+		// make sure we convert bools first.  Otherwise (bool) false becomes an empty string which is NOT desired,
1664
+		// we want "0".
1665
+		if (is_bool($answer)) {
1666
+			$answer = $answer ? 1 : 0;
1667
+		}
1668
+		$answer = trim(stripslashes(str_replace('&#039;', "'", $answer)));
1669
+		return $use_html_entities ? htmlentities($answer, ENT_QUOTES, 'UTF-8') : $answer;
1670
+	}
1671
+
1672
+
1673
+	/**
1674
+	 *  prep_answer_options
1675
+	 *
1676
+	 * @param array $QSOs array of EE_Question_Option objects
1677
+	 * @return array
1678
+	 */
1679
+	public static function prep_answer_options($QSOs = [])
1680
+	{
1681
+		$prepped_answer_options = [];
1682
+		if (is_array($QSOs) && ! empty($QSOs)) {
1683
+			foreach ($QSOs as $key => $QSO) {
1684
+				if (! $QSO instanceof EE_Question_Option) {
1685
+					$QSO = EE_Question_Option::new_instance(
1686
+						[
1687
+							'QSO_value' => is_array($QSO) && isset($QSO['id'])
1688
+								? (string) $QSO['id']
1689
+								: (string) $key,
1690
+							'QSO_desc'  => is_array($QSO) && isset($QSO['text'])
1691
+								? (string) $QSO['text']
1692
+								: (string) $QSO,
1693
+						]
1694
+					);
1695
+				}
1696
+				if ($QSO->opt_group()) {
1697
+					$prepped_answer_options[ $QSO->opt_group() ][] = $QSO;
1698
+				} else {
1699
+					$prepped_answer_options[] = $QSO;
1700
+				}
1701
+			}
1702
+		}
1703
+		//      d( $prepped_answer_options );
1704
+		return $prepped_answer_options;
1705
+	}
1706
+
1707
+
1708
+	/**
1709
+	 *  prep_option_value
1710
+	 *
1711
+	 * @param string $option_value
1712
+	 * @return string
1713
+	 */
1714
+	public static function prep_option_value($option_value)
1715
+	{
1716
+		return esc_attr(trim(stripslashes($option_value)));
1717
+	}
1718
+
1719
+
1720
+	/**
1721
+	 *  prep_required
1722
+	 *
1723
+	 * @param string|array $required
1724
+	 * @return array
1725
+	 */
1726
+	public static function prep_required($required = [])
1727
+	{
1728
+		// make sure required is an array
1729
+		$required = is_array($required) ? $required : [];
1730
+		// and set some defaults
1731
+		return array_merge(['label' => '', 'class' => '', 'msg' => ''], $required);
1732
+	}
1733
+
1734
+
1735
+	/**
1736
+	 *  get_label_size_class
1737
+	 *
1738
+	 * @param string $value
1739
+	 * @return string
1740
+	 */
1741
+	public static function get_label_size_class($value = false)
1742
+	{
1743
+		if ($value === false || $value === '') {
1744
+			return ' class="medium-lbl"';
1745
+		}
1746
+		// determine length of option value
1747
+		$val_size = strlen($value);
1748
+		switch ($val_size) {
1749
+			case $val_size < 3:
1750
+				$size = ' class="nano-lbl"';
1751
+				break;
1752
+			case $val_size < 6:
1753
+				$size = ' class="micro-lbl"';
1754
+				break;
1755
+			case $val_size < 12:
1756
+				$size = ' class="tiny-lbl"';
1757
+				break;
1758
+			case $val_size < 25:
1759
+				$size = ' class="small-lbl"';
1760
+				break;
1761
+			case $val_size > 100:
1762
+				$size = ' class="big-lbl"';
1763
+				break;
1764
+			default:
1765
+				$size = ' class="medium-lbl"';
1766
+				break;
1767
+		}
1768
+		return $size;
1769
+	}
1770
+
1771
+
1772
+	/**
1773
+	 *  _load_system_dropdowns
1774
+	 *
1775
+	 * @param EE_Question_Form_Input $QFI
1776
+	 * @return array
1777
+	 * @throws EE_Error
1778
+	 * @throws ReflectionException
1779
+	 */
1780
+	private static function _load_system_dropdowns($QFI)
1781
+	{
1782
+		$QST_system = $QFI->get('QST_system');
1783
+		switch ($QST_system) {
1784
+			case 'state':
1785
+				$QFI = self::generate_state_dropdown($QFI);
1786
+				break;
1787
+			case 'country':
1788
+				$QFI = self::generate_country_dropdown($QFI);
1789
+				break;
1790
+			case 'admin-state':
1791
+				$QFI = self::generate_state_dropdown($QFI, true);
1792
+				break;
1793
+			case 'admin-country':
1794
+				$QFI = self::generate_country_dropdown($QFI, true);
1795
+				break;
1796
+		}
1797
+		return $QFI;
1798
+	}
1799
+
1800
+
1801
+	/**
1802
+	 * This preps dropdowns that are specialized.
1803
+	 *
1804
+	 * @param EE_Question_Form_Input $QFI
1805
+	 *
1806
+	 * @return EE_Question_Form_Input
1807
+	 * @throws EE_Error
1808
+	 * @throws ReflectionException
1809
+	 * @since  4.6.0
1810
+	 */
1811
+	protected static function _load_specialized_dropdowns($QFI)
1812
+	{
1813
+		switch ($QFI->get('QST_type')) {
1814
+			case 'STATE':
1815
+				$QFI = self::generate_state_dropdown($QFI);
1816
+				break;
1817
+			case 'COUNTRY':
1818
+				$QFI = self::generate_country_dropdown($QFI);
1819
+				break;
1820
+		}
1821
+		return $QFI;
1822
+	}
1823
+
1824
+
1825
+	/**
1826
+	 *    generate_state_dropdown
1827
+	 *
1828
+	 * @param EE_Question_Form_Input $QST
1829
+	 * @param bool                   $get_all
1830
+	 * @return EE_Question_Form_Input
1831
+	 * @throws EE_Error
1832
+	 * @throws ReflectionException
1833
+	 */
1834
+	public static function generate_state_dropdown($QST, $get_all = false)
1835
+	{
1836
+		$states = $get_all
1837
+			? EEM_State::instance()->get_all_states()
1838
+			: EEM_State::instance()->get_all_states_of_active_countries();
1839
+		if ($states && count($states) != count($QST->options())) {
1840
+			$QST->set('QST_type', 'DROPDOWN');
1841
+			// if multiple countries, we'll create option groups within the dropdown
1842
+			foreach ($states as $state) {
1843
+				if ($state instanceof EE_State) {
1844
+					$QSO = EE_Question_Option::new_instance(
1845
+						[
1846
+							'QSO_value'   => $state->ID(),
1847
+							'QSO_desc'    => $state->name(),
1848
+							'QST_ID'      => $QST->get('QST_ID'),
1849
+							'QSO_deleted' => false,
1850
+						]
1851
+					);
1852
+					// set option group
1853
+					$QSO->set_opt_group($state->country()->name());
1854
+					// add option to question
1855
+					$QST->add_temp_option($QSO);
1856
+				}
1857
+			}
1858
+		}
1859
+		return $QST;
1860
+	}
1861
+
1862
+
1863
+	/**
1864
+	 *    generate_country_dropdown
1865
+	 *
1866
+	 * @param      $QST
1867
+	 * @param bool $get_all
1868
+	 * @return array
1869
+	 * @throws EE_Error
1870
+	 * @throws ReflectionException
1871
+	 * @internal param array $question
1872
+	 */
1873
+	public static function generate_country_dropdown($QST, $get_all = false)
1874
+	{
1875
+		$countries = $get_all
1876
+			? EEM_Country::instance()->get_all_countries()
1877
+			: EEM_Country::instance()->get_all_active_countries();
1878
+		if ($countries && count($countries) != count($QST->options())) {
1879
+			$QST->set('QST_type', 'DROPDOWN');
1880
+			// now add countries
1881
+			foreach ($countries as $country) {
1882
+				if ($country instanceof EE_Country) {
1883
+					$QSO = EE_Question_Option::new_instance(
1884
+						[
1885
+							'QSO_value'   => $country->ID(),
1886
+							'QSO_desc'    => $country->name(),
1887
+							'QST_ID'      => $QST->get('QST_ID'),
1888
+							'QSO_deleted' => false,
1889
+						]
1890
+					);
1891
+					$QST->add_temp_option($QSO);
1892
+				}
1893
+			}
1894
+		}
1895
+		return $QST;
1896
+	}
1897
+
1898
+
1899
+	/**
1900
+	 *  generates options for a month dropdown selector with numbers from 01 to 12
1901
+	 *
1902
+	 * @return array()
1903
+	 */
1904
+	public static function two_digit_months_dropdown_options()
1905
+	{
1906
+		$options = [];
1907
+		for ($x = 1; $x <= 12; $x++) {
1908
+			$mm             = str_pad($x, 2, '0', STR_PAD_LEFT);
1909
+			$options[ $mm ] = $mm;
1910
+		}
1911
+		return EEH_Form_Fields::prep_answer_options($options);
1912
+	}
1913
+
1914
+
1915
+	/**
1916
+	 *  generates a year dropdown selector with numbers for the next ten years
1917
+	 *
1918
+	 * @return array
1919
+	 */
1920
+	public static function next_decade_two_digit_year_dropdown_options()
1921
+	{
1922
+		$options      = [];
1923
+		$current_year = date('y');
1924
+		$next_decade  = $current_year + 10;
1925
+		for ($x = $current_year; $x <= $next_decade; $x++) {
1926
+			$yy             = str_pad($x, 2, '0', STR_PAD_LEFT);
1927
+			$options[ $yy ] = $yy;
1928
+		}
1929
+		return EEH_Form_Fields::prep_answer_options($options);
1930
+	}
1931
+
1932
+
1933
+	/**
1934
+	 * generates a month/year dropdown selector for all registrations matching the given criteria.  Typically used for
1935
+	 * list table filter.
1936
+	 *
1937
+	 * @param string  $cur_date     any currently selected date can be entered here.
1938
+	 * @param string  $status       Registration status
1939
+	 * @param integer $evt_category Event Category ID if the Event Category filter is selected
1940
+	 * @return string                html
1941
+	 * @throws EE_Error
1942
+	 */
1943
+	public static function generate_registration_months_dropdown($cur_date = '', $status = '', $evt_category = 0)
1944
+	{
1945
+		$_where = [];
1946
+		if (! empty($status)) {
1947
+			$_where['STS_ID'] = $status;
1948
+		}
1949
+
1950
+		if ($evt_category > 0) {
1951
+			$_where['Event.Term_Taxonomy.term_id'] = $evt_category;
1952
+		}
1953
+
1954
+		$regdtts = EEM_Registration::instance()->get_reg_months_and_years($_where);
1955
+
1956
+		// setup vals for select input helper
1957
+		$options = [
1958
+			0 => [
1959
+				'text' => esc_html__('Select a Month/Year', 'event_espresso'),
1960
+				'id'   => '',
1961
+			],
1962
+		];
1963
+
1964
+		foreach ($regdtts as $regdtt) {
1965
+			$date      = $regdtt->reg_month . ' ' . $regdtt->reg_year;
1966
+			$options[] = [
1967
+				'text' => $date,
1968
+				'id'   => $date,
1969
+			];
1970
+		}
1971
+
1972
+		return self::select_input('month_range', $options, $cur_date);
1973
+	}
1974
+
1975
+
1976
+	/**
1977
+	 * generates a month/year dropdown selector for all events matching the given criteria
1978
+	 * Typically used for list table filter
1979
+	 *
1980
+	 * @param string $cur_date          any currently selected date can be entered here.
1981
+	 * @param string $status            "view" (i.e. all, today, month, draft)
1982
+	 * @param int    $evt_category      category event belongs to
1983
+	 * @param string $evt_active_status "upcoming", "expired", "active", or "inactive"
1984
+	 * @return string                    html
1985
+	 * @throws EE_Error
1986
+	 */
1987
+	public static function generate_event_months_dropdown(
1988
+		$cur_date = '',
1989
+		$status = null,
1990
+		$evt_category = null,
1991
+		$evt_active_status = null
1992
+	) {
1993
+		// determine what post_status our condition will have for the query.
1994
+		// phpcs:disable PSR2.ControlStructures.SwitchDeclaration.TerminatingComment
1995
+		switch ($status) {
1996
+			case 'month':
1997
+			case 'today':
1998
+			case null:
1999
+			case 'all':
2000
+				$where['Event.status'] = ['NOT IN', ['trash']];
2001
+				break;
2002
+			case 'draft':
2003
+				$where['Event.status'] = ['IN', ['draft', 'auto-draft']];
2004
+				break;
2005
+			default:
2006
+				$where['Event.status'] = $status;
2007
+		}
2008
+
2009
+		// phpcs:enable
2010
+
2011
+		// categories?
2012
+
2013
+
2014
+		if (! empty($evt_category)) {
2015
+			$where['Event.Term_Taxonomy.taxonomy'] = 'espresso_event_categories';
2016
+			$where['Event.Term_Taxonomy.term_id']  = $evt_category;
2017
+		}
2018
+
2019
+
2020
+		//      $where['DTT_is_primary'] = 1;
2021
+
2022
+		$DTTS = EEM_Datetime::instance()->get_dtt_months_and_years($where, $evt_active_status);
2023
+
2024
+		// let's setup vals for select input helper
2025
+		$options = [
2026
+			0 => [
2027
+				'text' => esc_html__('Select a Month/Year', 'event_espresso'),
2028
+				'id'   => "",
2029
+			],
2030
+		];
2031
+
2032
+
2033
+		// translate month and date
2034
+		global $wp_locale;
2035
+
2036
+		foreach ($DTTS as $DTT) {
2037
+			$localized_date = $wp_locale->get_month($DTT->dtt_month_num) . ' ' . $DTT->dtt_year;
2038
+			$id             = $DTT->dtt_month . ' ' . $DTT->dtt_year;
2039
+			$options[]      = [
2040
+				'text' => $localized_date,
2041
+				'id'   => $id,
2042
+			];
2043
+		}
2044
+
2045
+
2046
+		return self::select_input('month_range', $options, $cur_date);
2047
+	}
2048
+
2049
+
2050
+	/**
2051
+	 * generates the dropdown selector for event categories
2052
+	 * typically used as a filter on list tables.
2053
+	 *
2054
+	 * @param integer $current_cat currently selected category
2055
+	 * @return string               html for dropdown
2056
+	 * @throws EE_Error
2057
+	 * @throws ReflectionException
2058
+	 */
2059
+	public static function generate_event_category_dropdown($current_cat = -1)
2060
+	{
2061
+		$categories = EEM_Term::instance()->get_all_ee_categories(true);
2062
+		$options    = [
2063
+			'0' => [
2064
+				'text' => esc_html__('All Categories', 'event_espresso'),
2065
+				'id'   => -1,
2066
+			],
2067
+		];
2068
+
2069
+		// setup categories for dropdown
2070
+		foreach ($categories as $category) {
2071
+			$options[] = [
2072
+				'text' => $category->get('name'),
2073
+				'id'   => $category->ID(),
2074
+			];
2075
+		}
2076
+
2077
+		return self::select_input('EVT_CAT', $options, $current_cat);
2078
+	}
2079
+
2080
+
2081
+	/**
2082
+	 *    generate a submit button with or without it's own microform
2083
+	 *    this is the only way to create buttons that are compatible across all themes
2084
+	 *
2085
+	 * @access    public
2086
+	 * @param string      $url              - the form action
2087
+	 * @param string      $ID               - some kind of unique ID, appended with "-sbmt" for the input and "-frm"
2088
+	 *                                      for the form
2089
+	 * @param string      $class            - css classes (separated by spaces if more than one)
2090
+	 * @param string      $text             - what appears on the button
2091
+	 * @param string      $nonce_action     - if using nonces
2092
+	 * @param bool|string $input_only       - whether to print form header and footer. TRUE returns the input without
2093
+	 *                                      the form
2094
+	 * @param string      $extra_attributes - any extra attributes that need to be attached to the form input
2095
+	 * @return    string
2096
+	 */
2097
+	public static function submit_button(
2098
+		$url = '',
2099
+		$ID = '',
2100
+		$class = '',
2101
+		$text = '',
2102
+		$nonce_action = '',
2103
+		$input_only = false,
2104
+		$extra_attributes = ''
2105
+	) {
2106
+		$btn = '';
2107
+		if (empty($url) || empty($ID)) {
2108
+			return $btn;
2109
+		}
2110
+		$text = ! empty($text) ? $text : esc_html__('Submit', 'event_espresso');
2111
+		$btn  .= '<input id="' . $ID . '-btn" class="' . $class . '" '
2112
+				 . 'type="submit" value="' . $text . '" ' . $extra_attributes . '/>';
2113
+		if (! $input_only) {
2114
+			$btn_frm = '<form id="' . $ID . '-frm" method="POST" action="' . $url . '">';
2115
+			$btn_frm .= ! empty($nonce_action)
2116
+				? wp_nonce_field($nonce_action, $nonce_action . '_nonce', true, false)
2117
+				: '';
2118
+			$btn_frm .= $btn;
2119
+			$btn_frm .= '</form>';
2120
+			$btn     = $btn_frm;
2121
+			unset($btn_frm);
2122
+		}
2123
+		return $btn;
2124
+	}
2125 2125
 }
Please login to merge, or discard this patch.
Spacing   +135 added lines, -135 removed lines patch added patch discarded remove patch
@@ -108,8 +108,8 @@  discard block
 block discarded – undo
108 108
             $type           = $input_value['input'];
109 109
             $value          = $input_value['value'];
110 110
 
111
-            $id    = $form_id ? $form_id . '-' . $input_key : $input_key;
112
-            $class = $required ? 'required ' . $css_class : $css_class;
111
+            $id    = $form_id ? $form_id.'-'.$input_key : $input_key;
112
+            $class = $required ? 'required '.$css_class : $css_class;
113 113
 
114 114
             // what type of input are we dealing with ?
115 115
             switch ($type) {
@@ -161,8 +161,8 @@  discard block
 block discarded – undo
161 161
             }
162 162
         } // end foreach( $input_vars as $input_key => $input_value )
163 163
 
164
-        if (! empty($inputs)) {
165
-            $glue   = "
164
+        if ( ! empty($inputs)) {
165
+            $glue = "
166 166
                 </li>
167 167
                 <li>
168 168
                     ";
@@ -175,7 +175,7 @@  discard block
 block discarded – undo
175 175
             </ul>
176 176
             ";
177 177
         }
178
-        return $output . implode("\n", $hidden_inputs);
178
+        return $output.implode("\n", $hidden_inputs);
179 179
     }
180 180
 
181 181
 
@@ -256,7 +256,7 @@  discard block
 block discarded – undo
256 256
             // generate label
257 257
             $label = ! empty($label) ? self::adminLabel($id, $label, $required) : '';
258 258
             // generate field name
259
-            $name = ! empty($unique_id) ? $field_name . '[' . $unique_id . ']' : $field_name;
259
+            $name = ! empty($unique_id) ? $field_name.'['.$unique_id.']' : $field_name;
260 260
 
261 261
             // we determine what we're building based on the type
262 262
             switch ($type) {
@@ -267,14 +267,14 @@  discard block
 block discarded – undo
267 267
                         foreach ($value as $key => $val) {
268 268
                             $c_input .= self::adminMulti(
269 269
                                 $default,
270
-                                isset($classes[ $key ]) ? $classes[ $key ] : '',
271
-                                $field_name . '_' . $value,
270
+                                isset($classes[$key]) ? $classes[$key] : '',
271
+                                $field_name.'_'.$value,
272 272
                                 $name,
273 273
                                 $required,
274 274
                                 $tab_index,
275 275
                                 $type,
276 276
                                 $val,
277
-                                isset($labels[ $key ]) ? $labels[ $key ] : ''
277
+                                isset($labels[$key]) ? $labels[$key] : ''
278 278
                             );
279 279
                         }
280 280
                         $field = $c_input;
@@ -300,7 +300,7 @@  discard block
 block discarded – undo
300 300
                 case 'select':
301 301
                     $options = [];
302 302
                     foreach ($value as $key => $val) {
303
-                        $options[ $val ] = isset($labels[ $key ]) ? $labels[ $key ] : '';
303
+                        $options[$val] = isset($labels[$key]) ? $labels[$key] : '';
304 304
                     }
305 305
                     $field = self::adminSelect($default, $class, $id, $name, $required, $tab_index, $options);
306 306
                     break;
@@ -326,7 +326,7 @@  discard block
 block discarded – undo
326 326
                     $field = self::adminText($class, $id, $name, $required, $tab_index, $value);
327 327
             }
328 328
 
329
-            $form_fields[ $field_name ] = ['label' => $label, 'field' => $field . $extra_desc];
329
+            $form_fields[$field_name] = ['label' => $label, 'field' => $field.$extra_desc];
330 330
         }
331 331
 
332 332
         return $form_fields;
@@ -395,7 +395,7 @@  discard block
 block discarded – undo
395 395
         }
396 396
         $label = esc_html($label);
397 397
         $label_class = self::appendInputSizeClass('', $label);
398
-        $label_class = $label_class ? ' class="' . $label_class . '"' : '';
398
+        $label_class = $label_class ? ' class="'.$label_class.'"' : '';
399 399
         return "
400 400
         <label for='$id'{$label_class}>
401 401
             {$input}
@@ -544,7 +544,7 @@  discard block
 block discarded – undo
544 544
         $autosize = true
545 545
     ) {
546 546
         // if $values was submitted in the wrong format, convert it over
547
-        if (! empty($values) && (! array_key_exists(0, $values) || ! is_array($values[0]))) {
547
+        if ( ! empty($values) && ( ! array_key_exists(0, $values) || ! is_array($values[0]))) {
548 548
             $converted_values = [];
549 549
             foreach ($values as $id => $text) {
550 550
                 $converted_values[] = ['id' => $id, 'text' => $text];
@@ -553,19 +553,19 @@  discard block
 block discarded – undo
553 553
         }
554 554
 
555 555
         $field =
556
-            '<select id="' . EEH_Formatter::ee_tep_output_string($name)
557
-            . '" name="' . EEH_Formatter::ee_tep_output_string($name)
556
+            '<select id="'.EEH_Formatter::ee_tep_output_string($name)
557
+            . '" name="'.EEH_Formatter::ee_tep_output_string($name)
558 558
             . '"';
559 559
 
560 560
         if (EEH_Formatter::ee_tep_not_null($parameters)) {
561
-            $field .= ' ' . $parameters;
561
+            $field .= ' '.$parameters;
562 562
         }
563 563
         $class = $autosize ? self::appendInputSizeClass($class, $values) : '';
564 564
 
565
-        $field .= ' class="' . $class . '">';
565
+        $field .= ' class="'.$class.'">';
566 566
 
567
-        if (empty($default) && isset($GLOBALS[ $name ])) {
568
-            $default = stripslashes($GLOBALS[ $name ]);
567
+        if (empty($default) && isset($GLOBALS[$name])) {
568
+            $default = stripslashes($GLOBALS[$name]);
569 569
         }
570 570
 
571 571
         $field .= self::selectInputOption($values, $default);
@@ -581,7 +581,7 @@  discard block
 block discarded – undo
581 581
             $id = is_scalar($values['id']) ? $values['id'] : '';
582 582
             $text = is_scalar($values['text']) ? $values['text'] : '';
583 583
             $selected = $default == $values['id'] ? ' selected = "selected"' : '';
584
-            $html_class = isset($values['class']) ? ' class="' . $values['class'] . '"' : '';
584
+            $html_class = isset($values['class']) ? ' class="'.$values['class'].'"' : '';
585 585
             return "<option value='{$id}'{$selected}{$html_class}>{$text}</option>";
586 586
         }
587 587
         $options = '';
@@ -611,7 +611,7 @@  discard block
 block discarded – undo
611 611
             return $chars;
612 612
         }
613 613
         // not a primitive? return something big
614
-        if (! is_scalar($value)) {
614
+        if ( ! is_scalar($value)) {
615 615
             return 500;
616 616
         }
617 617
         return strlen((string) $value);
@@ -661,11 +661,11 @@  discard block
 block discarded – undo
661 661
         $after_question_group_questions  =
662 662
             apply_filters('FHEE__EEH_Form_Fields__generate_question_groups_html__after_question_group_questions', '');
663 663
 
664
-        if (! empty($question_groups)) {
664
+        if ( ! empty($question_groups)) {
665 665
             // loop thru question groups
666 666
             foreach ($question_groups as $QSG) {
667 667
                 // check that questions exist
668
-                if (! empty($QSG['QSG_questions'])) {
668
+                if ( ! empty($QSG['QSG_questions'])) {
669 669
                     // use fieldsets
670 670
                     $html .= "\n\t"
671 671
                              . '<'
@@ -690,7 +690,7 @@  discard block
 block discarded – undo
690 690
                     $html .= $before_question_group_questions;
691 691
                     // loop thru questions
692 692
                     foreach ($QSG['QSG_questions'] as $question) {
693
-                        $QFI  = new EE_Question_Form_Input(
693
+                        $QFI = new EE_Question_Form_Input(
694 694
                             $question['qst_obj'],
695 695
                             $question['ans_obj'],
696 696
                             $question
@@ -698,7 +698,7 @@  discard block
 block discarded – undo
698 698
                         $html .= self::generate_form_input($QFI);
699 699
                     }
700 700
                     $html .= $after_question_group_questions;
701
-                    $html .= "\n\t" . '</' . $group_wrapper . '>';
701
+                    $html .= "\n\t".'</'.$group_wrapper.'>';
702 702
                 }
703 703
             }
704 704
         }
@@ -738,25 +738,25 @@  discard block
 block discarded – undo
738 738
             'input_id'    => '',
739 739
             'input_class' => '',
740 740
         ];
741
-        $q_meta         = array_merge($default_q_meta, $q_meta);
741
+        $q_meta = array_merge($default_q_meta, $q_meta);
742 742
 
743
-        if (! empty($question_groups)) {
743
+        if ( ! empty($question_groups)) {
744 744
             // loop thru question groups
745 745
             foreach ($question_groups as $QSG) {
746 746
                 if ($QSG instanceof EE_Question_Group) {
747 747
                     // check that questions exist
748 748
 
749 749
                     $where = ['QST_deleted' => 0];
750
-                    if (! $from_admin) {
750
+                    if ( ! $from_admin) {
751 751
                         $where['QST_admin_only'] = 0;
752 752
                     }
753 753
                     $questions =
754 754
                         $QSG->questions([$where, 'order_by' => ['Question_Group_Question.QGQ_order' => 'ASC']]);
755
-                    if (! empty($questions)) {
755
+                    if ( ! empty($questions)) {
756 756
                         // use fieldsets
757 757
                         $html .= "\n\t"
758
-                                 . '<' . $group_wrapper . ' class="espresso-question-group-wrap" '
759
-                                 . 'id="' . $QSG->get('QSG_identifier') . '">';
758
+                                 . '<'.$group_wrapper.' class="espresso-question-group-wrap" '
759
+                                 . 'id="'.$QSG->get('QSG_identifier').'">';
760 760
                         // group_name
761 761
                         if ($QSG->show_group_name()) {
762 762
                             $html .= "\n\t\t"
@@ -781,21 +781,21 @@  discard block
 block discarded – undo
781 781
                             /** @var RequestInterface $request */
782 782
                             $request      = LoaderFactory::getLoader()->getShared(RequestInterface::class);
783 783
                             $request_qstn = $request->getRequestParam('qstn', [], 'string', true);
784
-                            if (! empty($request_qstn) && isset($q_meta['input_id']) && isset($q_meta['att_nmbr'])) {
784
+                            if ( ! empty($request_qstn) && isset($q_meta['input_id']) && isset($q_meta['att_nmbr'])) {
785 785
                                 // check for answer in $request_qstn in case we are reprocessing a form after an error
786
-                                if (isset($request_qstn[ $q_meta['input_id'] ][ $qstn_id ])) {
787
-                                    $answer = is_array($request_qstn[ $q_meta['input_id'] ][ $qstn_id ])
788
-                                        ? $request_qstn[ $q_meta['input_id'] ][ $qstn_id ]
789
-                                        : sanitize_text_field($request_qstn[ $q_meta['input_id'] ][ $qstn_id ]);
786
+                                if (isset($request_qstn[$q_meta['input_id']][$qstn_id])) {
787
+                                    $answer = is_array($request_qstn[$q_meta['input_id']][$qstn_id])
788
+                                        ? $request_qstn[$q_meta['input_id']][$qstn_id]
789
+                                        : sanitize_text_field($request_qstn[$q_meta['input_id']][$qstn_id]);
790 790
                                 }
791 791
                             } elseif (isset($q_meta['attendee']) && $q_meta['attendee']) {
792 792
                                 // attendee data from the session
793 793
                                 $answer =
794
-                                    isset($q_meta['attendee'][ $qstn_id ]) ? $q_meta['attendee'][ $qstn_id ] : null;
794
+                                    isset($q_meta['attendee'][$qstn_id]) ? $q_meta['attendee'][$qstn_id] : null;
795 795
                             }
796 796
 
797 797
 
798
-                            $QFI  = new EE_Question_Form_Input(
798
+                            $QFI = new EE_Question_Form_Input(
799 799
                                 $QST,
800 800
                                 EE_Answer::new_instance(
801 801
                                     [
@@ -810,7 +810,7 @@  discard block
 block discarded – undo
810 810
                             $html .= self::generate_form_input($QFI);
811 811
                         }
812 812
                         $html .= $after_question_group_questions;
813
-                        $html .= "\n\t" . '</' . $group_wrapper . '>';
813
+                        $html .= "\n\t".'</'.$group_wrapper.'>';
814 814
                     }
815 815
                 }
816 816
             }
@@ -858,7 +858,7 @@  discard block
 block discarded – undo
858 858
             $QFI->get('QST_required_text') != ''
859 859
                 ? $QFI->get('QST_required_text')
860 860
                 : esc_html__('This field is required', 'event_espresso');
861
-        $required_text     = $QST_required
861
+        $required_text = $QST_required
862 862
             ? "\n\t\t\t"
863 863
               . '<div class="required-text hidden">'
864 864
               . self::prep_answer($required_text, $use_html_entities)
@@ -994,7 +994,7 @@  discard block
 block discarded – undo
994 994
     ): string {
995 995
         $for   = ! empty($name) ? " for='{$name}'" : '';
996 996
         $class = ! empty($label_class) ? " class='{$label_class}'" : '';
997
-        $label = self::prep_question($question) . $required_label;
997
+        $label = self::prep_question($question).$required_label;
998 998
         $label_html = "
999 999
             {$required_text}
1000 1000
             <label{$for}{$class}>{$label}</label>";
@@ -1050,7 +1050,7 @@  discard block
 block discarded – undo
1050 1050
         $extra_attributes = ''
1051 1051
     ) {
1052 1052
         // need these
1053
-        if (! $question || ! $name) {
1053
+        if ( ! $question || ! $name) {
1054 1054
             return null;
1055 1055
         }
1056 1056
         // prep the answer
@@ -1062,9 +1062,9 @@  discard block
 block discarded – undo
1062 1062
         // ya gots ta have style man!!!
1063 1063
         $txt_class = is_admin() ? 'regular-text' : 'espresso-text-inp';
1064 1064
         $class     = empty($class) ? $txt_class : $class;
1065
-        $class     .= ! empty($system_ID) ? ' ' . $system_ID : '';
1065
+        $class .= ! empty($system_ID) ? ' '.$system_ID : '';
1066 1066
         $class = self::appendInputSizeClass($class, $answer);
1067
-        $class .= ! empty($required['class']) ? ' ' . $required['class'] : '';
1067
+        $class .= ! empty($required['class']) ? ' '.$required['class'] : '';
1068 1068
         $extra_attributes = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', $extra_attributes);
1069 1069
 
1070 1070
         $label_html = self::label($question, $required_text, $required['label'], $name, $label_class);
@@ -1077,18 +1077,18 @@  discard block
 block discarded – undo
1077 1077
             $name
1078 1078
         );
1079 1079
 
1080
-        $input_html = $mobile_label . '
1080
+        $input_html = $mobile_label.'
1081 1081
             <input  type="text"
1082
-                    name="' . $name . '"
1083
-                    id="' . $id . '"
1084
-                    class="' . trim($class) . '"
1085
-                    value="' . esc_attr($answer) . '"
1086
-                    aria-label="' . esc_attr($required['msg']) . '"
1087
-                    ' . $disabled . ' ' . $extra_attributes . '
1082
+                    name="' . $name.'"
1083
+                    id="' . $id.'"
1084
+                    class="' . trim($class).'"
1085
+                    value="' . esc_attr($answer).'"
1086
+                    aria-label="' . esc_attr($required['msg']).'"
1087
+                    ' . $disabled.' '.$extra_attributes.'
1088 1088
             />';
1089 1089
 
1090 1090
         $input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1091
-        return $label_html . $input_html;
1091
+        return $label_html.$input_html;
1092 1092
     }
1093 1093
 
1094 1094
 
@@ -1123,7 +1123,7 @@  discard block
 block discarded – undo
1123 1123
         $add_mobile_label = false
1124 1124
     ) {
1125 1125
         // need these
1126
-        if (! $question || ! $name) {
1126
+        if ( ! $question || ! $name) {
1127 1127
             return null;
1128 1128
         }
1129 1129
         // prep the answer
@@ -1137,9 +1137,9 @@  discard block
 block discarded – undo
1137 1137
         // set disabled tag
1138 1138
         $disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1139 1139
         // ya gots ta have style man!!!
1140
-        $class     .= ! empty($system_ID) ? ' ' . $system_ID : '';
1141
-        $class     .= ! empty($required['class']) ? ' ' . $required['class'] : '';
1142
-        $extra     = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1140
+        $class     .= ! empty($system_ID) ? ' '.$system_ID : '';
1141
+        $class     .= ! empty($required['class']) ? ' '.$required['class'] : '';
1142
+        $extra = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1143 1143
 
1144 1144
         $label_html   = self::label($question, $required_text, $required['label'], $name, $label_class);
1145 1145
         $mobile_label = self::mobileLabel(
@@ -1152,14 +1152,14 @@  discard block
 block discarded – undo
1152 1152
         );
1153 1153
 
1154 1154
         $input_html = $mobile_label
1155
-            . '<textarea name="' . $name . '" id="' . $id . '" class="' . trim($class) . '" '
1156
-            . 'rows="' . $dimensions['rows'] . '" cols="' . $dimensions['cols'] . '"  '
1157
-            . 'aria-label="' . $required['msg'] . '" ' . $disabled . ' ' . $extra . '>'
1155
+            . '<textarea name="'.$name.'" id="'.$id.'" class="'.trim($class).'" '
1156
+            . 'rows="'.$dimensions['rows'].'" cols="'.$dimensions['cols'].'"  '
1157
+            . 'aria-label="'.$required['msg'].'" '.$disabled.' '.$extra.'>'
1158 1158
              . esc_textarea($answer)
1159 1159
               . '</textarea>';
1160 1160
 
1161 1161
         $input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1162
-        return $label_html . $input_html;
1162
+        return $label_html.$input_html;
1163 1163
     }
1164 1164
 
1165 1165
 
@@ -1197,7 +1197,7 @@  discard block
 block discarded – undo
1197 1197
     ) {
1198 1198
 
1199 1199
         // need these
1200
-        if (! $question || ! $name || ! $options || empty($options) || ! is_array($options)) {
1200
+        if ( ! $question || ! $name || ! $options || empty($options) || ! is_array($options)) {
1201 1201
             return null;
1202 1202
         }
1203 1203
         // prep the answer
@@ -1209,9 +1209,9 @@  discard block
 block discarded – undo
1209 1209
         // set disabled tag
1210 1210
         $disabled = $answer === null || ! $disabled ? '' : ' disabled="disabled"';
1211 1211
         // ya gots ta have style man!!!
1212
-        $class     .= ! empty($system_ID) ? ' ' . $system_ID : '';
1212
+        $class .= ! empty($system_ID) ? ' '.$system_ID : '';
1213 1213
         $class = self::appendInputSizeClass($class, $options);
1214
-        $extra     = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1214
+        $extra = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1215 1215
 
1216 1216
         $label_html   = self::label($question, $required_text, $required['label'], $name, $label_class);
1217 1217
         $mobile_label = self::mobileLabel(
@@ -1224,16 +1224,16 @@  discard block
 block discarded – undo
1224 1224
         );
1225 1225
 
1226 1226
         $input_html = $mobile_label
1227
-            . '<select name="' . $name . '" id="' . $id . '" class="' . trim($class) . ' ' . $required['class'] . '" '
1228
-            . 'aria-label="' . esc_attr($required['msg']) . '"' . $disabled . ' ' . $extra . '>';
1227
+            . '<select name="'.$name.'" id="'.$id.'" class="'.trim($class).' '.$required['class'].'" '
1228
+            . 'aria-label="'.esc_attr($required['msg']).'"'.$disabled.' '.$extra.'>';
1229 1229
         // recursively count array elements, to determine total number of options
1230 1230
         $only_option = count($options, 1) == 1;
1231
-        if (! $only_option) {
1231
+        if ( ! $only_option) {
1232 1232
             // if there is NO answer set and there are multiple options to choose from, then set the "please select" message as selected
1233
-            $selected   = $answer === null ? ' selected' : '';
1233
+            $selected = $answer === null ? ' selected' : '';
1234 1234
             $input_html .= $add_please_select_option
1235 1235
                 ? "\n\t\t\t\t"
1236
-                  . '<option value=""' . $selected . '>'
1236
+                  . '<option value=""'.$selected.'>'
1237 1237
                   . esc_html__(' - please select - ', 'event_espresso')
1238 1238
                   . '</option>'
1239 1239
                 : '';
@@ -1256,7 +1256,7 @@  discard block
 block discarded – undo
1256 1256
                 );
1257 1257
         }
1258 1258
 
1259
-        $input_html .= "\n\t\t\t" . '</select>';
1259
+        $input_html .= "\n\t\t\t".'</select>';
1260 1260
 
1261 1261
         $input_html =
1262 1262
             apply_filters(
@@ -1271,7 +1271,7 @@  discard block
 block discarded – undo
1271 1271
             );
1272 1272
 
1273 1273
         $input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1274
-        return $label_html . $input_html;
1274
+        return $label_html.$input_html;
1275 1275
     }
1276 1276
 
1277 1277
 
@@ -1289,11 +1289,11 @@  discard block
 block discarded – undo
1289 1289
      */
1290 1290
     private static function _generate_select_option_group($opt_group, $QSOs, $answer, $use_html_entities = true)
1291 1291
     {
1292
-        $html = "\n\t\t\t\t" . '<optgroup label="' . self::prep_option_value($opt_group) . '">';
1292
+        $html = "\n\t\t\t\t".'<optgroup label="'.self::prep_option_value($opt_group).'">';
1293 1293
         foreach ($QSOs as $QSO) {
1294 1294
             $html .= self::_generate_select_option($QSO->value(), $QSO->desc(), $answer, false, $use_html_entities);
1295 1295
         }
1296
-        $html .= "\n\t\t\t\t" . '</optgroup>';
1296
+        $html .= "\n\t\t\t\t".'</optgroup>';
1297 1297
         return $html;
1298 1298
     }
1299 1299
 
@@ -1320,7 +1320,7 @@  discard block
 block discarded – undo
1320 1320
         $value    = ! empty($value) ? $value : $key;
1321 1321
         $selected = ($answer == $key || $only_option) ? 'selected' : '';
1322 1322
         return "\n\t\t\t\t"
1323
-               . '<option value="' . self::prep_option_value($key) . '" ' . $selected . '> '
1323
+               . '<option value="'.self::prep_option_value($key).'" '.$selected.'> '
1324 1324
                . $value
1325 1325
                . '&nbsp;&nbsp;&nbsp;</option>';
1326 1326
     }
@@ -1365,7 +1365,7 @@  discard block
 block discarded – undo
1365 1365
         $add_mobile_label = false
1366 1366
     ) {
1367 1367
         // need these
1368
-        if (! $question || ! $name || ! $options || empty($options) || ! is_array($options)) {
1368
+        if ( ! $question || ! $name || ! $options || empty($options) || ! is_array($options)) {
1369 1369
             return null;
1370 1370
         }
1371 1371
         // prep the answer
@@ -1389,49 +1389,49 @@  discard block
 block discarded – undo
1389 1389
         );
1390 1390
 
1391 1391
         $input_html = $mobile_label
1392
-            . '<ul id="' . $id . '-ul" class="espresso-radio-btn-options-ul ' . $class . '-ul">';
1392
+            . '<ul id="'.$id.'-ul" class="espresso-radio-btn-options-ul '.$class.'-ul">';
1393 1393
 
1394
-        $class .= ! empty($system_ID) ? ' ' . $system_ID : '';
1395
-        $class .= ! empty($required['class']) ? ' ' . $required['class'] : '';
1394
+        $class .= ! empty($system_ID) ? ' '.$system_ID : '';
1395
+        $class .= ! empty($required['class']) ? ' '.$required['class'] : '';
1396 1396
 
1397 1397
         foreach ($options as $OPT) {
1398 1398
             if ($OPT instanceof EE_Question_Option) {
1399 1399
                 $value   = self::prep_option_value($OPT->value());
1400 1400
                 $label   = $use_desc_4_label ? $OPT->desc() : $OPT->value();
1401 1401
                 $size    = $use_desc_4_label
1402
-                    ? self::get_label_size_class($OPT->value() . ' ' . $OPT->desc())
1402
+                    ? self::get_label_size_class($OPT->value().' '.$OPT->desc())
1403 1403
                     : self::get_label_size_class($OPT->value());
1404
-                $desc    = $OPT->desc();// no self::prep_answer
1404
+                $desc    = $OPT->desc(); // no self::prep_answer
1405 1405
                 $answer  = is_numeric($value) && empty($answer) ? 0 : $answer;
1406 1406
                 $checked = (string) $value == (string) $answer ? ' checked' : '';
1407
-                $opt     = '-' . sanitize_key($value);
1407
+                $opt     = '-'.sanitize_key($value);
1408 1408
 
1409
-                $input_html .= "\n\t\t\t\t" . '<li' . $size . '>';
1410
-                $input_html .= "\n\t\t\t\t\t" . '<label class="' . $radio_class . ' espresso-radio-btn-lbl">';
1411
-                $input_html .= $label_b4 ? "\n\t\t\t\t\t\t" . '<span>' . $label . '</span>&nbsp;&nbsp;' : '';
1409
+                $input_html .= "\n\t\t\t\t".'<li'.$size.'>';
1410
+                $input_html .= "\n\t\t\t\t\t".'<label class="'.$radio_class.' espresso-radio-btn-lbl">';
1411
+                $input_html .= $label_b4 ? "\n\t\t\t\t\t\t".'<span>'.$label.'</span>&nbsp;&nbsp;' : '';
1412 1412
                 $input_html .= "\n\t\t\t\t\t\t"
1413
-                               . '<input type="radio" name="' . $name . '" id="' . $id . $opt . '" '
1414
-                               . 'class="' . $class . '" value="' . $value . '" '
1415
-                               . 'aria-label="' . esc_attr($required['msg']) . '" ' . $disabled
1416
-                               . $checked . ' ' . $extra . '/>';
1413
+                               . '<input type="radio" name="'.$name.'" id="'.$id.$opt.'" '
1414
+                               . 'class="'.$class.'" value="'.$value.'" '
1415
+                               . 'aria-label="'.esc_attr($required['msg']).'" '.$disabled
1416
+                               . $checked.' '.$extra.'/>';
1417 1417
                 $input_html .= ! $label_b4
1418 1418
                     ? "\n\t\t\t\t\t\t"
1419 1419
                       . '&nbsp;&nbsp;<span class="espresso-radio-btn-desc">'
1420 1420
                       . $label
1421 1421
                       . '</span>'
1422 1422
                     : '';
1423
-                $input_html .= "\n\t\t\t\t\t" . '</label>';
1423
+                $input_html .= "\n\t\t\t\t\t".'</label>';
1424 1424
                 $input_html .= $use_desc_4_label
1425 1425
                     ? ''
1426
-                    : '<span class="espresso-radio-btn-option-desc small-text grey-text">' . $desc . '</span>';
1427
-                $input_html .= "\n\t\t\t\t" . '</li>';
1426
+                    : '<span class="espresso-radio-btn-option-desc small-text grey-text">'.$desc.'</span>';
1427
+                $input_html .= "\n\t\t\t\t".'</li>';
1428 1428
             }
1429 1429
         }
1430 1430
 
1431
-        $input_html .= "\n\t\t\t" . '</ul>';
1431
+        $input_html .= "\n\t\t\t".'</ul>';
1432 1432
 
1433 1433
         $input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1434
-        return $label_html . $input_html;
1434
+        return $label_html.$input_html;
1435 1435
     }
1436 1436
 
1437 1437
 
@@ -1467,7 +1467,7 @@  discard block
 block discarded – undo
1467 1467
         $add_mobile_label = false
1468 1468
     ) {
1469 1469
         // need these
1470
-        if (! $question || ! $name || ! $options || empty($options) || ! is_array($options)) {
1470
+        if ( ! $question || ! $name || ! $options || empty($options) || ! is_array($options)) {
1471 1471
             return null;
1472 1472
         }
1473 1473
         $answer = maybe_unserialize($answer);
@@ -1477,7 +1477,7 @@  discard block
 block discarded – undo
1477 1477
 
1478 1478
         foreach ($answer as $key => $value) {
1479 1479
             $key            = self::prep_option_value($key);
1480
-            $answer[ $key ] = self::prep_answer($value, $use_html_entities);
1480
+            $answer[$key] = self::prep_answer($value, $use_html_entities);
1481 1481
         }
1482 1482
 
1483 1483
         // prep the required array
@@ -1499,42 +1499,42 @@  discard block
 block discarded – undo
1499 1499
         );
1500 1500
 
1501 1501
         $input_html = $mobile_label
1502
-            . '<ul id="' . $id . '-ul" class="espresso-checkbox-options-ul ' . $class . '-ul">';
1502
+            . '<ul id="'.$id.'-ul" class="espresso-checkbox-options-ul '.$class.'-ul">';
1503 1503
 
1504
-        $class .= ! empty($system_ID) ? ' ' . $system_ID : '';
1505
-        $class .= ! empty($required['class']) ? ' ' . $required['class'] : '';
1504
+        $class .= ! empty($system_ID) ? ' '.$system_ID : '';
1505
+        $class .= ! empty($required['class']) ? ' '.$required['class'] : '';
1506 1506
 
1507 1507
         foreach ($options as $OPT) {
1508
-            $value = $OPT->value();// self::prep_option_value( $OPT->value() );
1509
-            $size  = self::get_label_size_class($OPT->value() . ' ' . $OPT->desc());
1508
+            $value = $OPT->value(); // self::prep_option_value( $OPT->value() );
1509
+            $size  = self::get_label_size_class($OPT->value().' '.$OPT->desc());
1510 1510
             $text  = self::prep_answer($OPT->value());
1511 1511
             $desc  = $OPT->desc();
1512
-            $opt   = '-' . sanitize_key($value);
1512
+            $opt   = '-'.sanitize_key($value);
1513 1513
 
1514 1514
             $checked = is_array($answer) && in_array($text, $answer) ? ' checked' : '';
1515 1515
 
1516
-            $input_html .= "\n\t\t\t\t" . '<li' . $size . '>';
1517
-            $input_html .= "\n\t\t\t\t\t" . '<label class="' . $radio_class . ' espresso-checkbox-lbl">';
1518
-            $input_html .= $label_b4 ? "\n\t\t\t\t\t\t" . '<span>' . $text . '</span>&nbsp;&nbsp;' : '';
1516
+            $input_html .= "\n\t\t\t\t".'<li'.$size.'>';
1517
+            $input_html .= "\n\t\t\t\t\t".'<label class="'.$radio_class.' espresso-checkbox-lbl">';
1518
+            $input_html .= $label_b4 ? "\n\t\t\t\t\t\t".'<span>'.$text.'</span>&nbsp;&nbsp;' : '';
1519 1519
             $input_html .= "\n\t\t\t\t\t\t"
1520
-                           . '<input type="checkbox" name="' . $name . '[' . $OPT->ID() . ']" '
1521
-                           . 'id="' . $id . $opt . '" class="' . $class . '" value="' . $value . '" '
1522
-                           . 'aria-label="' . esc_attr($required['msg']) . '" ' . $disabled . $checked . ' ' . $extra . '/>';
1523
-            $input_html .= ! $label_b4 ? "\n\t\t\t\t\t\t" . '&nbsp;&nbsp;<span>' . $text . '</span>' : '';
1524
-            $input_html .= "\n\t\t\t\t\t" . '</label>';
1525
-            if (! empty($desc) && $desc != $text) {
1520
+                           . '<input type="checkbox" name="'.$name.'['.$OPT->ID().']" '
1521
+                           . 'id="'.$id.$opt.'" class="'.$class.'" value="'.$value.'" '
1522
+                           . 'aria-label="'.esc_attr($required['msg']).'" '.$disabled.$checked.' '.$extra.'/>';
1523
+            $input_html .= ! $label_b4 ? "\n\t\t\t\t\t\t".'&nbsp;&nbsp;<span>'.$text.'</span>' : '';
1524
+            $input_html .= "\n\t\t\t\t\t".'</label>';
1525
+            if ( ! empty($desc) && $desc != $text) {
1526 1526
                 $input_html .= "\n\t\t\t\t\t"
1527 1527
                                . ' &nbsp; <br/><div class="espresso-checkbox-option-desc small-text grey-text">'
1528 1528
                                . $desc
1529 1529
                                . '</div>';
1530 1530
             }
1531
-            $input_html .= "\n\t\t\t\t" . '</li>';
1531
+            $input_html .= "\n\t\t\t\t".'</li>';
1532 1532
         }
1533 1533
 
1534
-        $input_html .= "\n\t\t\t" . '</ul>';
1534
+        $input_html .= "\n\t\t\t".'</ul>';
1535 1535
 
1536 1536
         $input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1537
-        return $label_html . $input_html;
1537
+        return $label_html.$input_html;
1538 1538
     }
1539 1539
 
1540 1540
 
@@ -1567,7 +1567,7 @@  discard block
 block discarded – undo
1567 1567
         $add_mobile_label = false
1568 1568
     ) {
1569 1569
         // need these
1570
-        if (! $question || ! $name) {
1570
+        if ( ! $question || ! $name) {
1571 1571
             return null;
1572 1572
         }
1573 1573
         // prep the answer
@@ -1579,7 +1579,7 @@  discard block
 block discarded – undo
1579 1579
         // ya gots ta have style man!!!
1580 1580
         $txt_class = is_admin() ? 'regular-text' : 'espresso-datepicker-inp';
1581 1581
         $class     = empty($class) ? $txt_class : $class;
1582
-        $class     .= ! empty($system_ID) ? ' ' . $system_ID : '';
1582
+        $class .= ! empty($system_ID) ? ' '.$system_ID : '';
1583 1583
         $class = self::appendInputSizeClass($class, $answer);
1584 1584
         $extra     = apply_filters('FHEE__EEH_Form_Fields__additional_form_field_attributes', '');
1585 1585
 
@@ -1594,14 +1594,14 @@  discard block
 block discarded – undo
1594 1594
         );
1595 1595
 
1596 1596
         $input_html = $mobile_label
1597
-            . '<input type="text" name="' . $name . '" id="' . $id . '" '
1598
-            . 'class="' . $class . ' ' . $required['class'] . ' datepicker" value="' . $answer . '"  '
1599
-            . 'aria-label="' . esc_attr($required['msg']) . '" ' . $disabled . ' ' . $extra . '/>';
1597
+            . '<input type="text" name="'.$name.'" id="'.$id.'" '
1598
+            . 'class="'.$class.' '.$required['class'].' datepicker" value="'.$answer.'"  '
1599
+            . 'aria-label="'.esc_attr($required['msg']).'" '.$disabled.' '.$extra.'/>';
1600 1600
 
1601 1601
         // enqueue scripts
1602 1602
         wp_register_style(
1603 1603
             'espresso-ui-theme',
1604
-            EE_GLOBAL_ASSETS_URL . 'css/espresso-ui-theme/jquery-ui-1.10.3.custom.min.css',
1604
+            EE_GLOBAL_ASSETS_URL.'css/espresso-ui-theme/jquery-ui-1.10.3.custom.min.css',
1605 1605
             [],
1606 1606
             EVENT_ESPRESSO_VERSION
1607 1607
         );
@@ -1609,7 +1609,7 @@  discard block
 block discarded – undo
1609 1609
         wp_enqueue_script('jquery-ui-datepicker');
1610 1610
 
1611 1611
         $input_html = apply_filters('FHEE__EEH_Form_Fields__input_html', $input_html, $label_html, $id);
1612
-        return $label_html . $input_html;
1612
+        return $label_html.$input_html;
1613 1613
     }
1614 1614
 
1615 1615
 
@@ -1636,7 +1636,7 @@  discard block
 block discarded – undo
1636 1636
     public static function hidden_input($name, $value, $id = '')
1637 1637
     {
1638 1638
         $id = ! empty($id) ? $id : $name;
1639
-        return '<input id="' . $id . '" type="hidden" name="' . $name . '" value="' . $value . '"/>';
1639
+        return '<input id="'.$id.'" type="hidden" name="'.$name.'" value="'.$value.'"/>';
1640 1640
     }
1641 1641
 
1642 1642
 
@@ -1681,7 +1681,7 @@  discard block
 block discarded – undo
1681 1681
         $prepped_answer_options = [];
1682 1682
         if (is_array($QSOs) && ! empty($QSOs)) {
1683 1683
             foreach ($QSOs as $key => $QSO) {
1684
-                if (! $QSO instanceof EE_Question_Option) {
1684
+                if ( ! $QSO instanceof EE_Question_Option) {
1685 1685
                     $QSO = EE_Question_Option::new_instance(
1686 1686
                         [
1687 1687
                             'QSO_value' => is_array($QSO) && isset($QSO['id'])
@@ -1694,7 +1694,7 @@  discard block
 block discarded – undo
1694 1694
                     );
1695 1695
                 }
1696 1696
                 if ($QSO->opt_group()) {
1697
-                    $prepped_answer_options[ $QSO->opt_group() ][] = $QSO;
1697
+                    $prepped_answer_options[$QSO->opt_group()][] = $QSO;
1698 1698
                 } else {
1699 1699
                     $prepped_answer_options[] = $QSO;
1700 1700
                 }
@@ -1906,7 +1906,7 @@  discard block
 block discarded – undo
1906 1906
         $options = [];
1907 1907
         for ($x = 1; $x <= 12; $x++) {
1908 1908
             $mm             = str_pad($x, 2, '0', STR_PAD_LEFT);
1909
-            $options[ $mm ] = $mm;
1909
+            $options[$mm] = $mm;
1910 1910
         }
1911 1911
         return EEH_Form_Fields::prep_answer_options($options);
1912 1912
     }
@@ -1924,7 +1924,7 @@  discard block
 block discarded – undo
1924 1924
         $next_decade  = $current_year + 10;
1925 1925
         for ($x = $current_year; $x <= $next_decade; $x++) {
1926 1926
             $yy             = str_pad($x, 2, '0', STR_PAD_LEFT);
1927
-            $options[ $yy ] = $yy;
1927
+            $options[$yy] = $yy;
1928 1928
         }
1929 1929
         return EEH_Form_Fields::prep_answer_options($options);
1930 1930
     }
@@ -1943,7 +1943,7 @@  discard block
 block discarded – undo
1943 1943
     public static function generate_registration_months_dropdown($cur_date = '', $status = '', $evt_category = 0)
1944 1944
     {
1945 1945
         $_where = [];
1946
-        if (! empty($status)) {
1946
+        if ( ! empty($status)) {
1947 1947
             $_where['STS_ID'] = $status;
1948 1948
         }
1949 1949
 
@@ -1962,7 +1962,7 @@  discard block
 block discarded – undo
1962 1962
         ];
1963 1963
 
1964 1964
         foreach ($regdtts as $regdtt) {
1965
-            $date      = $regdtt->reg_month . ' ' . $regdtt->reg_year;
1965
+            $date      = $regdtt->reg_month.' '.$regdtt->reg_year;
1966 1966
             $options[] = [
1967 1967
                 'text' => $date,
1968 1968
                 'id'   => $date,
@@ -2011,7 +2011,7 @@  discard block
 block discarded – undo
2011 2011
         // categories?
2012 2012
 
2013 2013
 
2014
-        if (! empty($evt_category)) {
2014
+        if ( ! empty($evt_category)) {
2015 2015
             $where['Event.Term_Taxonomy.taxonomy'] = 'espresso_event_categories';
2016 2016
             $where['Event.Term_Taxonomy.term_id']  = $evt_category;
2017 2017
         }
@@ -2034,8 +2034,8 @@  discard block
 block discarded – undo
2034 2034
         global $wp_locale;
2035 2035
 
2036 2036
         foreach ($DTTS as $DTT) {
2037
-            $localized_date = $wp_locale->get_month($DTT->dtt_month_num) . ' ' . $DTT->dtt_year;
2038
-            $id             = $DTT->dtt_month . ' ' . $DTT->dtt_year;
2037
+            $localized_date = $wp_locale->get_month($DTT->dtt_month_num).' '.$DTT->dtt_year;
2038
+            $id             = $DTT->dtt_month.' '.$DTT->dtt_year;
2039 2039
             $options[]      = [
2040 2040
                 'text' => $localized_date,
2041 2041
                 'id'   => $id,
@@ -2108,16 +2108,16 @@  discard block
 block discarded – undo
2108 2108
             return $btn;
2109 2109
         }
2110 2110
         $text = ! empty($text) ? $text : esc_html__('Submit', 'event_espresso');
2111
-        $btn  .= '<input id="' . $ID . '-btn" class="' . $class . '" '
2112
-                 . 'type="submit" value="' . $text . '" ' . $extra_attributes . '/>';
2113
-        if (! $input_only) {
2114
-            $btn_frm = '<form id="' . $ID . '-frm" method="POST" action="' . $url . '">';
2111
+        $btn .= '<input id="'.$ID.'-btn" class="'.$class.'" '
2112
+                 . 'type="submit" value="'.$text.'" '.$extra_attributes.'/>';
2113
+        if ( ! $input_only) {
2114
+            $btn_frm = '<form id="'.$ID.'-frm" method="POST" action="'.$url.'">';
2115 2115
             $btn_frm .= ! empty($nonce_action)
2116
-                ? wp_nonce_field($nonce_action, $nonce_action . '_nonce', true, false)
2116
+                ? wp_nonce_field($nonce_action, $nonce_action.'_nonce', true, false)
2117 2117
                 : '';
2118 2118
             $btn_frm .= $btn;
2119 2119
             $btn_frm .= '</form>';
2120
-            $btn     = $btn_frm;
2120
+            $btn = $btn_frm;
2121 2121
             unset($btn_frm);
2122 2122
         }
2123 2123
         return $btn;
Please login to merge, or discard this patch.
core/helpers/EEH_Export.helper.php 2 patches
Indentation   +167 added lines, -167 removed lines patch added patch discarded remove patch
@@ -13,171 +13,171 @@
 block discarded – undo
13 13
  */
14 14
 class EEH_Export
15 15
 {
16
-    /**
17
-     * Gets the 'normal' column named for fields
18
-     * @param EE_Model_Field_Base $field
19
-     * @return string
20
-     * @throws EE_Error
21
-     */
22
-    public static function get_column_name_for_field(EE_Model_Field_Base $field)
23
-    {
24
-        $column_name = wp_specialchars_decode($field->get_nicename(), ENT_QUOTES);
25
-        if (
26
-            apply_filters(
27
-                'FHEE__EEH_Export__get_column_name_for_field__add_field_name',
28
-                false,
29
-                $column_name,
30
-                $field
31
-            )
32
-        ) {
33
-            $column_name .= "["
34
-                . wp_specialchars_decode($field->get_name(), ENT_QUOTES)
35
-                . "]";
36
-        }
37
-        return $column_name;
38
-    }
39
-
40
-
41
-    /**
42
-     * Writes $data to the csv file open in $filehandle. uses the array indices of $data for column headers
43
-     *
44
-     * @param string $filepath
45
-     * @param array  $data                  2D array,first numerically-indexed,
46
-     *                                      and next-level-down preferably indexed by string
47
-     * @param bool   $write_column_headers  whether or not we should add the keys in the bottom-most array
48
-     *                                      as a row for headers in the CSV.
49
-     *                                      Eg, if $data looked like:
50
-     *                                          array(
51
-     *                                              0=>array('EVT_ID'=>1,'EVT_name'=>'monkey'...),
52
-     *                                              1=>array(...,...)
53
-     *                                          )
54
-     * @param bool   $headers_only          if true then we won't print any data, just headers. defaults to false
55
-     * @return boolean                      if we successfully wrote to the CSV or not. If there's no $data,
56
-     *                                      we consider that a success (because we wrote everything there was...nothing)
57
-     * @throws EE_Error
58
-     */
59
-    public static function write_data_array_to_csv(
60
-        string $filepath,
61
-        array $data,
62
-        bool $write_column_headers = true,
63
-        bool $headers_only = false
64
-    ) {
65
-        // determine if $data is actually a 2d array
66
-        if ($data && is_array($data) && is_array(EEH_Array::get_one_item_from_array($data))) {
67
-            // make sure top level is numerically indexed,
68
-            if (EEH_Array::is_associative_array($data)) {
69
-                throw new EE_Error(sprintf(esc_html__("top-level array must be numerically indexed. Does these look like numbers to you? %s", "event_espresso"), implode(",", array_keys($data))));
70
-            }
71
-            $new_file_contents = '';
72
-            $item_in_top_level_array = EEH_Array::get_one_item_from_array($data);
73
-            // now, is the last item in the top-level array of $data an associative or numeric array?
74
-            if ($write_column_headers && EEH_Array::is_associative_array($item_in_top_level_array)) {
75
-                // its associative, so we want to output its keys as column headers
76
-                $keys = array_keys($item_in_top_level_array);
77
-                $new_file_contents .=  EEH_Export::get_csv_row($keys);
78
-                if ($headers_only) {
79
-                    return EEH_File::write_to_file(
80
-                        $filepath,
81
-                        EEH_File::get_file_contents($filepath) . $new_file_contents
82
-                    );
83
-                }
84
-            }
85
-            // start writing data
86
-            foreach ($data as $data_row) {
87
-                $new_row = EEH_Export::get_csv_row($data_row);
88
-                $new_file_contents .= $new_row ?: '';
89
-            }
90
-            return EEH_File::write_to_file($filepath, EEH_File::get_file_contents($filepath) . $new_file_contents);
91
-        }
92
-        // no data TO write... so we can assume that's a success
93
-        return true;
94
-    }
95
-
96
-
97
-
98
-     /**
99
-      *
100
-     *  Writes a row to the csv file
101
-     *  @param array $row - individual row of csv data
102
-     *  @param string $delimiter - csv delimiter
103
-     *  @param string $enclosure - csv enclosure
104
-     *  @param bool $mysql_null - allows php NULL to be overridden with MySQl's insertable NULL value
105
-     *  @return string of text for teh csv file
106
-     */
107
-    public static function get_csv_row(array $row, $delimiter = ',', $enclosure = '"', $mysql_null = false)
108
-    {
109
-        // Allow user to filter the csv delimiter and enclosure for other countries csv standards
110
-        $delimiter = apply_filters('FHEE__EE_CSV__fputcsv2__delimiter', $delimiter);
111
-        $enclosure = apply_filters('FHEE__EE_CSV__fputcsv2__enclosure', $enclosure);
112
-
113
-        $delimiter_esc = preg_quote($delimiter, '/');
114
-        $enclosure_esc = preg_quote($enclosure, '/');
115
-
116
-        $output = array();
117
-        foreach ($row as $field_value) {
118
-            if (is_object($field_value) || is_array($field_value)) {
119
-                $field_value = serialize($field_value);
120
-            }
121
-            if ($field_value === null && $mysql_null) {
122
-                $output[] = 'NULL';
123
-                continue;
124
-            }
125
-
126
-            $output[] = preg_match("/(?:${delimiter_esc}|${enclosure_esc}|\s)/", $field_value) ?
127
-                ( $enclosure . str_replace($enclosure, $enclosure . $enclosure, $field_value) . $enclosure ) : $field_value;
128
-        }
129
-
130
-        return  implode($delimiter, $output) . PHP_EOL;
131
-    }
132
-
133
-
134
-
135
-    /**
136
-     * Shortcut for preparing a database result for display
137
-     * @param EEM_Base $model
138
-     * @param string $field_name
139
-     * @param string $raw_db_value
140
-     * @param boolean|string $pretty_schema true to display pretty, a string to use a specific "Schema", or false to NOT display pretty
141
-     * @return string
142
-     */
143
-    public static function prepare_value_from_db_for_display($model, $field_name, $raw_db_value, $pretty_schema = true)
144
-    {
145
-        $field_obj = $model->field_settings_for($field_name);
146
-        $value_on_model_obj = $field_obj->prepare_for_set_from_db($raw_db_value);
147
-        if ($field_obj instanceof EE_Datetime_Field) {
148
-            $field_obj->set_date_format(EEH_Export::get_date_format_for_export($field_obj->get_date_format($pretty_schema)), $pretty_schema);
149
-            $field_obj->set_time_format(EEH_Export::get_time_format_for_export($field_obj->get_time_format($pretty_schema)), $pretty_schema);
150
-        }
151
-        if ($pretty_schema === true) {
152
-            return $field_obj->prepare_for_pretty_echoing($value_on_model_obj);
153
-        } elseif (is_string($pretty_schema)) {
154
-            return $field_obj->prepare_for_pretty_echoing($value_on_model_obj, $pretty_schema);
155
-        } else {
156
-            return $field_obj->prepare_for_get($value_on_model_obj);
157
-        }
158
-    }
159
-
160
-
161
-
162
-    /**
163
-     * Gets the date format to use in exports. filterable
164
-     * @param string $current_format
165
-     * @return string
166
-     */
167
-    public static function get_date_format_for_export($current_format = null)
168
-    {
169
-        return apply_filters('FHEE__EE_CSV__get_date_format_for_csv__format', 'Y-m-d', $current_format);
170
-    }
171
-
172
-
173
-
174
-    /**
175
-     * Gets the time format we want to use in exports. Filterable
176
-     * @param string $current_format
177
-     * @return string
178
-     */
179
-    public static function get_time_format_for_export($current_format = null)
180
-    {
181
-        return apply_filters('FHEE__EE_CSV__get_time_format_for_csv__format', 'H:i:s', $current_format);
182
-    }
16
+	/**
17
+	 * Gets the 'normal' column named for fields
18
+	 * @param EE_Model_Field_Base $field
19
+	 * @return string
20
+	 * @throws EE_Error
21
+	 */
22
+	public static function get_column_name_for_field(EE_Model_Field_Base $field)
23
+	{
24
+		$column_name = wp_specialchars_decode($field->get_nicename(), ENT_QUOTES);
25
+		if (
26
+			apply_filters(
27
+				'FHEE__EEH_Export__get_column_name_for_field__add_field_name',
28
+				false,
29
+				$column_name,
30
+				$field
31
+			)
32
+		) {
33
+			$column_name .= "["
34
+				. wp_specialchars_decode($field->get_name(), ENT_QUOTES)
35
+				. "]";
36
+		}
37
+		return $column_name;
38
+	}
39
+
40
+
41
+	/**
42
+	 * Writes $data to the csv file open in $filehandle. uses the array indices of $data for column headers
43
+	 *
44
+	 * @param string $filepath
45
+	 * @param array  $data                  2D array,first numerically-indexed,
46
+	 *                                      and next-level-down preferably indexed by string
47
+	 * @param bool   $write_column_headers  whether or not we should add the keys in the bottom-most array
48
+	 *                                      as a row for headers in the CSV.
49
+	 *                                      Eg, if $data looked like:
50
+	 *                                          array(
51
+	 *                                              0=>array('EVT_ID'=>1,'EVT_name'=>'monkey'...),
52
+	 *                                              1=>array(...,...)
53
+	 *                                          )
54
+	 * @param bool   $headers_only          if true then we won't print any data, just headers. defaults to false
55
+	 * @return boolean                      if we successfully wrote to the CSV or not. If there's no $data,
56
+	 *                                      we consider that a success (because we wrote everything there was...nothing)
57
+	 * @throws EE_Error
58
+	 */
59
+	public static function write_data_array_to_csv(
60
+		string $filepath,
61
+		array $data,
62
+		bool $write_column_headers = true,
63
+		bool $headers_only = false
64
+	) {
65
+		// determine if $data is actually a 2d array
66
+		if ($data && is_array($data) && is_array(EEH_Array::get_one_item_from_array($data))) {
67
+			// make sure top level is numerically indexed,
68
+			if (EEH_Array::is_associative_array($data)) {
69
+				throw new EE_Error(sprintf(esc_html__("top-level array must be numerically indexed. Does these look like numbers to you? %s", "event_espresso"), implode(",", array_keys($data))));
70
+			}
71
+			$new_file_contents = '';
72
+			$item_in_top_level_array = EEH_Array::get_one_item_from_array($data);
73
+			// now, is the last item in the top-level array of $data an associative or numeric array?
74
+			if ($write_column_headers && EEH_Array::is_associative_array($item_in_top_level_array)) {
75
+				// its associative, so we want to output its keys as column headers
76
+				$keys = array_keys($item_in_top_level_array);
77
+				$new_file_contents .=  EEH_Export::get_csv_row($keys);
78
+				if ($headers_only) {
79
+					return EEH_File::write_to_file(
80
+						$filepath,
81
+						EEH_File::get_file_contents($filepath) . $new_file_contents
82
+					);
83
+				}
84
+			}
85
+			// start writing data
86
+			foreach ($data as $data_row) {
87
+				$new_row = EEH_Export::get_csv_row($data_row);
88
+				$new_file_contents .= $new_row ?: '';
89
+			}
90
+			return EEH_File::write_to_file($filepath, EEH_File::get_file_contents($filepath) . $new_file_contents);
91
+		}
92
+		// no data TO write... so we can assume that's a success
93
+		return true;
94
+	}
95
+
96
+
97
+
98
+	 /**
99
+	  *
100
+	  *  Writes a row to the csv file
101
+	  *  @param array $row - individual row of csv data
102
+	  *  @param string $delimiter - csv delimiter
103
+	  *  @param string $enclosure - csv enclosure
104
+	  *  @param bool $mysql_null - allows php NULL to be overridden with MySQl's insertable NULL value
105
+	  *  @return string of text for teh csv file
106
+	  */
107
+	public static function get_csv_row(array $row, $delimiter = ',', $enclosure = '"', $mysql_null = false)
108
+	{
109
+		// Allow user to filter the csv delimiter and enclosure for other countries csv standards
110
+		$delimiter = apply_filters('FHEE__EE_CSV__fputcsv2__delimiter', $delimiter);
111
+		$enclosure = apply_filters('FHEE__EE_CSV__fputcsv2__enclosure', $enclosure);
112
+
113
+		$delimiter_esc = preg_quote($delimiter, '/');
114
+		$enclosure_esc = preg_quote($enclosure, '/');
115
+
116
+		$output = array();
117
+		foreach ($row as $field_value) {
118
+			if (is_object($field_value) || is_array($field_value)) {
119
+				$field_value = serialize($field_value);
120
+			}
121
+			if ($field_value === null && $mysql_null) {
122
+				$output[] = 'NULL';
123
+				continue;
124
+			}
125
+
126
+			$output[] = preg_match("/(?:${delimiter_esc}|${enclosure_esc}|\s)/", $field_value) ?
127
+				( $enclosure . str_replace($enclosure, $enclosure . $enclosure, $field_value) . $enclosure ) : $field_value;
128
+		}
129
+
130
+		return  implode($delimiter, $output) . PHP_EOL;
131
+	}
132
+
133
+
134
+
135
+	/**
136
+	 * Shortcut for preparing a database result for display
137
+	 * @param EEM_Base $model
138
+	 * @param string $field_name
139
+	 * @param string $raw_db_value
140
+	 * @param boolean|string $pretty_schema true to display pretty, a string to use a specific "Schema", or false to NOT display pretty
141
+	 * @return string
142
+	 */
143
+	public static function prepare_value_from_db_for_display($model, $field_name, $raw_db_value, $pretty_schema = true)
144
+	{
145
+		$field_obj = $model->field_settings_for($field_name);
146
+		$value_on_model_obj = $field_obj->prepare_for_set_from_db($raw_db_value);
147
+		if ($field_obj instanceof EE_Datetime_Field) {
148
+			$field_obj->set_date_format(EEH_Export::get_date_format_for_export($field_obj->get_date_format($pretty_schema)), $pretty_schema);
149
+			$field_obj->set_time_format(EEH_Export::get_time_format_for_export($field_obj->get_time_format($pretty_schema)), $pretty_schema);
150
+		}
151
+		if ($pretty_schema === true) {
152
+			return $field_obj->prepare_for_pretty_echoing($value_on_model_obj);
153
+		} elseif (is_string($pretty_schema)) {
154
+			return $field_obj->prepare_for_pretty_echoing($value_on_model_obj, $pretty_schema);
155
+		} else {
156
+			return $field_obj->prepare_for_get($value_on_model_obj);
157
+		}
158
+	}
159
+
160
+
161
+
162
+	/**
163
+	 * Gets the date format to use in exports. filterable
164
+	 * @param string $current_format
165
+	 * @return string
166
+	 */
167
+	public static function get_date_format_for_export($current_format = null)
168
+	{
169
+		return apply_filters('FHEE__EE_CSV__get_date_format_for_csv__format', 'Y-m-d', $current_format);
170
+	}
171
+
172
+
173
+
174
+	/**
175
+	 * Gets the time format we want to use in exports. Filterable
176
+	 * @param string $current_format
177
+	 * @return string
178
+	 */
179
+	public static function get_time_format_for_export($current_format = null)
180
+	{
181
+		return apply_filters('FHEE__EE_CSV__get_time_format_for_csv__format', 'H:i:s', $current_format);
182
+	}
183 183
 }
Please login to merge, or discard this patch.
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -74,11 +74,11 @@  discard block
 block discarded – undo
74 74
             if ($write_column_headers && EEH_Array::is_associative_array($item_in_top_level_array)) {
75 75
                 // its associative, so we want to output its keys as column headers
76 76
                 $keys = array_keys($item_in_top_level_array);
77
-                $new_file_contents .=  EEH_Export::get_csv_row($keys);
77
+                $new_file_contents .= EEH_Export::get_csv_row($keys);
78 78
                 if ($headers_only) {
79 79
                     return EEH_File::write_to_file(
80 80
                         $filepath,
81
-                        EEH_File::get_file_contents($filepath) . $new_file_contents
81
+                        EEH_File::get_file_contents($filepath).$new_file_contents
82 82
                     );
83 83
                 }
84 84
             }
@@ -87,7 +87,7 @@  discard block
 block discarded – undo
87 87
                 $new_row = EEH_Export::get_csv_row($data_row);
88 88
                 $new_file_contents .= $new_row ?: '';
89 89
             }
90
-            return EEH_File::write_to_file($filepath, EEH_File::get_file_contents($filepath) . $new_file_contents);
90
+            return EEH_File::write_to_file($filepath, EEH_File::get_file_contents($filepath).$new_file_contents);
91 91
         }
92 92
         // no data TO write... so we can assume that's a success
93 93
         return true;
@@ -124,10 +124,10 @@  discard block
 block discarded – undo
124 124
             }
125 125
 
126 126
             $output[] = preg_match("/(?:${delimiter_esc}|${enclosure_esc}|\s)/", $field_value) ?
127
-                ( $enclosure . str_replace($enclosure, $enclosure . $enclosure, $field_value) . $enclosure ) : $field_value;
127
+                ($enclosure.str_replace($enclosure, $enclosure.$enclosure, $field_value).$enclosure) : $field_value;
128 128
         }
129 129
 
130
-        return  implode($delimiter, $output) . PHP_EOL;
130
+        return  implode($delimiter, $output).PHP_EOL;
131 131
     }
132 132
 
133 133
 
Please login to merge, or discard this patch.
core/libraries/batch/JobHandlerBaseClasses/JobHandlerFile.php 2 patches
Indentation   +140 added lines, -140 removed lines patch added patch discarded remove patch
@@ -19,144 +19,144 @@
 block discarded – undo
19 19
  */
20 20
 abstract class JobHandlerFile extends JobHandler
21 21
 {
22
-    // phpcs:disable Generic.NamingConventions.UpperCaseConstantName.ClassConstantNotUpperCase
23
-    const temp_folder_name = 'batch_temp_folder';
24
-
25
-    // phpcs:disable PSR2.Classes.PropertyDeclaration.Underscore
26
-
27
-    /**
28
-     * @var EEHI_File
29
-     */
30
-    protected $_file_helper = null;
31
-
32
-
33
-    /**
34
-     * JobHandlerFile constructor.
35
-     *
36
-     * @param EEHI_File|null $file_helper
37
-     */
38
-    public function __construct(EEHI_File $file_helper = null)
39
-    {
40
-        if (! $file_helper) {
41
-            $this->_file_helper = new EEH_File();
42
-        }
43
-    }
44
-
45
-    // phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
46
-
47
-
48
-    /**
49
-     * Creates a file
50
-     *
51
-     * @param string $job_id
52
-     * @param string $filename
53
-     * @param string $filetype
54
-     * @param string $bom initial content to place in the file.
55
-     * @return string
56
-     * @throws BatchRequestException
57
-     */
58
-    public function create_file_from_job_with_name(
59
-        string $job_id,
60
-        string $filename,
61
-        string $filetype = 'application/ms-excel',
62
-        string $bom = "\xEF\xBB\xBF"
63
-    ): string {
64
-        $filepath = '';
65
-        try {
66
-            $base_folder = $this->get_base_folder();
67
-            $success     = $this->_file_helper->ensure_folder_exists_and_is_writable(
68
-                $base_folder . JobHandlerFile::temp_folder_name
69
-            );
70
-            if ($success) {
71
-                $success = $this->_file_helper->ensure_folder_exists_and_is_writable(
72
-                    $base_folder . JobHandlerFile::temp_folder_name . '/' . $job_id
73
-                );
74
-            }
75
-            if ($success) {
76
-                $filepath = $base_folder . JobHandlerFile::temp_folder_name . '/' . $job_id . '/' . $filename;
77
-                $success  = $this->_file_helper->ensure_file_exists_and_is_writable($filepath);
78
-            }
79
-            // let's add the .htaccess file so safari will open the file properly
80
-            if ($success) {
81
-                $extension = EEH_File::get_file_extension($filepath);
82
-                EEH_File::write_to_file(
83
-                    $base_folder . JobHandlerFile::temp_folder_name . '/' . $job_id . '/.htaccess',
84
-                    'AddType ' . $filetype . ' ' . $extension,
85
-                    '.htaccess'
86
-                );
87
-            }
88
-            /**
89
-             * Filters what initial content will be added to the file.
90
-             *
91
-             * @param string $return_value  By default it's whatever was passed into
92
-             *                              JobHandlerFile::create_file_from_job_with_name()
93
-             * @param string $filename
94
-             * @param string $filetype default 'application/ms-excel'
95
-             * @param string $filepath
96
-             */
97
-            EEH_File::write_to_file(
98
-                $filepath,
99
-                apply_filters(
100
-                    'FHEE__EE_CSV__begin_sending_csv__start_writing',
101
-                    $bom,
102
-                    $filename,
103
-                    $filetype,
104
-                    $filepath
105
-                )
106
-            );
107
-            // those methods normally fail with an exception, but if not, let's do it
108
-            if (! $success) {
109
-                throw new EE_Error(
110
-                    esc_html__('Could not create temporary file, an unknown error occurred', 'event_espresso')
111
-                );
112
-            }
113
-        } catch (EE_Error $e) {
114
-            throw new BatchRequestException(
115
-                sprintf(
116
-                // phpcs:disable WordPress.WP.I18n.MissingTranslatorsComment
117
-                    esc_html__('Could not create temporary file for job %1$s, because: %2$s ', 'event_espresso'),
118
-                    $job_id,
119
-                    $e->getMessage()
120
-                ),
121
-                500,
122
-                $e
123
-            );
124
-        }
125
-        return $filepath;
126
-    }
127
-
128
-
129
-    /**
130
-     * Gets the URL to download the file
131
-     *
132
-     * @param string $filepath
133
-     * @return string url to file
134
-     */
135
-    public function get_url_to_file(string $filepath): string
136
-    {
137
-        return str_replace($this->get_base_folder(), $this->get_base_url(), $filepath);
138
-    }
139
-
140
-
141
-    /**
142
-     * Gets the folder which will contain the "batch_temp_folder"
143
-     *
144
-     * @return string
145
-     */
146
-    public function get_base_folder(): string
147
-    {
148
-        return apply_filters(
149
-            'FHEE__EventEspressoBatchRequest\JobHandlerBaseClasses\JobHandlerFile__get_base_folder',
150
-            EVENT_ESPRESSO_UPLOAD_DIR
151
-        );
152
-    }
153
-
154
-
155
-    public function get_base_url(): string
156
-    {
157
-        return apply_filters(
158
-            'FHEE__EventEspressoBatchRequest\JobHandlerBaseClasses\JobHandlerFile__get_base_url',
159
-            EVENT_ESPRESSO_UPLOAD_URL
160
-        );
161
-    }
22
+	// phpcs:disable Generic.NamingConventions.UpperCaseConstantName.ClassConstantNotUpperCase
23
+	const temp_folder_name = 'batch_temp_folder';
24
+
25
+	// phpcs:disable PSR2.Classes.PropertyDeclaration.Underscore
26
+
27
+	/**
28
+	 * @var EEHI_File
29
+	 */
30
+	protected $_file_helper = null;
31
+
32
+
33
+	/**
34
+	 * JobHandlerFile constructor.
35
+	 *
36
+	 * @param EEHI_File|null $file_helper
37
+	 */
38
+	public function __construct(EEHI_File $file_helper = null)
39
+	{
40
+		if (! $file_helper) {
41
+			$this->_file_helper = new EEH_File();
42
+		}
43
+	}
44
+
45
+	// phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
46
+
47
+
48
+	/**
49
+	 * Creates a file
50
+	 *
51
+	 * @param string $job_id
52
+	 * @param string $filename
53
+	 * @param string $filetype
54
+	 * @param string $bom initial content to place in the file.
55
+	 * @return string
56
+	 * @throws BatchRequestException
57
+	 */
58
+	public function create_file_from_job_with_name(
59
+		string $job_id,
60
+		string $filename,
61
+		string $filetype = 'application/ms-excel',
62
+		string $bom = "\xEF\xBB\xBF"
63
+	): string {
64
+		$filepath = '';
65
+		try {
66
+			$base_folder = $this->get_base_folder();
67
+			$success     = $this->_file_helper->ensure_folder_exists_and_is_writable(
68
+				$base_folder . JobHandlerFile::temp_folder_name
69
+			);
70
+			if ($success) {
71
+				$success = $this->_file_helper->ensure_folder_exists_and_is_writable(
72
+					$base_folder . JobHandlerFile::temp_folder_name . '/' . $job_id
73
+				);
74
+			}
75
+			if ($success) {
76
+				$filepath = $base_folder . JobHandlerFile::temp_folder_name . '/' . $job_id . '/' . $filename;
77
+				$success  = $this->_file_helper->ensure_file_exists_and_is_writable($filepath);
78
+			}
79
+			// let's add the .htaccess file so safari will open the file properly
80
+			if ($success) {
81
+				$extension = EEH_File::get_file_extension($filepath);
82
+				EEH_File::write_to_file(
83
+					$base_folder . JobHandlerFile::temp_folder_name . '/' . $job_id . '/.htaccess',
84
+					'AddType ' . $filetype . ' ' . $extension,
85
+					'.htaccess'
86
+				);
87
+			}
88
+			/**
89
+			 * Filters what initial content will be added to the file.
90
+			 *
91
+			 * @param string $return_value  By default it's whatever was passed into
92
+			 *                              JobHandlerFile::create_file_from_job_with_name()
93
+			 * @param string $filename
94
+			 * @param string $filetype default 'application/ms-excel'
95
+			 * @param string $filepath
96
+			 */
97
+			EEH_File::write_to_file(
98
+				$filepath,
99
+				apply_filters(
100
+					'FHEE__EE_CSV__begin_sending_csv__start_writing',
101
+					$bom,
102
+					$filename,
103
+					$filetype,
104
+					$filepath
105
+				)
106
+			);
107
+			// those methods normally fail with an exception, but if not, let's do it
108
+			if (! $success) {
109
+				throw new EE_Error(
110
+					esc_html__('Could not create temporary file, an unknown error occurred', 'event_espresso')
111
+				);
112
+			}
113
+		} catch (EE_Error $e) {
114
+			throw new BatchRequestException(
115
+				sprintf(
116
+				// phpcs:disable WordPress.WP.I18n.MissingTranslatorsComment
117
+					esc_html__('Could not create temporary file for job %1$s, because: %2$s ', 'event_espresso'),
118
+					$job_id,
119
+					$e->getMessage()
120
+				),
121
+				500,
122
+				$e
123
+			);
124
+		}
125
+		return $filepath;
126
+	}
127
+
128
+
129
+	/**
130
+	 * Gets the URL to download the file
131
+	 *
132
+	 * @param string $filepath
133
+	 * @return string url to file
134
+	 */
135
+	public function get_url_to_file(string $filepath): string
136
+	{
137
+		return str_replace($this->get_base_folder(), $this->get_base_url(), $filepath);
138
+	}
139
+
140
+
141
+	/**
142
+	 * Gets the folder which will contain the "batch_temp_folder"
143
+	 *
144
+	 * @return string
145
+	 */
146
+	public function get_base_folder(): string
147
+	{
148
+		return apply_filters(
149
+			'FHEE__EventEspressoBatchRequest\JobHandlerBaseClasses\JobHandlerFile__get_base_folder',
150
+			EVENT_ESPRESSO_UPLOAD_DIR
151
+		);
152
+	}
153
+
154
+
155
+	public function get_base_url(): string
156
+	{
157
+		return apply_filters(
158
+			'FHEE__EventEspressoBatchRequest\JobHandlerBaseClasses\JobHandlerFile__get_base_url',
159
+			EVENT_ESPRESSO_UPLOAD_URL
160
+		);
161
+	}
162 162
 }
Please login to merge, or discard this patch.
Spacing   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -37,7 +37,7 @@  discard block
 block discarded – undo
37 37
      */
38 38
     public function __construct(EEHI_File $file_helper = null)
39 39
     {
40
-        if (! $file_helper) {
40
+        if ( ! $file_helper) {
41 41
             $this->_file_helper = new EEH_File();
42 42
         }
43 43
     }
@@ -65,23 +65,23 @@  discard block
 block discarded – undo
65 65
         try {
66 66
             $base_folder = $this->get_base_folder();
67 67
             $success     = $this->_file_helper->ensure_folder_exists_and_is_writable(
68
-                $base_folder . JobHandlerFile::temp_folder_name
68
+                $base_folder.JobHandlerFile::temp_folder_name
69 69
             );
70 70
             if ($success) {
71 71
                 $success = $this->_file_helper->ensure_folder_exists_and_is_writable(
72
-                    $base_folder . JobHandlerFile::temp_folder_name . '/' . $job_id
72
+                    $base_folder.JobHandlerFile::temp_folder_name.'/'.$job_id
73 73
                 );
74 74
             }
75 75
             if ($success) {
76
-                $filepath = $base_folder . JobHandlerFile::temp_folder_name . '/' . $job_id . '/' . $filename;
76
+                $filepath = $base_folder.JobHandlerFile::temp_folder_name.'/'.$job_id.'/'.$filename;
77 77
                 $success  = $this->_file_helper->ensure_file_exists_and_is_writable($filepath);
78 78
             }
79 79
             // let's add the .htaccess file so safari will open the file properly
80 80
             if ($success) {
81 81
                 $extension = EEH_File::get_file_extension($filepath);
82 82
                 EEH_File::write_to_file(
83
-                    $base_folder . JobHandlerFile::temp_folder_name . '/' . $job_id . '/.htaccess',
84
-                    'AddType ' . $filetype . ' ' . $extension,
83
+                    $base_folder.JobHandlerFile::temp_folder_name.'/'.$job_id.'/.htaccess',
84
+                    'AddType '.$filetype.' '.$extension,
85 85
                     '.htaccess'
86 86
                 );
87 87
             }
@@ -105,7 +105,7 @@  discard block
 block discarded – undo
105 105
                 )
106 106
             );
107 107
             // those methods normally fail with an exception, but if not, let's do it
108
-            if (! $success) {
108
+            if ( ! $success) {
109 109
                 throw new EE_Error(
110 110
                     esc_html__('Could not create temporary file, an unknown error occurred', 'event_espresso')
111 111
                 );
Please login to merge, or discard this patch.
modules/batch/EED_Batch.module.php 2 patches
Indentation   +443 added lines, -443 removed lines patch added patch discarded remove patch
@@ -28,447 +28,447 @@
 block discarded – undo
28 28
  */
29 29
 class EED_Batch extends EED_Module
30 30
 {
31
-    public const PAGE_SLUG = 'espresso_batch';
32
-
33
-    /**
34
-     * Possibly value for $_REQUEST[ 'batch' ]. Indicates to run a job that
35
-     * processes data only
36
-     */
37
-    const batch_job = 'job';
38
-
39
-    /**
40
-     * Possibly value for $_REQUEST[ 'batch' ]. Indicates to run a job that
41
-     * produces a file for download
42
-     */
43
-    const batch_file_job = 'file';
44
-
45
-    /**
46
-     * Possibly value for $_REQUEST[ 'batch' ]. Indicates this request is NOT
47
-     * for a batch job. It's the same as not providing the $_REQUEST[ 'batch' ]
48
-     * at all
49
-     */
50
-    const batch_not_job = 'none';
51
-
52
-    /**
53
-     *
54
-     * @var string 'file', or 'job', or false to indicate its not a batch request at all
55
-     */
56
-    protected $_batch_request_type = '';
57
-
58
-    /**
59
-     * Because we want to use the response in both the localized JS and in the body
60
-     * we need to make this response available between method calls
61
-     *
62
-     * @var JobStepResponse|null
63
-     */
64
-    protected $_job_step_response = null;
65
-
66
-    /**
67
-     * @var LoaderInterface|null
68
-     */
69
-    protected $loader = null;
70
-
71
-
72
-    /**
73
-     * Gets the batch instance
74
-     *
75
-     * @return  EED_Module|EED_Batch
76
-     * @throws EE_Error
77
-     * @throws ReflectionException
78
-     */
79
-    public static function instance(): EED_Batch
80
-    {
81
-        return parent::get_instance(__CLASS__);
82
-    }
83
-
84
-
85
-    /**
86
-     * Sets hooks to enable batch jobs on the frontend. Disabled by default
87
-     * because it's an attack vector and there are currently no implementations
88
-     *
89
-     * @throws EE_Error
90
-     * @throws ReflectionException
91
-     */
92
-    public static function set_hooks()
93
-    {
94
-        // because this is a possible attack vector, let's have this disabled until
95
-        // we at least have a real use for it on the frontend
96
-        if (apply_filters('FHEE__EED_Batch__set_hooks__enable_frontend_batch', false)) {
97
-            add_action('wp_enqueue_scripts', [self::instance(), 'enqueue_scripts']);
98
-            add_filter('template_include', [self::instance(), 'override_template'], 99);
99
-        }
100
-    }
101
-
102
-
103
-    /**
104
-     * Initializes some hooks for the admin in order to run batch jobs
105
-     *
106
-     * @throws EE_Error
107
-     * @throws ReflectionException
108
-     */
109
-    public static function set_hooks_admin()
110
-    {
111
-        add_action('admin_menu', [self::instance(), 'register_admin_pages']);
112
-        add_action('admin_enqueue_scripts', [self::instance(), 'enqueue_scripts']);
113
-
114
-        // ajax
115
-        add_action('wp_ajax_espresso_batch_continue', [self::instance(), 'continueBatchJob']);
116
-        add_action('wp_ajax_espresso_batch_advance', [self::instance(), 'advanceBatchJob']);
117
-        add_action('wp_ajax_espresso_batch_cleanup', [self::instance(), 'cleanupBatchJob']);
118
-        add_action('wp_ajax_nopriv_espresso_batch_continue', [self::instance(), 'continueBatchJob']);
119
-        add_action('wp_ajax_nopriv_espresso_batch_advance', [self::instance(), 'advanceBatchJob']);
120
-        add_action('wp_ajax_nopriv_espresso_batch_cleanup', [self::instance(), 'cleanupBatchJob']);
121
-        add_filter(
122
-            'admin_body_class',
123
-            function ($classes) {
124
-                if (strpos($classes, 'espresso-admin') === false) {
125
-                    $classes .= ' espresso-admin';
126
-                }
127
-                return $classes;
128
-            }
129
-        );
130
-    }
131
-
132
-
133
-    /**
134
-     * @return LoaderInterface
135
-     * @throws InvalidArgumentException
136
-     * @throws InvalidDataTypeException
137
-     * @throws InvalidInterfaceException
138
-     * @since 4.9.80.p
139
-     */
140
-    protected function getLoader(): LoaderInterface
141
-    {
142
-        if (! $this->loader instanceof LoaderInterface) {
143
-            $this->loader = LoaderFactory::getLoader();
144
-        }
145
-        return $this->loader;
146
-    }
147
-
148
-
149
-    /**
150
-     * Enqueues batch scripts on the frontend or admin, and creates a job
151
-     */
152
-    public function enqueue_scripts()
153
-    {
154
-        $request = EED_Batch::getRequest();
155
-        if (
156
-            $request->getRequestParam(EED_Batch::PAGE_SLUG)
157
-            || $request->getRequestParam('page') === EED_Batch::PAGE_SLUG
158
-        ) {
159
-            if (
160
-                ! $request->requestParamIsSet('default_nonce')
161
-                || ! wp_verify_nonce($request->getRequestParam('default_nonce'), 'default_nonce')
162
-            ) {
163
-                wp_die(
164
-                    esc_html__(
165
-                        'The link you clicked to start the batch job has expired. Please go back and refresh the previous page.',
166
-                        'event_espresso'
167
-                    )
168
-                );
169
-            }
170
-            switch ($this->batch_request_type()) {
171
-                case self::batch_job:
172
-                    $this->enqueue_scripts_styles_batch_create();
173
-                    break;
174
-                case self::batch_file_job:
175
-                    $this->enqueue_scripts_styles_batch_file_create();
176
-                    break;
177
-            }
178
-        }
179
-    }
180
-
181
-
182
-    /**
183
-     * Create a batch job, enqueues a script to run it, and localizes some data for it
184
-     */
185
-    public function enqueue_scripts_styles_batch_create()
186
-    {
187
-        $job_response = $this->_enqueue_batch_job_scripts_and_styles_and_start_job();
188
-        wp_enqueue_script(
189
-            'batch_runner_init',
190
-            BATCH_URL . 'assets/batch_runner_init.js',
191
-            ['batch_runner'],
192
-            date('Y-m-d-H:i', time()),
193
-            true
194
-        );
195
-        wp_localize_script('batch_runner_init', 'ee_job_response', $job_response->to_array());
196
-        wp_localize_script('batch_runner_init', 'eei18n', EE_Registry::$i18n_js_strings);
197
-
198
-        $return_url = EED_Batch::getRequest()->getRequestParam('return_url', '', 'url');
199
-        if ($return_url) {
200
-            wp_localize_script(
201
-                'batch_runner_init',
202
-                'ee_job_i18n',
203
-                [
204
-                    'return_url'                => $return_url,
205
-                    'auto_redirect_on_complete' => EED_Batch::getRequest()->getRequestParam(
206
-                        'auto_redirect_on_complete'
207
-                    ),
208
-                    'user_message'              => EED_Batch::getRequest()->getRequestParam('assessment_notice')
209
-                        ?: EED_Batch::getRequest()->getRequestParam('job_start_notice'),
210
-                ]
211
-            );
212
-        }
213
-    }
214
-
215
-
216
-    /**
217
-     * Creates a batch job which will download a file, enqueues a script to run the job, and localizes some data for it
218
-     */
219
-    public function enqueue_scripts_styles_batch_file_create()
220
-    {
221
-        // creates a job based on the request variable
222
-        $job_response = $this->_enqueue_batch_job_scripts_and_styles_and_start_job();
223
-        wp_enqueue_script(
224
-            'batch_file_runner_init',
225
-            BATCH_URL . 'assets/batch_file_runner_init.js',
226
-            ['batch_runner'],
227
-            date('Y-m-d-H:i', time()),
228
-            true
229
-        );
230
-        wp_localize_script('batch_file_runner_init', 'ee_job_response', $job_response->to_array());
231
-        wp_localize_script('batch_file_runner_init', 'eei18n', EE_Registry::$i18n_js_strings);
232
-
233
-        $return_url = EED_Batch::getRequest()->getRequestParam('return_url', '', 'url');
234
-        if ($return_url) {
235
-            wp_localize_script(
236
-                'batch_file_runner_init',
237
-                'ee_job_i18n',
238
-                ['return_url' => $return_url]
239
-            );
240
-        }
241
-    }
242
-
243
-
244
-    /**
245
-     * Enqueues scripts and styles common to any batch job, and creates
246
-     * a job from the request data, and stores the response in the
247
-     * $this->_job_step_response property
248
-     *
249
-     * @return JobStepResponse
250
-     */
251
-    protected function _enqueue_batch_job_scripts_and_styles_and_start_job(): JobStepResponse
252
-    {
253
-        // just copy the bits of EE admin's eei18n that we need in the JS
254
-        EE_Registry::$i18n_js_strings['batchJobError'] = __(
255
-            'An error occurred and the job has been stopped. Please refresh the page to try again.',
256
-            'event_espresso'
257
-        );
258
-        EE_Registry::$i18n_js_strings['is_admin']      = is_admin();
259
-        wp_enqueue_style(
260
-            EspressoLegacyAdminAssetManager::CSS_HANDLE_EE_ADMIN,
261
-            EE_ADMIN_URL . 'assets/ee-admin-page.css',
262
-            [],
263
-            EVENT_ESPRESSO_VERSION
264
-        );
265
-        wp_enqueue_style(
266
-            'batch_runner',
267
-            BATCH_URL . 'assets/batch_runner.css',
268
-            [EspressoLegacyAdminAssetManager::CSS_HANDLE_EE_ADMIN],
269
-            date('Y-m-d-H:i', time())
270
-        );
271
-        wp_register_script(
272
-            'progress_bar',
273
-            EE_PLUGIN_DIR_URL . 'core/libraries/batch/Assets/progress_bar.js',
274
-            ['jquery'],
275
-            date('Y-m-d-H:i', time()),
276
-            true
277
-        );
278
-        wp_enqueue_style(
279
-            'progress_bar',
280
-            EE_PLUGIN_DIR_URL . 'core/libraries/batch/Assets/progress_bar.css',
281
-            [],
282
-            date('Y-m-d-H:i', time())
283
-        );
284
-        wp_enqueue_script(
285
-            'batch_runner',
286
-            EE_PLUGIN_DIR_URL . 'core/libraries/batch/Assets/batch_runner.js',
287
-            ['progress_bar', CoreAssetManager::JS_HANDLE_CORE],
288
-            date('Y-m-d-H:i', time()),
289
-            true
290
-        );
291
-        /** @var BatchRequestProcessor $batch_runner */
292
-        $batch_runner = $this->getLoader()->getShared('EventEspressoBatchRequest\BatchRequestProcessor');
293
-        // eg 'EventEspressoBatchRequest\JobHandlers\RegistrationsReport'
294
-        // remember the response for later. We need it to display the page body
295
-        $this->_job_step_response = $batch_runner->createJob();
296
-        return $this->_job_step_response;
297
-    }
298
-
299
-
300
-    /**
301
-     * If we are doing a frontend batch job, this makes it so WP shows our template's HTML
302
-     *
303
-     * @param string $template
304
-     * @return string
305
-     */
306
-    public function override_template(string $template): string
307
-    {
308
-        $request = EED_Batch::getRequest();
309
-        if ($request->requestParamIsSet('batch') && $request->requestParamIsSet(EED_Batch::PAGE_SLUG)) {
310
-            return EE_MODULES . 'batch/templates/batch_frontend_wrapper.template.php';
311
-        }
312
-        return $template;
313
-    }
314
-
315
-
316
-    /**
317
-     * Adds an admin page which doesn't appear in the admin menu
318
-     *
319
-     * @throws EE_Error
320
-     * @throws ReflectionException
321
-     */
322
-    public function register_admin_pages()
323
-    {
324
-        add_submenu_page(
325
-            '',
326
-            // parent slug. we don't want this to actually appear in the menu
327
-            esc_html__('Batch Job', 'event_espresso'),
328
-            // page title
329
-            'n/a',
330
-            // menu title
331
-            'read',
332
-            // we want this page to actually be accessible to anyone,
333
-            EED_Batch::PAGE_SLUG,
334
-            // menu slug
335
-            [self::instance(), 'show_admin_page']
336
-        );
337
-    }
338
-
339
-
340
-    /**
341
-     * Renders the admin page, after most of the work was already done during enqueuing scripts
342
-     * of creating the job and localizing some data
343
-     */
344
-    public function show_admin_page()
345
-    {
346
-        echo EEH_Template::locate_template(
347
-            EE_MODULES . 'batch/templates/batch_wrapper.template.php',
348
-            [
349
-                'batch_request_type'        => $this->batch_request_type(),
350
-                'auto_redirect_on_complete' => EED_Batch::getRequest()->getRequestParam('auto_redirect_on_complete'),
351
-                'user_message'              => EED_Batch::getRequest()->getRequestParam('assessment_notice')
352
-                    ?: EED_Batch::getRequest()->getRequestParam('job_start_notice'),
353
-            ]
354
-        );
355
-    }
356
-
357
-
358
-    private function runBatchRunnerJob(string $job)
359
-    {
360
-        $job_id = EED_Batch::getRequest()->getRequestParam('job_id');
361
-        /** @var BatchRequestProcessor $batch_runner */
362
-        $batch_runner = $this->getLoader()->getShared('EventEspressoBatchRequest\BatchRequestProcessor');
363
-        $job_response = $batch_runner->{$job}($job_id);
364
-        $this->_return_json($job_response->to_array());
365
-    }
366
-
367
-
368
-    /**
369
-     * Receives ajax calls for continuing a job
370
-     */
371
-    public function continueBatchJob()
372
-    {
373
-        $this->runBatchRunnerJob('continueJob');
374
-    }
375
-
376
-
377
-    /**
378
-     * Receives ajax calls for continuing a job
379
-     */
380
-    public function advanceBatchJob()
381
-    {
382
-        $this->runBatchRunnerJob('advanceJob');
383
-    }
384
-
385
-
386
-    /**
387
-     * Receives the ajax call to cleanup a job
388
-     *
389
-     * @return void
390
-     */
391
-    public function cleanupBatchJob()
392
-    {
393
-        $this->runBatchRunnerJob('cleanupJob');
394
-    }
395
-
396
-
397
-    /**
398
-     * Returns a json response
399
-     *
400
-     * @param array $data The data we want to send echo via in the JSON response's "data" element
401
-     *
402
-     * The returned json object is created from an array in the following format:
403
-     * array(
404
-     *    'notices' => '', // - contains any EE_Error formatted notices
405
-     *    'data' => array() //this can be any key/value pairs that a method returns for later json parsing by the js.
406
-     *    We're also going to include the template args with every package (so js can pick out any specific template
407
-     *    args that might be included in here)
408
-     *    'isEEajax' => true,//indicates this is a response from EE
409
-     * )
410
-     */
411
-    protected function _return_json(array $data)
412
-    {
413
-        $json = [
414
-            'notices'  => EE_Error::get_notices(),
415
-            'data'     => $data,
416
-            'isEEajax' => true
417
-            // special flag so any ajax.Success methods in js can identify this return package as a EEajax package.
418
-        ];
419
-
420
-        // make sure there are no php errors or headers_sent.  Then we can set correct json header.
421
-        if (error_get_last() === null || ! headers_sent()) {
422
-            header('Content-Type: application/json; charset=UTF-8');
423
-            echo wp_json_encode($json);
424
-            exit();
425
-        }
426
-    }
427
-
428
-
429
-    /**
430
-     * Gets the job step response which was done during the enqueuing of scripts
431
-     *
432
-     * @return JobStepResponse
433
-     */
434
-    public function job_step_response(): JobStepResponse
435
-    {
436
-        return $this->_job_step_response;
437
-    }
438
-
439
-
440
-    /**
441
-     * Gets the batch request type indicated in the current request
442
-     *
443
-     * @return string: EED_Batch::batch_job, EED_Batch::batch_file_job, EED_Batch::batch_not_job
444
-     */
445
-    public function batch_request_type(): string
446
-    {
447
-        if (! $this->_batch_request_type) {
448
-            $request = EED_Batch::getRequest();
449
-            $batch   = $request->getRequestParam('batch');
450
-            switch ($batch) {
451
-                case self::batch_job:
452
-                    $this->_batch_request_type = self::batch_job;
453
-                    break;
454
-                case self::batch_file_job:
455
-                    $this->_batch_request_type = self::batch_file_job;
456
-                    break;
457
-                default:
458
-                    // if we didn't find that it was a batch request, indicate it wasn't
459
-                    $this->_batch_request_type = self::batch_not_job;
460
-            }
461
-        }
462
-        return $this->_batch_request_type;
463
-    }
464
-
465
-
466
-    /**
467
-     * Unnecessary
468
-     *
469
-     * @param WP $WP
470
-     */
471
-    public function run($WP)
472
-    {
473
-    }
31
+	public const PAGE_SLUG = 'espresso_batch';
32
+
33
+	/**
34
+	 * Possibly value for $_REQUEST[ 'batch' ]. Indicates to run a job that
35
+	 * processes data only
36
+	 */
37
+	const batch_job = 'job';
38
+
39
+	/**
40
+	 * Possibly value for $_REQUEST[ 'batch' ]. Indicates to run a job that
41
+	 * produces a file for download
42
+	 */
43
+	const batch_file_job = 'file';
44
+
45
+	/**
46
+	 * Possibly value for $_REQUEST[ 'batch' ]. Indicates this request is NOT
47
+	 * for a batch job. It's the same as not providing the $_REQUEST[ 'batch' ]
48
+	 * at all
49
+	 */
50
+	const batch_not_job = 'none';
51
+
52
+	/**
53
+	 *
54
+	 * @var string 'file', or 'job', or false to indicate its not a batch request at all
55
+	 */
56
+	protected $_batch_request_type = '';
57
+
58
+	/**
59
+	 * Because we want to use the response in both the localized JS and in the body
60
+	 * we need to make this response available between method calls
61
+	 *
62
+	 * @var JobStepResponse|null
63
+	 */
64
+	protected $_job_step_response = null;
65
+
66
+	/**
67
+	 * @var LoaderInterface|null
68
+	 */
69
+	protected $loader = null;
70
+
71
+
72
+	/**
73
+	 * Gets the batch instance
74
+	 *
75
+	 * @return  EED_Module|EED_Batch
76
+	 * @throws EE_Error
77
+	 * @throws ReflectionException
78
+	 */
79
+	public static function instance(): EED_Batch
80
+	{
81
+		return parent::get_instance(__CLASS__);
82
+	}
83
+
84
+
85
+	/**
86
+	 * Sets hooks to enable batch jobs on the frontend. Disabled by default
87
+	 * because it's an attack vector and there are currently no implementations
88
+	 *
89
+	 * @throws EE_Error
90
+	 * @throws ReflectionException
91
+	 */
92
+	public static function set_hooks()
93
+	{
94
+		// because this is a possible attack vector, let's have this disabled until
95
+		// we at least have a real use for it on the frontend
96
+		if (apply_filters('FHEE__EED_Batch__set_hooks__enable_frontend_batch', false)) {
97
+			add_action('wp_enqueue_scripts', [self::instance(), 'enqueue_scripts']);
98
+			add_filter('template_include', [self::instance(), 'override_template'], 99);
99
+		}
100
+	}
101
+
102
+
103
+	/**
104
+	 * Initializes some hooks for the admin in order to run batch jobs
105
+	 *
106
+	 * @throws EE_Error
107
+	 * @throws ReflectionException
108
+	 */
109
+	public static function set_hooks_admin()
110
+	{
111
+		add_action('admin_menu', [self::instance(), 'register_admin_pages']);
112
+		add_action('admin_enqueue_scripts', [self::instance(), 'enqueue_scripts']);
113
+
114
+		// ajax
115
+		add_action('wp_ajax_espresso_batch_continue', [self::instance(), 'continueBatchJob']);
116
+		add_action('wp_ajax_espresso_batch_advance', [self::instance(), 'advanceBatchJob']);
117
+		add_action('wp_ajax_espresso_batch_cleanup', [self::instance(), 'cleanupBatchJob']);
118
+		add_action('wp_ajax_nopriv_espresso_batch_continue', [self::instance(), 'continueBatchJob']);
119
+		add_action('wp_ajax_nopriv_espresso_batch_advance', [self::instance(), 'advanceBatchJob']);
120
+		add_action('wp_ajax_nopriv_espresso_batch_cleanup', [self::instance(), 'cleanupBatchJob']);
121
+		add_filter(
122
+			'admin_body_class',
123
+			function ($classes) {
124
+				if (strpos($classes, 'espresso-admin') === false) {
125
+					$classes .= ' espresso-admin';
126
+				}
127
+				return $classes;
128
+			}
129
+		);
130
+	}
131
+
132
+
133
+	/**
134
+	 * @return LoaderInterface
135
+	 * @throws InvalidArgumentException
136
+	 * @throws InvalidDataTypeException
137
+	 * @throws InvalidInterfaceException
138
+	 * @since 4.9.80.p
139
+	 */
140
+	protected function getLoader(): LoaderInterface
141
+	{
142
+		if (! $this->loader instanceof LoaderInterface) {
143
+			$this->loader = LoaderFactory::getLoader();
144
+		}
145
+		return $this->loader;
146
+	}
147
+
148
+
149
+	/**
150
+	 * Enqueues batch scripts on the frontend or admin, and creates a job
151
+	 */
152
+	public function enqueue_scripts()
153
+	{
154
+		$request = EED_Batch::getRequest();
155
+		if (
156
+			$request->getRequestParam(EED_Batch::PAGE_SLUG)
157
+			|| $request->getRequestParam('page') === EED_Batch::PAGE_SLUG
158
+		) {
159
+			if (
160
+				! $request->requestParamIsSet('default_nonce')
161
+				|| ! wp_verify_nonce($request->getRequestParam('default_nonce'), 'default_nonce')
162
+			) {
163
+				wp_die(
164
+					esc_html__(
165
+						'The link you clicked to start the batch job has expired. Please go back and refresh the previous page.',
166
+						'event_espresso'
167
+					)
168
+				);
169
+			}
170
+			switch ($this->batch_request_type()) {
171
+				case self::batch_job:
172
+					$this->enqueue_scripts_styles_batch_create();
173
+					break;
174
+				case self::batch_file_job:
175
+					$this->enqueue_scripts_styles_batch_file_create();
176
+					break;
177
+			}
178
+		}
179
+	}
180
+
181
+
182
+	/**
183
+	 * Create a batch job, enqueues a script to run it, and localizes some data for it
184
+	 */
185
+	public function enqueue_scripts_styles_batch_create()
186
+	{
187
+		$job_response = $this->_enqueue_batch_job_scripts_and_styles_and_start_job();
188
+		wp_enqueue_script(
189
+			'batch_runner_init',
190
+			BATCH_URL . 'assets/batch_runner_init.js',
191
+			['batch_runner'],
192
+			date('Y-m-d-H:i', time()),
193
+			true
194
+		);
195
+		wp_localize_script('batch_runner_init', 'ee_job_response', $job_response->to_array());
196
+		wp_localize_script('batch_runner_init', 'eei18n', EE_Registry::$i18n_js_strings);
197
+
198
+		$return_url = EED_Batch::getRequest()->getRequestParam('return_url', '', 'url');
199
+		if ($return_url) {
200
+			wp_localize_script(
201
+				'batch_runner_init',
202
+				'ee_job_i18n',
203
+				[
204
+					'return_url'                => $return_url,
205
+					'auto_redirect_on_complete' => EED_Batch::getRequest()->getRequestParam(
206
+						'auto_redirect_on_complete'
207
+					),
208
+					'user_message'              => EED_Batch::getRequest()->getRequestParam('assessment_notice')
209
+						?: EED_Batch::getRequest()->getRequestParam('job_start_notice'),
210
+				]
211
+			);
212
+		}
213
+	}
214
+
215
+
216
+	/**
217
+	 * Creates a batch job which will download a file, enqueues a script to run the job, and localizes some data for it
218
+	 */
219
+	public function enqueue_scripts_styles_batch_file_create()
220
+	{
221
+		// creates a job based on the request variable
222
+		$job_response = $this->_enqueue_batch_job_scripts_and_styles_and_start_job();
223
+		wp_enqueue_script(
224
+			'batch_file_runner_init',
225
+			BATCH_URL . 'assets/batch_file_runner_init.js',
226
+			['batch_runner'],
227
+			date('Y-m-d-H:i', time()),
228
+			true
229
+		);
230
+		wp_localize_script('batch_file_runner_init', 'ee_job_response', $job_response->to_array());
231
+		wp_localize_script('batch_file_runner_init', 'eei18n', EE_Registry::$i18n_js_strings);
232
+
233
+		$return_url = EED_Batch::getRequest()->getRequestParam('return_url', '', 'url');
234
+		if ($return_url) {
235
+			wp_localize_script(
236
+				'batch_file_runner_init',
237
+				'ee_job_i18n',
238
+				['return_url' => $return_url]
239
+			);
240
+		}
241
+	}
242
+
243
+
244
+	/**
245
+	 * Enqueues scripts and styles common to any batch job, and creates
246
+	 * a job from the request data, and stores the response in the
247
+	 * $this->_job_step_response property
248
+	 *
249
+	 * @return JobStepResponse
250
+	 */
251
+	protected function _enqueue_batch_job_scripts_and_styles_and_start_job(): JobStepResponse
252
+	{
253
+		// just copy the bits of EE admin's eei18n that we need in the JS
254
+		EE_Registry::$i18n_js_strings['batchJobError'] = __(
255
+			'An error occurred and the job has been stopped. Please refresh the page to try again.',
256
+			'event_espresso'
257
+		);
258
+		EE_Registry::$i18n_js_strings['is_admin']      = is_admin();
259
+		wp_enqueue_style(
260
+			EspressoLegacyAdminAssetManager::CSS_HANDLE_EE_ADMIN,
261
+			EE_ADMIN_URL . 'assets/ee-admin-page.css',
262
+			[],
263
+			EVENT_ESPRESSO_VERSION
264
+		);
265
+		wp_enqueue_style(
266
+			'batch_runner',
267
+			BATCH_URL . 'assets/batch_runner.css',
268
+			[EspressoLegacyAdminAssetManager::CSS_HANDLE_EE_ADMIN],
269
+			date('Y-m-d-H:i', time())
270
+		);
271
+		wp_register_script(
272
+			'progress_bar',
273
+			EE_PLUGIN_DIR_URL . 'core/libraries/batch/Assets/progress_bar.js',
274
+			['jquery'],
275
+			date('Y-m-d-H:i', time()),
276
+			true
277
+		);
278
+		wp_enqueue_style(
279
+			'progress_bar',
280
+			EE_PLUGIN_DIR_URL . 'core/libraries/batch/Assets/progress_bar.css',
281
+			[],
282
+			date('Y-m-d-H:i', time())
283
+		);
284
+		wp_enqueue_script(
285
+			'batch_runner',
286
+			EE_PLUGIN_DIR_URL . 'core/libraries/batch/Assets/batch_runner.js',
287
+			['progress_bar', CoreAssetManager::JS_HANDLE_CORE],
288
+			date('Y-m-d-H:i', time()),
289
+			true
290
+		);
291
+		/** @var BatchRequestProcessor $batch_runner */
292
+		$batch_runner = $this->getLoader()->getShared('EventEspressoBatchRequest\BatchRequestProcessor');
293
+		// eg 'EventEspressoBatchRequest\JobHandlers\RegistrationsReport'
294
+		// remember the response for later. We need it to display the page body
295
+		$this->_job_step_response = $batch_runner->createJob();
296
+		return $this->_job_step_response;
297
+	}
298
+
299
+
300
+	/**
301
+	 * If we are doing a frontend batch job, this makes it so WP shows our template's HTML
302
+	 *
303
+	 * @param string $template
304
+	 * @return string
305
+	 */
306
+	public function override_template(string $template): string
307
+	{
308
+		$request = EED_Batch::getRequest();
309
+		if ($request->requestParamIsSet('batch') && $request->requestParamIsSet(EED_Batch::PAGE_SLUG)) {
310
+			return EE_MODULES . 'batch/templates/batch_frontend_wrapper.template.php';
311
+		}
312
+		return $template;
313
+	}
314
+
315
+
316
+	/**
317
+	 * Adds an admin page which doesn't appear in the admin menu
318
+	 *
319
+	 * @throws EE_Error
320
+	 * @throws ReflectionException
321
+	 */
322
+	public function register_admin_pages()
323
+	{
324
+		add_submenu_page(
325
+			'',
326
+			// parent slug. we don't want this to actually appear in the menu
327
+			esc_html__('Batch Job', 'event_espresso'),
328
+			// page title
329
+			'n/a',
330
+			// menu title
331
+			'read',
332
+			// we want this page to actually be accessible to anyone,
333
+			EED_Batch::PAGE_SLUG,
334
+			// menu slug
335
+			[self::instance(), 'show_admin_page']
336
+		);
337
+	}
338
+
339
+
340
+	/**
341
+	 * Renders the admin page, after most of the work was already done during enqueuing scripts
342
+	 * of creating the job and localizing some data
343
+	 */
344
+	public function show_admin_page()
345
+	{
346
+		echo EEH_Template::locate_template(
347
+			EE_MODULES . 'batch/templates/batch_wrapper.template.php',
348
+			[
349
+				'batch_request_type'        => $this->batch_request_type(),
350
+				'auto_redirect_on_complete' => EED_Batch::getRequest()->getRequestParam('auto_redirect_on_complete'),
351
+				'user_message'              => EED_Batch::getRequest()->getRequestParam('assessment_notice')
352
+					?: EED_Batch::getRequest()->getRequestParam('job_start_notice'),
353
+			]
354
+		);
355
+	}
356
+
357
+
358
+	private function runBatchRunnerJob(string $job)
359
+	{
360
+		$job_id = EED_Batch::getRequest()->getRequestParam('job_id');
361
+		/** @var BatchRequestProcessor $batch_runner */
362
+		$batch_runner = $this->getLoader()->getShared('EventEspressoBatchRequest\BatchRequestProcessor');
363
+		$job_response = $batch_runner->{$job}($job_id);
364
+		$this->_return_json($job_response->to_array());
365
+	}
366
+
367
+
368
+	/**
369
+	 * Receives ajax calls for continuing a job
370
+	 */
371
+	public function continueBatchJob()
372
+	{
373
+		$this->runBatchRunnerJob('continueJob');
374
+	}
375
+
376
+
377
+	/**
378
+	 * Receives ajax calls for continuing a job
379
+	 */
380
+	public function advanceBatchJob()
381
+	{
382
+		$this->runBatchRunnerJob('advanceJob');
383
+	}
384
+
385
+
386
+	/**
387
+	 * Receives the ajax call to cleanup a job
388
+	 *
389
+	 * @return void
390
+	 */
391
+	public function cleanupBatchJob()
392
+	{
393
+		$this->runBatchRunnerJob('cleanupJob');
394
+	}
395
+
396
+
397
+	/**
398
+	 * Returns a json response
399
+	 *
400
+	 * @param array $data The data we want to send echo via in the JSON response's "data" element
401
+	 *
402
+	 * The returned json object is created from an array in the following format:
403
+	 * array(
404
+	 *    'notices' => '', // - contains any EE_Error formatted notices
405
+	 *    'data' => array() //this can be any key/value pairs that a method returns for later json parsing by the js.
406
+	 *    We're also going to include the template args with every package (so js can pick out any specific template
407
+	 *    args that might be included in here)
408
+	 *    'isEEajax' => true,//indicates this is a response from EE
409
+	 * )
410
+	 */
411
+	protected function _return_json(array $data)
412
+	{
413
+		$json = [
414
+			'notices'  => EE_Error::get_notices(),
415
+			'data'     => $data,
416
+			'isEEajax' => true
417
+			// special flag so any ajax.Success methods in js can identify this return package as a EEajax package.
418
+		];
419
+
420
+		// make sure there are no php errors or headers_sent.  Then we can set correct json header.
421
+		if (error_get_last() === null || ! headers_sent()) {
422
+			header('Content-Type: application/json; charset=UTF-8');
423
+			echo wp_json_encode($json);
424
+			exit();
425
+		}
426
+	}
427
+
428
+
429
+	/**
430
+	 * Gets the job step response which was done during the enqueuing of scripts
431
+	 *
432
+	 * @return JobStepResponse
433
+	 */
434
+	public function job_step_response(): JobStepResponse
435
+	{
436
+		return $this->_job_step_response;
437
+	}
438
+
439
+
440
+	/**
441
+	 * Gets the batch request type indicated in the current request
442
+	 *
443
+	 * @return string: EED_Batch::batch_job, EED_Batch::batch_file_job, EED_Batch::batch_not_job
444
+	 */
445
+	public function batch_request_type(): string
446
+	{
447
+		if (! $this->_batch_request_type) {
448
+			$request = EED_Batch::getRequest();
449
+			$batch   = $request->getRequestParam('batch');
450
+			switch ($batch) {
451
+				case self::batch_job:
452
+					$this->_batch_request_type = self::batch_job;
453
+					break;
454
+				case self::batch_file_job:
455
+					$this->_batch_request_type = self::batch_file_job;
456
+					break;
457
+				default:
458
+					// if we didn't find that it was a batch request, indicate it wasn't
459
+					$this->_batch_request_type = self::batch_not_job;
460
+			}
461
+		}
462
+		return $this->_batch_request_type;
463
+	}
464
+
465
+
466
+	/**
467
+	 * Unnecessary
468
+	 *
469
+	 * @param WP $WP
470
+	 */
471
+	public function run($WP)
472
+	{
473
+	}
474 474
 }
Please login to merge, or discard this patch.
Spacing   +13 added lines, -13 removed lines patch added patch discarded remove patch
@@ -120,7 +120,7 @@  discard block
 block discarded – undo
120 120
         add_action('wp_ajax_nopriv_espresso_batch_cleanup', [self::instance(), 'cleanupBatchJob']);
121 121
         add_filter(
122 122
             'admin_body_class',
123
-            function ($classes) {
123
+            function($classes) {
124 124
                 if (strpos($classes, 'espresso-admin') === false) {
125 125
                     $classes .= ' espresso-admin';
126 126
                 }
@@ -139,7 +139,7 @@  discard block
 block discarded – undo
139 139
      */
140 140
     protected function getLoader(): LoaderInterface
141 141
     {
142
-        if (! $this->loader instanceof LoaderInterface) {
142
+        if ( ! $this->loader instanceof LoaderInterface) {
143 143
             $this->loader = LoaderFactory::getLoader();
144 144
         }
145 145
         return $this->loader;
@@ -187,7 +187,7 @@  discard block
 block discarded – undo
187 187
         $job_response = $this->_enqueue_batch_job_scripts_and_styles_and_start_job();
188 188
         wp_enqueue_script(
189 189
             'batch_runner_init',
190
-            BATCH_URL . 'assets/batch_runner_init.js',
190
+            BATCH_URL.'assets/batch_runner_init.js',
191 191
             ['batch_runner'],
192 192
             date('Y-m-d-H:i', time()),
193 193
             true
@@ -222,7 +222,7 @@  discard block
 block discarded – undo
222 222
         $job_response = $this->_enqueue_batch_job_scripts_and_styles_and_start_job();
223 223
         wp_enqueue_script(
224 224
             'batch_file_runner_init',
225
-            BATCH_URL . 'assets/batch_file_runner_init.js',
225
+            BATCH_URL.'assets/batch_file_runner_init.js',
226 226
             ['batch_runner'],
227 227
             date('Y-m-d-H:i', time()),
228 228
             true
@@ -255,35 +255,35 @@  discard block
 block discarded – undo
255 255
             'An error occurred and the job has been stopped. Please refresh the page to try again.',
256 256
             'event_espresso'
257 257
         );
258
-        EE_Registry::$i18n_js_strings['is_admin']      = is_admin();
258
+        EE_Registry::$i18n_js_strings['is_admin'] = is_admin();
259 259
         wp_enqueue_style(
260 260
             EspressoLegacyAdminAssetManager::CSS_HANDLE_EE_ADMIN,
261
-            EE_ADMIN_URL . 'assets/ee-admin-page.css',
261
+            EE_ADMIN_URL.'assets/ee-admin-page.css',
262 262
             [],
263 263
             EVENT_ESPRESSO_VERSION
264 264
         );
265 265
         wp_enqueue_style(
266 266
             'batch_runner',
267
-            BATCH_URL . 'assets/batch_runner.css',
267
+            BATCH_URL.'assets/batch_runner.css',
268 268
             [EspressoLegacyAdminAssetManager::CSS_HANDLE_EE_ADMIN],
269 269
             date('Y-m-d-H:i', time())
270 270
         );
271 271
         wp_register_script(
272 272
             'progress_bar',
273
-            EE_PLUGIN_DIR_URL . 'core/libraries/batch/Assets/progress_bar.js',
273
+            EE_PLUGIN_DIR_URL.'core/libraries/batch/Assets/progress_bar.js',
274 274
             ['jquery'],
275 275
             date('Y-m-d-H:i', time()),
276 276
             true
277 277
         );
278 278
         wp_enqueue_style(
279 279
             'progress_bar',
280
-            EE_PLUGIN_DIR_URL . 'core/libraries/batch/Assets/progress_bar.css',
280
+            EE_PLUGIN_DIR_URL.'core/libraries/batch/Assets/progress_bar.css',
281 281
             [],
282 282
             date('Y-m-d-H:i', time())
283 283
         );
284 284
         wp_enqueue_script(
285 285
             'batch_runner',
286
-            EE_PLUGIN_DIR_URL . 'core/libraries/batch/Assets/batch_runner.js',
286
+            EE_PLUGIN_DIR_URL.'core/libraries/batch/Assets/batch_runner.js',
287 287
             ['progress_bar', CoreAssetManager::JS_HANDLE_CORE],
288 288
             date('Y-m-d-H:i', time()),
289 289
             true
@@ -307,7 +307,7 @@  discard block
 block discarded – undo
307 307
     {
308 308
         $request = EED_Batch::getRequest();
309 309
         if ($request->requestParamIsSet('batch') && $request->requestParamIsSet(EED_Batch::PAGE_SLUG)) {
310
-            return EE_MODULES . 'batch/templates/batch_frontend_wrapper.template.php';
310
+            return EE_MODULES.'batch/templates/batch_frontend_wrapper.template.php';
311 311
         }
312 312
         return $template;
313 313
     }
@@ -344,7 +344,7 @@  discard block
 block discarded – undo
344 344
     public function show_admin_page()
345 345
     {
346 346
         echo EEH_Template::locate_template(
347
-            EE_MODULES . 'batch/templates/batch_wrapper.template.php',
347
+            EE_MODULES.'batch/templates/batch_wrapper.template.php',
348 348
             [
349 349
                 'batch_request_type'        => $this->batch_request_type(),
350 350
                 'auto_redirect_on_complete' => EED_Batch::getRequest()->getRequestParam('auto_redirect_on_complete'),
@@ -444,7 +444,7 @@  discard block
 block discarded – undo
444 444
      */
445 445
     public function batch_request_type(): string
446 446
     {
447
-        if (! $this->_batch_request_type) {
447
+        if ( ! $this->_batch_request_type) {
448 448
             $request = EED_Batch::getRequest();
449 449
             $batch   = $request->getRequestParam('batch');
450 450
             switch ($batch) {
Please login to merge, or discard this patch.