Completed
Branch master (d65695)
by
unknown
04:25
created
caffeinated/admin/extend/events/Extend_Events_Admin_Page.core.php 1 patch
Indentation   +1279 added lines, -1279 removed lines patch added patch discarded remove patch
@@ -16,1289 +16,1289 @@
 block discarded – undo
16 16
  */
17 17
 class Extend_Events_Admin_Page extends Events_Admin_Page
18 18
 {
19
-    /**
20
-     * @var EE_Admin_Config
21
-     */
22
-    protected $admin_config;
23
-
24
-
25
-    /**
26
-     * Extend_Events_Admin_Page constructor.
27
-     *
28
-     * @param bool $routing
29
-     * @throws ReflectionException
30
-     */
31
-    public function __construct($routing = true)
32
-    {
33
-        if (! defined('EVENTS_CAF_TEMPLATE_PATH')) {
34
-            define('EVENTS_CAF_TEMPLATE_PATH', EE_CORE_CAF_ADMIN_EXTEND . 'events/templates/');
35
-            define('EVENTS_CAF_ASSETS', EE_CORE_CAF_ADMIN_EXTEND . 'events/assets/');
36
-            define('EVENTS_CAF_ASSETS_URL', EE_CORE_CAF_ADMIN_EXTEND_URL . 'events/assets/');
37
-        }
38
-        parent::__construct($routing);
39
-        $this->admin_config = $this->loader->getShared('EE_Admin_Config');
40
-    }
41
-
42
-
43
-    protected function _set_page_config()
44
-    {
45
-        parent::_set_page_config();
46
-
47
-        $this->_admin_base_path = EE_CORE_CAF_ADMIN_EXTEND . 'events';
48
-        // is there a evt_id in the request?
49
-        $EVT_ID                                          = $this->request->getRequestParam('EVT_ID', 0, 'int');
50
-        $EVT_ID                                          = $this->request->getRequestParam('post', $EVT_ID, 'int');
51
-        $TKT_ID                                          = $this->request->getRequestParam('TKT_ID', 0, 'int');
52
-        $new_page_routes                                 = [
53
-            'duplicate_event'          => [
54
-                'func'       => '_duplicate_event',
55
-                'capability' => 'ee_edit_event',
56
-                'obj_id'     => $EVT_ID,
57
-                'noheader'   => true,
58
-            ],
59
-            'import_page'              => [
60
-                'func'       => '_import_page',
61
-                'capability' => 'import',
62
-            ],
63
-            'import'                   => [
64
-                'func'       => '_import_events',
65
-                'capability' => 'import',
66
-                'noheader'   => true,
67
-            ],
68
-            'import_events'            => [
69
-                'func'       => '_import_events',
70
-                'capability' => 'import',
71
-                'noheader'   => true,
72
-            ],
73
-            'export_events'            => [
74
-                'func'       => '_events_export',
75
-                'capability' => 'export',
76
-                'noheader'   => true,
77
-            ],
78
-            'export_categories'        => [
79
-                'func'       => '_categories_export',
80
-                'capability' => 'export',
81
-                'noheader'   => true,
82
-            ],
83
-            'sample_export_file'       => [
84
-                'func'       => '_sample_export_file',
85
-                'capability' => 'export',
86
-                'noheader'   => true,
87
-            ],
88
-            'update_template_settings' => [
89
-                'func'       => '_update_template_settings',
90
-                'capability' => 'manage_options',
91
-                'noheader'   => true,
92
-            ],
93
-            'ticket_list_table'        => [
94
-                'func'       => '_tickets_overview_list_table',
95
-                'capability' => 'ee_read_default_tickets',
96
-            ],
97
-        ];
98
-        $this->_page_config['create_new']['metaboxes'][] = '_premium_event_editor_meta_boxes';
99
-        $this->_page_config['edit']['metaboxes'][]       = '_premium_event_editor_meta_boxes';
100
-        // don't load these meta boxes if using the advanced editor
101
-        if (
102
-            ! $this->admin_config->useAdvancedEditor()
103
-            || ! $this->feature->allowed('use_default_ticket_manager')
104
-        ) {
105
-            $this->_page_config['create_new']['qtips'][] = 'EE_Event_Editor_Tips';
106
-            $this->_page_config['edit']['qtips'][]       = 'EE_Event_Editor_Tips';
107
-
108
-            $legacy_editor_page_routes = [
109
-                'trash_ticket'    => [
110
-                    'func'       => '_trash_or_restore_ticket',
111
-                    'capability' => 'ee_delete_default_ticket',
112
-                    'obj_id'     => $TKT_ID,
113
-                    'noheader'   => true,
114
-                    'args'       => ['trash' => true],
115
-                ],
116
-                'trash_tickets'   => [
117
-                    'func'       => '_trash_or_restore_ticket',
118
-                    'capability' => 'ee_delete_default_tickets',
119
-                    'noheader'   => true,
120
-                    'args'       => ['trash' => true],
121
-                ],
122
-                'restore_ticket'  => [
123
-                    'func'       => '_trash_or_restore_ticket',
124
-                    'capability' => 'ee_delete_default_ticket',
125
-                    'obj_id'     => $TKT_ID,
126
-                    'noheader'   => true,
127
-                ],
128
-                'restore_tickets' => [
129
-                    'func'       => '_trash_or_restore_ticket',
130
-                    'capability' => 'ee_delete_default_tickets',
131
-                    'noheader'   => true,
132
-                ],
133
-                'delete_ticket'   => [
134
-                    'func'       => '_delete_ticket',
135
-                    'capability' => 'ee_delete_default_ticket',
136
-                    'obj_id'     => $TKT_ID,
137
-                    'noheader'   => true,
138
-                ],
139
-                'delete_tickets'  => [
140
-                    'func'       => '_delete_ticket',
141
-                    'capability' => 'ee_delete_default_tickets',
142
-                    'noheader'   => true,
143
-                ],
144
-            ];
145
-            $new_page_routes           = array_merge($new_page_routes, $legacy_editor_page_routes);
146
-        }
147
-
148
-        $this->_page_routes = array_merge($this->_page_routes, $new_page_routes);
149
-        // partial route/config override
150
-        $this->_page_config['import_events']['metaboxes'] = $this->_default_espresso_metaboxes;
151
-        $this->_page_config['default']['list_table']      = 'Extend_Events_Admin_List_Table';
152
-
153
-        // add default tickets tab and template settings nav tabs (note union at end)
154
-        $this->_page_config = [
155
-                                  'ticket_list_table' => [
156
-                                      'nav'           => [
157
-                                          'label' => esc_html__('Default Tickets', 'event_espresso'),
158
-                                          'icon'  => 'dashicons-tickets-alt',
159
-                                          'order' => 60,
160
-                                      ],
161
-                                      'list_table'    => 'Tickets_List_Table',
162
-                                      'require_nonce' => false,
163
-                                  ],
164
-                                  'template_settings' => [
165
-                                      'nav'           => [
166
-                                          'label' => esc_html__('Templates', 'event_espresso'),
167
-                                          'icon'  => 'dashicons-layout',
168
-                                          'order' => 30,
169
-                                      ],
170
-                                      'metaboxes'     => array_merge(
171
-                                          ['_publish_post_box'],
172
-                                          $this->_default_espresso_metaboxes
173
-                                      ),
174
-                                      'help_tabs'     => [
175
-                                          'general_settings_templates_help_tab' => [
176
-                                              'title'    => esc_html__('Templates', 'event_espresso'),
177
-                                              'filename' => 'general_settings_templates',
178
-                                          ],
179
-                                      ],
180
-                                      'require_nonce' => false,
181
-                                  ],
182
-                              ] + $this->_page_config;
183
-
184
-        // add filters and actions
185
-        // modifying _views
186
-        add_filter(
187
-            'FHEE_event_datetime_metabox_add_additional_date_time_template',
188
-            [$this, 'add_additional_datetime_button'],
189
-            10,
190
-            2
191
-        );
192
-        add_filter(
193
-            'FHEE_event_datetime_metabox_clone_button_template',
194
-            [$this, 'add_datetime_clone_button'],
195
-            10,
196
-            2
197
-        );
198
-        add_filter(
199
-            'FHEE_event_datetime_metabox_timezones_template',
200
-            [$this, 'datetime_timezones_template'],
201
-            10,
202
-            2
203
-        );
204
-        // filters for event list table
205
-        add_filter(
206
-            'FHEE__Events_Admin_List_Table__column_actions__action_links',
207
-            [$this, 'extra_list_table_actions'],
208
-            10,
209
-            2
210
-        );
211
-        // legend item
212
-        add_filter('FHEE__Events_Admin_Page___event_legend_items__items', [$this, 'additional_legend_items']);
213
-        add_action('admin_init', [$this, 'admin_init']);
214
-        // this is a filter that allows the addition of extra html after the permalink field on the wp post edit-form
215
-        add_filter('get_sample_permalink_html', [DuplicateEventButton::class, 'addButton'], 8, 4);
216
-    }
217
-
218
-
219
-    /**
220
-     * admin_init
221
-     */
222
-    public function admin_init()
223
-    {
224
-        EE_Registry::$i18n_js_strings = array_merge(
225
-            EE_Registry::$i18n_js_strings,
226
-            [
227
-                'image_confirm'          => esc_html__(
228
-                    'Do you really want to delete this image? Please remember to update your event to complete the removal.',
229
-                    'event_espresso'
230
-                ),
231
-                'event_starts_on'        => esc_html__('Event Starts on', 'event_espresso'),
232
-                'event_ends_on'          => esc_html__('Event Ends on', 'event_espresso'),
233
-                'event_datetime_actions' => esc_html__('Actions', 'event_espresso'),
234
-                'event_clone_dt_msg'     => esc_html__('Clone this Event Date and Time', 'event_espresso'),
235
-                'remove_event_dt_msg'    => esc_html__('Remove this Event Time', 'event_espresso'),
236
-            ]
237
-        );
238
-    }
239
-
240
-
241
-    /**
242
-     * Add per page screen options to the default ticket list table view.
243
-     *
244
-     * @throws InvalidArgumentException
245
-     * @throws InvalidDataTypeException
246
-     * @throws InvalidInterfaceException
247
-     */
248
-    protected function _add_screen_options_ticket_list_table()
249
-    {
250
-        $this->_per_page_screen_option();
251
-    }
252
-
253
-
254
-    /**
255
-     * @param string      $return    the current html
256
-     * @param int         $id        the post id for the page
257
-     * @param string|null $new_title What the title is
258
-     * @param string|null $new_slug  what the slug is
259
-     * @return string
260
-     * @deprecated 5.0.0.p
261
-     */
262
-    public function extra_permalink_field_buttons(
263
-        string $return,
264
-        int $id,
265
-        ?string $new_title,
266
-        ?string $new_slug
267
-    ): string {
268
-        $return = DuplicateEventButton::addButton($return, $id, $new_title, $new_slug);
269
-        return TicketSelectorShortcodeButton::addButton($return, $id, $new_title, $new_slug);
270
-    }
271
-
272
-
273
-    /**
274
-     * Set the list table views for the default ticket list table view.
275
-     */
276
-    public function _set_list_table_views_ticket_list_table()
277
-    {
278
-        $this->_views = [
279
-            'all'     => [
280
-                'slug'        => 'all',
281
-                'label'       => esc_html__('All', 'event_espresso'),
282
-                'count'       => 0,
283
-                'bulk_action' => [
284
-                    'trash_tickets' => esc_html__('Move to Trash', 'event_espresso'),
285
-                ],
286
-            ],
287
-            'trashed' => [
288
-                'slug'        => 'trashed',
289
-                'label'       => esc_html__('Trash', 'event_espresso'),
290
-                'count'       => 0,
291
-                'bulk_action' => [
292
-                    'restore_tickets' => esc_html__('Restore from Trash', 'event_espresso'),
293
-                    'delete_tickets'  => esc_html__('Delete Permanently', 'event_espresso'),
294
-                ],
295
-            ],
296
-        ];
297
-    }
298
-
299
-
300
-    /**
301
-     * Enqueue scripts and styles for the event editor.
302
-     */
303
-    public function load_scripts_styles_edit()
304
-    {
305
-        if (! $this->admin_config->useAdvancedEditor()) {
306
-            wp_register_script(
307
-                'ee-event-editor-heartbeat',
308
-                EVENTS_CAF_ASSETS_URL . 'event-editor-heartbeat.js',
309
-                ['ee_admin_js', 'heartbeat'],
310
-                EVENT_ESPRESSO_VERSION,
311
-                true
312
-            );
313
-            wp_enqueue_script('ee-accounting');
314
-            wp_enqueue_script('ee-event-editor-heartbeat');
315
-        }
316
-        wp_enqueue_script('event_editor_js');
317
-        wp_register_style(
318
-            'event-editor-css',
319
-            EVENTS_ASSETS_URL . 'event-editor.css',
320
-            ['ee-admin-css'],
321
-            EVENT_ESPRESSO_VERSION
322
-        );
323
-        wp_enqueue_style('event-editor-css');
324
-        // styles
325
-        wp_enqueue_style('espresso-ui-theme');
326
-    }
327
-
328
-
329
-    /**
330
-     * Sets the views for the default list table view.
331
-     *
332
-     * @throws EE_Error
333
-     * @throws ReflectionException
334
-     */
335
-    protected function _set_list_table_views_default()
336
-    {
337
-        parent::_set_list_table_views_default();
338
-        $new_views    = [
339
-            'today' => [
340
-                'slug'        => 'today',
341
-                'label'       => esc_html__('Today', 'event_espresso'),
342
-                'count'       => $this->total_events_today(),
343
-                'bulk_action' => [
344
-                    'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
345
-                ],
346
-            ],
347
-            'month' => [
348
-                'slug'        => 'month',
349
-                'label'       => esc_html__('This Month', 'event_espresso'),
350
-                'count'       => $this->total_events_this_month(),
351
-                'bulk_action' => [
352
-                    'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
353
-                ],
354
-            ],
355
-        ];
356
-        $this->_views = array_merge($this->_views, $new_views);
357
-    }
358
-
359
-
360
-    /**
361
-     * Returns the extra action links for the default list table view.
362
-     *
363
-     * @param array    $action_links
364
-     * @param EE_Event $event
365
-     * @return array
366
-     * @throws EE_Error
367
-     * @throws ReflectionException
368
-     */
369
-    public function extra_list_table_actions(array $action_links, EE_Event $event): array
370
-    {
371
-        if (
372
-        EE_Registry::instance()->CAP->current_user_can(
373
-            'ee_read_registrations',
374
-            'espresso_registrations_reports',
375
-            $event->ID()
376
-        )
377
-        ) {
378
-            $reports_link = EE_Admin_Page::add_query_args_and_nonce(
379
-                [
380
-                    'action' => 'reports',
381
-                    'EVT_ID' => $event->ID(),
382
-                ],
383
-                REG_ADMIN_URL
384
-            );
385
-
386
-            $action_links[] = '
19
+	/**
20
+	 * @var EE_Admin_Config
21
+	 */
22
+	protected $admin_config;
23
+
24
+
25
+	/**
26
+	 * Extend_Events_Admin_Page constructor.
27
+	 *
28
+	 * @param bool $routing
29
+	 * @throws ReflectionException
30
+	 */
31
+	public function __construct($routing = true)
32
+	{
33
+		if (! defined('EVENTS_CAF_TEMPLATE_PATH')) {
34
+			define('EVENTS_CAF_TEMPLATE_PATH', EE_CORE_CAF_ADMIN_EXTEND . 'events/templates/');
35
+			define('EVENTS_CAF_ASSETS', EE_CORE_CAF_ADMIN_EXTEND . 'events/assets/');
36
+			define('EVENTS_CAF_ASSETS_URL', EE_CORE_CAF_ADMIN_EXTEND_URL . 'events/assets/');
37
+		}
38
+		parent::__construct($routing);
39
+		$this->admin_config = $this->loader->getShared('EE_Admin_Config');
40
+	}
41
+
42
+
43
+	protected function _set_page_config()
44
+	{
45
+		parent::_set_page_config();
46
+
47
+		$this->_admin_base_path = EE_CORE_CAF_ADMIN_EXTEND . 'events';
48
+		// is there a evt_id in the request?
49
+		$EVT_ID                                          = $this->request->getRequestParam('EVT_ID', 0, 'int');
50
+		$EVT_ID                                          = $this->request->getRequestParam('post', $EVT_ID, 'int');
51
+		$TKT_ID                                          = $this->request->getRequestParam('TKT_ID', 0, 'int');
52
+		$new_page_routes                                 = [
53
+			'duplicate_event'          => [
54
+				'func'       => '_duplicate_event',
55
+				'capability' => 'ee_edit_event',
56
+				'obj_id'     => $EVT_ID,
57
+				'noheader'   => true,
58
+			],
59
+			'import_page'              => [
60
+				'func'       => '_import_page',
61
+				'capability' => 'import',
62
+			],
63
+			'import'                   => [
64
+				'func'       => '_import_events',
65
+				'capability' => 'import',
66
+				'noheader'   => true,
67
+			],
68
+			'import_events'            => [
69
+				'func'       => '_import_events',
70
+				'capability' => 'import',
71
+				'noheader'   => true,
72
+			],
73
+			'export_events'            => [
74
+				'func'       => '_events_export',
75
+				'capability' => 'export',
76
+				'noheader'   => true,
77
+			],
78
+			'export_categories'        => [
79
+				'func'       => '_categories_export',
80
+				'capability' => 'export',
81
+				'noheader'   => true,
82
+			],
83
+			'sample_export_file'       => [
84
+				'func'       => '_sample_export_file',
85
+				'capability' => 'export',
86
+				'noheader'   => true,
87
+			],
88
+			'update_template_settings' => [
89
+				'func'       => '_update_template_settings',
90
+				'capability' => 'manage_options',
91
+				'noheader'   => true,
92
+			],
93
+			'ticket_list_table'        => [
94
+				'func'       => '_tickets_overview_list_table',
95
+				'capability' => 'ee_read_default_tickets',
96
+			],
97
+		];
98
+		$this->_page_config['create_new']['metaboxes'][] = '_premium_event_editor_meta_boxes';
99
+		$this->_page_config['edit']['metaboxes'][]       = '_premium_event_editor_meta_boxes';
100
+		// don't load these meta boxes if using the advanced editor
101
+		if (
102
+			! $this->admin_config->useAdvancedEditor()
103
+			|| ! $this->feature->allowed('use_default_ticket_manager')
104
+		) {
105
+			$this->_page_config['create_new']['qtips'][] = 'EE_Event_Editor_Tips';
106
+			$this->_page_config['edit']['qtips'][]       = 'EE_Event_Editor_Tips';
107
+
108
+			$legacy_editor_page_routes = [
109
+				'trash_ticket'    => [
110
+					'func'       => '_trash_or_restore_ticket',
111
+					'capability' => 'ee_delete_default_ticket',
112
+					'obj_id'     => $TKT_ID,
113
+					'noheader'   => true,
114
+					'args'       => ['trash' => true],
115
+				],
116
+				'trash_tickets'   => [
117
+					'func'       => '_trash_or_restore_ticket',
118
+					'capability' => 'ee_delete_default_tickets',
119
+					'noheader'   => true,
120
+					'args'       => ['trash' => true],
121
+				],
122
+				'restore_ticket'  => [
123
+					'func'       => '_trash_or_restore_ticket',
124
+					'capability' => 'ee_delete_default_ticket',
125
+					'obj_id'     => $TKT_ID,
126
+					'noheader'   => true,
127
+				],
128
+				'restore_tickets' => [
129
+					'func'       => '_trash_or_restore_ticket',
130
+					'capability' => 'ee_delete_default_tickets',
131
+					'noheader'   => true,
132
+				],
133
+				'delete_ticket'   => [
134
+					'func'       => '_delete_ticket',
135
+					'capability' => 'ee_delete_default_ticket',
136
+					'obj_id'     => $TKT_ID,
137
+					'noheader'   => true,
138
+				],
139
+				'delete_tickets'  => [
140
+					'func'       => '_delete_ticket',
141
+					'capability' => 'ee_delete_default_tickets',
142
+					'noheader'   => true,
143
+				],
144
+			];
145
+			$new_page_routes           = array_merge($new_page_routes, $legacy_editor_page_routes);
146
+		}
147
+
148
+		$this->_page_routes = array_merge($this->_page_routes, $new_page_routes);
149
+		// partial route/config override
150
+		$this->_page_config['import_events']['metaboxes'] = $this->_default_espresso_metaboxes;
151
+		$this->_page_config['default']['list_table']      = 'Extend_Events_Admin_List_Table';
152
+
153
+		// add default tickets tab and template settings nav tabs (note union at end)
154
+		$this->_page_config = [
155
+								  'ticket_list_table' => [
156
+									  'nav'           => [
157
+										  'label' => esc_html__('Default Tickets', 'event_espresso'),
158
+										  'icon'  => 'dashicons-tickets-alt',
159
+										  'order' => 60,
160
+									  ],
161
+									  'list_table'    => 'Tickets_List_Table',
162
+									  'require_nonce' => false,
163
+								  ],
164
+								  'template_settings' => [
165
+									  'nav'           => [
166
+										  'label' => esc_html__('Templates', 'event_espresso'),
167
+										  'icon'  => 'dashicons-layout',
168
+										  'order' => 30,
169
+									  ],
170
+									  'metaboxes'     => array_merge(
171
+										  ['_publish_post_box'],
172
+										  $this->_default_espresso_metaboxes
173
+									  ),
174
+									  'help_tabs'     => [
175
+										  'general_settings_templates_help_tab' => [
176
+											  'title'    => esc_html__('Templates', 'event_espresso'),
177
+											  'filename' => 'general_settings_templates',
178
+										  ],
179
+									  ],
180
+									  'require_nonce' => false,
181
+								  ],
182
+							  ] + $this->_page_config;
183
+
184
+		// add filters and actions
185
+		// modifying _views
186
+		add_filter(
187
+			'FHEE_event_datetime_metabox_add_additional_date_time_template',
188
+			[$this, 'add_additional_datetime_button'],
189
+			10,
190
+			2
191
+		);
192
+		add_filter(
193
+			'FHEE_event_datetime_metabox_clone_button_template',
194
+			[$this, 'add_datetime_clone_button'],
195
+			10,
196
+			2
197
+		);
198
+		add_filter(
199
+			'FHEE_event_datetime_metabox_timezones_template',
200
+			[$this, 'datetime_timezones_template'],
201
+			10,
202
+			2
203
+		);
204
+		// filters for event list table
205
+		add_filter(
206
+			'FHEE__Events_Admin_List_Table__column_actions__action_links',
207
+			[$this, 'extra_list_table_actions'],
208
+			10,
209
+			2
210
+		);
211
+		// legend item
212
+		add_filter('FHEE__Events_Admin_Page___event_legend_items__items', [$this, 'additional_legend_items']);
213
+		add_action('admin_init', [$this, 'admin_init']);
214
+		// this is a filter that allows the addition of extra html after the permalink field on the wp post edit-form
215
+		add_filter('get_sample_permalink_html', [DuplicateEventButton::class, 'addButton'], 8, 4);
216
+	}
217
+
218
+
219
+	/**
220
+	 * admin_init
221
+	 */
222
+	public function admin_init()
223
+	{
224
+		EE_Registry::$i18n_js_strings = array_merge(
225
+			EE_Registry::$i18n_js_strings,
226
+			[
227
+				'image_confirm'          => esc_html__(
228
+					'Do you really want to delete this image? Please remember to update your event to complete the removal.',
229
+					'event_espresso'
230
+				),
231
+				'event_starts_on'        => esc_html__('Event Starts on', 'event_espresso'),
232
+				'event_ends_on'          => esc_html__('Event Ends on', 'event_espresso'),
233
+				'event_datetime_actions' => esc_html__('Actions', 'event_espresso'),
234
+				'event_clone_dt_msg'     => esc_html__('Clone this Event Date and Time', 'event_espresso'),
235
+				'remove_event_dt_msg'    => esc_html__('Remove this Event Time', 'event_espresso'),
236
+			]
237
+		);
238
+	}
239
+
240
+
241
+	/**
242
+	 * Add per page screen options to the default ticket list table view.
243
+	 *
244
+	 * @throws InvalidArgumentException
245
+	 * @throws InvalidDataTypeException
246
+	 * @throws InvalidInterfaceException
247
+	 */
248
+	protected function _add_screen_options_ticket_list_table()
249
+	{
250
+		$this->_per_page_screen_option();
251
+	}
252
+
253
+
254
+	/**
255
+	 * @param string      $return    the current html
256
+	 * @param int         $id        the post id for the page
257
+	 * @param string|null $new_title What the title is
258
+	 * @param string|null $new_slug  what the slug is
259
+	 * @return string
260
+	 * @deprecated 5.0.0.p
261
+	 */
262
+	public function extra_permalink_field_buttons(
263
+		string $return,
264
+		int $id,
265
+		?string $new_title,
266
+		?string $new_slug
267
+	): string {
268
+		$return = DuplicateEventButton::addButton($return, $id, $new_title, $new_slug);
269
+		return TicketSelectorShortcodeButton::addButton($return, $id, $new_title, $new_slug);
270
+	}
271
+
272
+
273
+	/**
274
+	 * Set the list table views for the default ticket list table view.
275
+	 */
276
+	public function _set_list_table_views_ticket_list_table()
277
+	{
278
+		$this->_views = [
279
+			'all'     => [
280
+				'slug'        => 'all',
281
+				'label'       => esc_html__('All', 'event_espresso'),
282
+				'count'       => 0,
283
+				'bulk_action' => [
284
+					'trash_tickets' => esc_html__('Move to Trash', 'event_espresso'),
285
+				],
286
+			],
287
+			'trashed' => [
288
+				'slug'        => 'trashed',
289
+				'label'       => esc_html__('Trash', 'event_espresso'),
290
+				'count'       => 0,
291
+				'bulk_action' => [
292
+					'restore_tickets' => esc_html__('Restore from Trash', 'event_espresso'),
293
+					'delete_tickets'  => esc_html__('Delete Permanently', 'event_espresso'),
294
+				],
295
+			],
296
+		];
297
+	}
298
+
299
+
300
+	/**
301
+	 * Enqueue scripts and styles for the event editor.
302
+	 */
303
+	public function load_scripts_styles_edit()
304
+	{
305
+		if (! $this->admin_config->useAdvancedEditor()) {
306
+			wp_register_script(
307
+				'ee-event-editor-heartbeat',
308
+				EVENTS_CAF_ASSETS_URL . 'event-editor-heartbeat.js',
309
+				['ee_admin_js', 'heartbeat'],
310
+				EVENT_ESPRESSO_VERSION,
311
+				true
312
+			);
313
+			wp_enqueue_script('ee-accounting');
314
+			wp_enqueue_script('ee-event-editor-heartbeat');
315
+		}
316
+		wp_enqueue_script('event_editor_js');
317
+		wp_register_style(
318
+			'event-editor-css',
319
+			EVENTS_ASSETS_URL . 'event-editor.css',
320
+			['ee-admin-css'],
321
+			EVENT_ESPRESSO_VERSION
322
+		);
323
+		wp_enqueue_style('event-editor-css');
324
+		// styles
325
+		wp_enqueue_style('espresso-ui-theme');
326
+	}
327
+
328
+
329
+	/**
330
+	 * Sets the views for the default list table view.
331
+	 *
332
+	 * @throws EE_Error
333
+	 * @throws ReflectionException
334
+	 */
335
+	protected function _set_list_table_views_default()
336
+	{
337
+		parent::_set_list_table_views_default();
338
+		$new_views    = [
339
+			'today' => [
340
+				'slug'        => 'today',
341
+				'label'       => esc_html__('Today', 'event_espresso'),
342
+				'count'       => $this->total_events_today(),
343
+				'bulk_action' => [
344
+					'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
345
+				],
346
+			],
347
+			'month' => [
348
+				'slug'        => 'month',
349
+				'label'       => esc_html__('This Month', 'event_espresso'),
350
+				'count'       => $this->total_events_this_month(),
351
+				'bulk_action' => [
352
+					'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
353
+				],
354
+			],
355
+		];
356
+		$this->_views = array_merge($this->_views, $new_views);
357
+	}
358
+
359
+
360
+	/**
361
+	 * Returns the extra action links for the default list table view.
362
+	 *
363
+	 * @param array    $action_links
364
+	 * @param EE_Event $event
365
+	 * @return array
366
+	 * @throws EE_Error
367
+	 * @throws ReflectionException
368
+	 */
369
+	public function extra_list_table_actions(array $action_links, EE_Event $event): array
370
+	{
371
+		if (
372
+		EE_Registry::instance()->CAP->current_user_can(
373
+			'ee_read_registrations',
374
+			'espresso_registrations_reports',
375
+			$event->ID()
376
+		)
377
+		) {
378
+			$reports_link = EE_Admin_Page::add_query_args_and_nonce(
379
+				[
380
+					'action' => 'reports',
381
+					'EVT_ID' => $event->ID(),
382
+				],
383
+				REG_ADMIN_URL
384
+			);
385
+
386
+			$action_links[] = '
387 387
                 <a href="' . $reports_link . '"
388 388
                     aria-label="' . esc_attr__('View Report', 'event_espresso') . '"
389 389
                     class="ee-aria-tooltip button button--icon-only"
390 390
                 >
391 391
                     <span class="dashicons dashicons-chart-bar"></span>
392 392
                 </a>';
393
-        }
394
-        if (EE_Registry::instance()->CAP->current_user_can('ee_read_global_messages', 'view_filtered_messages')) {
395
-            EE_Registry::instance()->load_helper('MSG_Template');
396
-            $action_links[] = EEH_MSG_Template::get_message_action_link(
397
-                'see_notifications_for',
398
-                null,
399
-                ['EVT_ID' => $event->ID()]
400
-            );
401
-        }
402
-        return $action_links;
403
-    }
404
-
405
-
406
-    /**
407
-     * @param $items
408
-     * @return mixed
409
-     */
410
-    public function additional_legend_items($items)
411
-    {
412
-        if (
413
-        EE_Registry::instance()->CAP->current_user_can(
414
-            'ee_read_registrations',
415
-            'espresso_registrations_reports'
416
-        )
417
-        ) {
418
-            $items['reports'] = [
419
-                'class' => 'dashicons dashicons-chart-bar',
420
-                'desc'  => esc_html__('Event Reports', 'event_espresso'),
421
-            ];
422
-        }
423
-        if (EE_Registry::instance()->CAP->current_user_can('ee_read_global_messages', 'view_filtered_messages')) {
424
-            $related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
425
-            // $related_for_icon can sometimes be a string so 'css_class' would be an illegal offset
426
-            // (can only use numeric offsets when treating strings as arrays)
427
-            if (is_array($related_for_icon) && isset($related_for_icon['css_class'], $related_for_icon['label'])) {
428
-                $items['view_related_messages'] = [
429
-                    'class' => $related_for_icon['css_class'],
430
-                    'desc'  => $related_for_icon['label'],
431
-                ];
432
-            }
433
-        }
434
-        return $items;
435
-    }
436
-
437
-
438
-    /**
439
-     * This is the callback method for the duplicate event route
440
-     * Method looks for 'EVT_ID' in the request and retrieves that event and its details and duplicates them
441
-     * into a new event.  We add a hook so that any plugins that add extra event details can hook into this
442
-     * action.  Note that the dupe will have **DUPLICATE** as its title and slug.
443
-     * After duplication the redirect is to the new event edit page.
444
-     *
445
-     * @return void
446
-     * @throws EE_Error If EE_Event is not available with given ID
447
-     * @throws ReflectionException
448
-     * @access protected
449
-     */
450
-    protected function _duplicate_event()
451
-    {
452
-        // first make sure the ID for the event is in the request.
453
-        //  If it isn't then we need to bail and redirect back to overview list table (cause how did we get here?)
454
-        $EVT_ID = $this->request->getRequestParam('EVT_ID', 0, 'int');
455
-        if (! $EVT_ID) {
456
-            EE_Error::add_error(
457
-                esc_html__(
458
-                    'In order to duplicate an event an Event ID is required.  None was given.',
459
-                    'event_espresso'
460
-                ),
461
-                __FILE__,
462
-                __FUNCTION__,
463
-                __LINE__
464
-            );
465
-            $this->_redirect_after_action(false, '', '', [], true);
466
-            return;
467
-        }
468
-        // k we've got EVT_ID so let's use that to get the event we'll duplicate
469
-        $orig_event = EEM_Event::instance()->get_one_by_ID($EVT_ID);
470
-        if (! $orig_event instanceof EE_Event) {
471
-            throw new EE_Error(
472
-                sprintf(
473
-                    esc_html__('An EE_Event object could not be retrieved for the given ID (%s)', 'event_espresso'),
474
-                    $EVT_ID
475
-                )
476
-            );
477
-        }
478
-        // k now let's clone the $orig_event before getting relations
479
-        $new_event = clone $orig_event;
480
-        // original datetimes
481
-        $orig_datetimes = $orig_event->get_many_related('Datetime');
482
-        // other original relations
483
-        $orig_ven = $orig_event->get_many_related('Venue');
484
-        // reset the ID and modify other details to make it clear this is a dupe
485
-        $new_event->set('EVT_ID', 0);
486
-        $new_name = $new_event->name() . ' ' . esc_html__('**DUPLICATE**', 'event_espresso');
487
-        $new_event->set('EVT_name', $new_name);
488
-        $new_event->set(
489
-            'EVT_slug',
490
-            wp_unique_post_slug(
491
-                sanitize_title($orig_event->name()),
492
-                0,
493
-                'publish',
494
-                'espresso_events',
495
-                0
496
-            )
497
-        );
498
-        $new_event->set('status', 'draft');
499
-        // duplicate discussion settings
500
-        $new_event->set('comment_status', $orig_event->get('comment_status'));
501
-        $new_event->set('ping_status', $orig_event->get('ping_status'));
502
-        // save the new event
503
-        $new_event->save();
504
-        // venues
505
-        foreach ($orig_ven as $ven) {
506
-            $new_event->_add_relation_to($ven, 'Venue');
507
-        }
508
-        $new_event->save();
509
-        // now we need to get the question group relations and handle that
510
-        // first primary question groups
511
-        $orig_primary_qgs = $orig_event->get_many_related(
512
-            'Question_Group',
513
-            [['Event_Question_Group.EQG_primary' => true]]
514
-        );
515
-        if (! empty($orig_primary_qgs)) {
516
-            foreach ($orig_primary_qgs as $obj) {
517
-                if ($obj instanceof EE_Question_Group) {
518
-                    $new_event->_add_relation_to($obj, 'Question_Group', ['EQG_primary' => true]);
519
-                }
520
-            }
521
-        }
522
-        // next additional attendee question groups
523
-        $orig_additional_qgs = $orig_event->get_many_related(
524
-            'Question_Group',
525
-            [['Event_Question_Group.EQG_additional' => true]]
526
-        );
527
-        if (! empty($orig_additional_qgs)) {
528
-            foreach ($orig_additional_qgs as $obj) {
529
-                if ($obj instanceof EE_Question_Group) {
530
-                    $new_event->_add_relation_to($obj, 'Question_Group', ['EQG_additional' => true]);
531
-                }
532
-            }
533
-        }
534
-
535
-        $new_event->save();
536
-
537
-        // k now that we have the new event saved we can loop through the datetimes and start adding relations.
538
-        $cloned_tickets = [];
539
-        foreach ($orig_datetimes as $orig_dtt) {
540
-            if (! $orig_dtt instanceof EE_Datetime) {
541
-                continue;
542
-            }
543
-            $new_dtt      = clone $orig_dtt;
544
-            $orig_tickets = $orig_dtt->tickets();
545
-            // save new dtt then add to event
546
-            $new_dtt->set('DTT_ID', 0);
547
-            $new_dtt->set('DTT_sold', 0);
548
-            $new_dtt->set_reserved(0);
549
-            $new_dtt->save();
550
-            $new_event->_add_relation_to($new_dtt, 'Datetime');
551
-            $new_event->save();
552
-            // now let's get the ticket relations setup.
553
-            foreach ((array) $orig_tickets as $orig_ticket) {
554
-                // it's possible a datetime will have no tickets so let's verify we HAVE a ticket first.
555
-                if (! $orig_ticket instanceof EE_Ticket) {
556
-                    continue;
557
-                }
558
-                // is this ticket archived?  If it is then let's skip
559
-                if ($orig_ticket->get('TKT_deleted')) {
560
-                    continue;
561
-                }
562
-                // does this original ticket already exist in the clone_tickets cache?
563
-                //  If so we'll just use the new ticket from it.
564
-                if (isset($cloned_tickets[ $orig_ticket->ID() ])) {
565
-                    $new_ticket = $cloned_tickets[ $orig_ticket->ID() ];
566
-                } else {
567
-                    $new_ticket = clone $orig_ticket;
568
-                    // get relations on the $orig_ticket that we need to setup.
569
-                    $orig_prices = $orig_ticket->prices();
570
-                    $new_ticket->set('TKT_ID', 0);
571
-                    $new_ticket->set('TKT_sold', 0);
572
-                    $new_ticket->set('TKT_reserved', 0);
573
-                    $new_ticket->save(); // make sure new ticket has ID.
574
-                    // price relations on new ticket need to be setup.
575
-                    foreach ($orig_prices as $orig_price) {
576
-                        $new_price = clone $orig_price;
577
-                        $new_price->set('PRC_ID', 0);
578
-                        $new_price->save();
579
-                        $new_ticket->_add_relation_to($new_price, 'Price');
580
-                        $new_ticket->save();
581
-                    }
582
-
583
-                    do_action(
584
-                        'AHEE__Extend_Events_Admin_Page___duplicate_event__duplicate_ticket__after',
585
-                        $orig_ticket,
586
-                        $new_ticket,
587
-                        $orig_prices,
588
-                        $orig_event,
589
-                        $orig_dtt,
590
-                        $new_dtt
591
-                    );
592
-                }
593
-                // k now we can add the new ticket as a relation to the new datetime
594
-                // and make sure its added to our cached $cloned_tickets array
595
-                // for use with later datetimes that have the same ticket.
596
-                $new_dtt->_add_relation_to($new_ticket, 'Ticket');
597
-                $new_dtt->save();
598
-                $cloned_tickets[ $orig_ticket->ID() ] = $new_ticket;
599
-            }
600
-        }
601
-        // clone taxonomy information
602
-        $taxonomies_to_clone_with = apply_filters(
603
-            'FHEE__Extend_Events_Admin_Page___duplicate_event__taxonomies_to_clone',
604
-            ['espresso_event_categories', 'espresso_event_type', 'post_tag']
605
-        );
606
-        // get terms for original event (notice)
607
-        $orig_terms = wp_get_object_terms($orig_event->ID(), $taxonomies_to_clone_with);
608
-        // loop through terms and add them to new event.
609
-        foreach ($orig_terms as $term) {
610
-            wp_set_object_terms($new_event->ID(), $term->term_id, $term->taxonomy, true);
611
-        }
612
-
613
-        // duplicate other core WP_Post items for this event.
614
-        // post thumbnail (feature image).
615
-        $feature_image_id = get_post_thumbnail_id($orig_event->ID());
616
-        if ($feature_image_id) {
617
-            update_post_meta($new_event->ID(), '_thumbnail_id', $feature_image_id);
618
-        }
619
-
620
-        // duplicate page_template setting
621
-        $page_template = get_post_meta($orig_event->ID(), '_wp_page_template', true);
622
-        if ($page_template) {
623
-            update_post_meta($new_event->ID(), '_wp_page_template', $page_template);
624
-        }
625
-
626
-        do_action('AHEE__Extend_Events_Admin_Page___duplicate_event__after', $new_event, $orig_event);
627
-        // now let's redirect to the edit page for this duplicated event if we have a new event id.
628
-        if ($new_event->ID()) {
629
-            $redirect_args = [
630
-                'post'   => $new_event->ID(),
631
-                'action' => 'edit',
632
-            ];
633
-            EE_Error::add_success(
634
-                esc_html__(
635
-                    'Event successfully duplicated.  Please review the details below and make any necessary edits',
636
-                    'event_espresso'
637
-                )
638
-            );
639
-        } else {
640
-            $redirect_args = [
641
-                'action' => 'default',
642
-            ];
643
-            EE_Error::add_error(
644
-                esc_html__('Not able to duplicate event.  Something went wrong.', 'event_espresso'),
645
-                __FILE__,
646
-                __FUNCTION__,
647
-                __LINE__
648
-            );
649
-        }
650
-        $this->_redirect_after_action(false, '', '', $redirect_args, true);
651
-    }
652
-
653
-
654
-    /**
655
-     * Generates output for the import page.
656
-     *
657
-     * @throws EE_Error
658
-     */
659
-    protected function _import_page()
660
-    {
661
-        $title = esc_html__('Import', 'event_espresso');
662
-        $intro = esc_html__(
663
-            'If you have a previously exported Event Espresso 4 information in a Comma Separated Value (CSV) file format, you can upload the file here: ',
664
-            'event_espresso'
665
-        );
666
-
667
-        $form_url = EVENTS_ADMIN_URL;
668
-        $action   = 'import_events';
669
-        $type     = 'csv';
670
-
671
-        $this->_template_args['form'] = EE_Import::instance()->upload_form(
672
-            $title,
673
-            $intro,
674
-            $form_url,
675
-            $action,
676
-            $type
677
-        );
678
-
679
-        $this->_template_args['sample_file_link']   = EE_Admin_Page::add_query_args_and_nonce(
680
-            ['action' => 'sample_export_file'],
681
-            $this->_admin_base_url
682
-        );
683
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
684
-            EVENTS_CAF_TEMPLATE_PATH . 'import_page.template.php',
685
-            $this->_template_args,
686
-            true
687
-        );
688
-        $this->display_admin_page_with_sidebar();
689
-    }
690
-
691
-
692
-    /**
693
-     * _import_events
694
-     * This handles displaying the screen and running imports for importing events.
695
-     *
696
-     * @return void
697
-     * @throws EE_Error
698
-     */
699
-    protected function _import_events()
700
-    {
701
-        require_once(EE_CLASSES . 'EE_Import.class.php');
702
-        $success = EE_Import::instance()->import();
703
-        $this->_redirect_after_action(
704
-            $success,
705
-            esc_html__('Import File', 'event_espresso'),
706
-            'ran',
707
-            ['action' => 'import_page'],
708
-            true
709
-        );
710
-    }
711
-
712
-
713
-    /**
714
-     * _events_export
715
-     * Will export all (or just the given event) to a Excel compatible file.
716
-     *
717
-     * @access protected
718
-     * @return void
719
-     */
720
-    protected function _events_export()
721
-    {
722
-        $EVT_ID = $this->request->getRequestParam('EVT_ID', 0, 'int');
723
-        $EVT_ID = $this->request->getRequestParam('EVT_IDs', $EVT_ID, 'int');
724
-        $this->request->mergeRequestParams(
725
-            [
726
-                'export' => 'report',
727
-                'action' => 'all_event_data',
728
-                'EVT_ID' => $EVT_ID,
729
-            ]
730
-        );
731
-        if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
732
-            require_once(EE_CLASSES . 'EE_Export.class.php');
733
-            $EE_Export = EE_Export::instance($this->request->requestParams());
734
-            $EE_Export->export();
735
-        }
736
-    }
737
-
738
-
739
-    /**
740
-     * handle category exports()
741
-     *
742
-     * @return void
743
-     */
744
-    protected function _categories_export()
745
-    {
746
-        $EVT_ID = $this->request->getRequestParam('EVT_CAT_ID', 0, 'int');
747
-        $this->request->mergeRequestParams(
748
-            [
749
-                'export' => 'report',
750
-                'action' => 'categories',
751
-                'EVT_ID' => $EVT_ID,
752
-            ]
753
-        );
754
-        if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
755
-            require_once(EE_CLASSES . 'EE_Export.class.php');
756
-            $EE_Export = EE_Export::instance($this->request->requestParams());
757
-            $EE_Export->export();
758
-        }
759
-    }
760
-
761
-
762
-    /**
763
-     * Creates a sample CSV file for importing
764
-     */
765
-    protected function _sample_export_file()
766
-    {
767
-        $EE_Export = EE_Export::instance();
768
-        if ($EE_Export instanceof EE_Export) {
769
-            $EE_Export->export();
770
-        }
771
-    }
772
-
773
-
774
-    /*************        Template Settings        *************/
775
-    /**
776
-     * Generates template settings page output
777
-     *
778
-     * @throws DomainException
779
-     * @throws EE_Error
780
-     * @throws InvalidArgumentException
781
-     * @throws InvalidDataTypeException
782
-     * @throws InvalidInterfaceException
783
-     */
784
-    protected function _template_settings()
785
-    {
786
-        $this->_template_args['values'] = $this->_yes_no_values;
787
-        /**
788
-         * Note leaving this filter in for backward compatibility this was moved in 4.6.x
789
-         * from General_Settings_Admin_Page to here.
790
-         */
791
-        $this->_template_args = apply_filters(
792
-            'FHEE__General_Settings_Admin_Page__template_settings__template_args',
793
-            $this->_template_args
794
-        );
795
-        $this->_set_add_edit_form_tags('update_template_settings');
796
-        $this->_set_publish_post_box_vars();
797
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
798
-            EVENTS_CAF_TEMPLATE_PATH . 'template_settings.template.php',
799
-            $this->_template_args,
800
-            true
801
-        );
802
-        $this->display_admin_page_with_sidebar();
803
-    }
804
-
805
-
806
-    /**
807
-     * Handler for updating template settings.
808
-     *
809
-     * @throws EE_Error
810
-     */
811
-    protected function _update_template_settings()
812
-    {
813
-        /**
814
-         * Note leaving this filter in for backward compatibility this was moved in 4.6.x
815
-         * from General_Settings_Admin_Page to here.
816
-         */
817
-        EE_Registry::instance()->CFG->template_settings = apply_filters(
818
-            'FHEE__General_Settings_Admin_Page__update_template_settings__data',
819
-            EE_Registry::instance()->CFG->template_settings,
820
-            $this->request->requestParams()
821
-        );
822
-        // update custom post type slugs and detect if we need to flush rewrite rules
823
-        $old_slug = EE_Registry::instance()->CFG->core->event_cpt_slug;
824
-
825
-        $event_cpt_slug = $this->request->getRequestParam('event_cpt_slug');
826
-
827
-        EE_Registry::instance()->CFG->core->event_cpt_slug = $event_cpt_slug
828
-            ? EEH_URL::slugify($event_cpt_slug, 'events')
829
-            : EE_Registry::instance()->CFG->core->event_cpt_slug;
830
-
831
-        $what    = esc_html__('Template Settings', 'event_espresso');
832
-        $success = $this->_update_espresso_configuration(
833
-            $what,
834
-            EE_Registry::instance()->CFG->template_settings,
835
-            __FILE__,
836
-            __FUNCTION__,
837
-            __LINE__
838
-        );
839
-        if (EE_Registry::instance()->CFG->core->event_cpt_slug !== $old_slug) {
840
-            /** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
841
-            $rewrite_rules = LoaderFactory::getLoader()->getShared(
842
-                'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
843
-            );
844
-            $rewrite_rules->flush();
845
-        }
846
-        $this->_redirect_after_action($success, $what, 'updated', ['action' => 'template_settings']);
847
-    }
848
-
849
-
850
-    /**
851
-     * _premium_event_editor_meta_boxes
852
-     * add all metaboxes related to the event_editor
853
-     *
854
-     * @access protected
855
-     * @return void
856
-     * @throws EE_Error
857
-     * @throws ReflectionException
858
-     */
859
-    protected function _premium_event_editor_meta_boxes()
860
-    {
861
-        $this->verify_cpt_object();
862
-        // check if the new EDTR reg options meta box is being used, and if so, don't load the legacy version
863
-        if (
864
-            ! $this->admin_config->useAdvancedEditor()
865
-            || ! $this->feature->allowed('use_reg_options_meta_box')
866
-        ) {
867
-            $this->addMetaBox(
868
-                'espresso_event_editor_event_options',
869
-                esc_html__('Event Registration Options', 'event_espresso'),
870
-                [$this, 'registration_options_meta_box'],
871
-                $this->page_slug,
872
-                'side',
873
-                'core'
874
-            );
875
-        }
876
-    }
877
-
878
-
879
-    /**
880
-     * override caf metabox
881
-     *
882
-     * @return void
883
-     * @throws EE_Error
884
-     * @throws ReflectionException
885
-     */
886
-    public function registration_options_meta_box()
887
-    {
888
-        $yes_no_values = [
889
-            ['id' => true, 'text' => esc_html__('Yes', 'event_espresso')],
890
-            ['id' => false, 'text' => esc_html__('No', 'event_espresso')],
891
-        ];
892
-
893
-        $default_reg_status_values = EEM_Registration::reg_status_array(
894
-            [
895
-                EEM_Registration::status_id_cancelled,
896
-                EEM_Registration::status_id_declined,
897
-                EEM_Registration::status_id_incomplete,
898
-                EEM_Registration::status_id_wait_list,
899
-            ],
900
-            true
901
-        );
902
-
903
-        $template_args['active_status']    = $this->_cpt_model_obj->pretty_active_status(false);
904
-        $template_args['_event']           = $this->_cpt_model_obj;
905
-        $template_args['additional_limit'] = $this->_cpt_model_obj->additional_limit();
906
-
907
-        $template_args['default_registration_status']     = EEH_Form_Fields::select_input(
908
-            'default_reg_status',
909
-            $default_reg_status_values,
910
-            $this->_cpt_model_obj->default_registration_status()
911
-        );
912
-        $template_args['display_description']             = EEH_Form_Fields::select_input(
913
-            'display_desc',
914
-            $yes_no_values,
915
-            $this->_cpt_model_obj->display_description()
916
-        );
917
-        $template_args['display_ticket_selector']         = EEH_Form_Fields::select_input(
918
-            'display_ticket_selector',
919
-            $yes_no_values,
920
-            $this->_cpt_model_obj->display_ticket_selector(),
921
-            '',
922
-            '',
923
-            false
924
-        );
925
-        $template_args['EVT_default_registration_status'] = EEH_Form_Fields::select_input(
926
-            'EVT_default_registration_status',
927
-            $default_reg_status_values,
928
-            $this->_cpt_model_obj->default_registration_status()
929
-        );
930
-        $template_args['additional_registration_options'] = apply_filters(
931
-            'FHEE__Events_Admin_Page__registration_options_meta_box__additional_registration_options',
932
-            '',
933
-            $template_args,
934
-            $yes_no_values,
935
-            $default_reg_status_values
936
-        );
937
-        EEH_Template::display_template(
938
-            EVENTS_CAF_TEMPLATE_PATH . 'event_registration_options.template.php',
939
-            $template_args
940
-        );
941
-    }
942
-
943
-
944
-
945
-    /**
946
-     * wp_list_table_mods for caf
947
-     * ============================
948
-     */
949
-
950
-
951
-    /**
952
-     * espresso_event_months_dropdown
953
-     *
954
-     * @deprecatd 5.0.0.p
955
-     * @access public
956
-     * @return string                dropdown listing month/year selections for events.
957
-     * @throws EE_Error
958
-     */
959
-    public function espresso_event_months_dropdown(): string
960
-    {
961
-        // what we need to do is get all PRIMARY datetimes for all events to filter on.
962
-        // Note we need to include any other filters that are set!
963
-        return EEH_Form_Fields::generate_event_months_dropdown(
964
-            $this->request->getRequestParam('month_range'),
965
-            $this->request->getRequestParam('status'),
966
-            $this->request->getRequestParam('EVT_CAT', 0, 'int'),
967
-            $this->request->getRequestParam('active_status')
968
-        );
969
-    }
970
-
971
-
972
-    /**
973
-     * returns a list of "active" statuses on the event
974
-     *
975
-     * @deprecatd 5.0.0.p
976
-     * @param string $current_value whatever the current active status is
977
-     * @return string
978
-     */
979
-    public function active_status_dropdown(string $current_value = ''): string
980
-    {
981
-        $select_name = 'active_status';
982
-        $values      = [
983
-            'none'     => esc_html__('Show Active/Inactive', 'event_espresso'),
984
-            'active'   => esc_html__('Active', 'event_espresso'),
985
-            'upcoming' => esc_html__('Upcoming', 'event_espresso'),
986
-            'expired'  => esc_html__('Expired', 'event_espresso'),
987
-            'inactive' => esc_html__('Inactive', 'event_espresso'),
988
-        ];
989
-
990
-        return EEH_Form_Fields::select_input($select_name, $values, $current_value);
991
-    }
992
-
993
-
994
-    /**
995
-     * returns a list of "venues"
996
-     *
997
-     * @deprecatd 5.0.0.p
998
-     * @param string $current_value whatever the current active status is
999
-     * @return string
1000
-     * @throws EE_Error
1001
-     * @throws ReflectionException
1002
-     */
1003
-    protected function venuesDropdown(string $current_value = ''): string
1004
-    {
1005
-        $values = ['' => esc_html__('All Venues', 'event_espresso')];
1006
-        // populate the list of venues.
1007
-        $venues = EEM_Venue::instance()->get_all(['order_by' => ['VNU_name' => 'ASC']]);
1008
-
1009
-        foreach ($venues as $venue) {
1010
-            $values[ $venue->ID() ] = $venue->name();
1011
-        }
1012
-
1013
-        return EEH_Form_Fields::select_input('venue', $values, $current_value);
1014
-    }
1015
-
1016
-
1017
-    /**
1018
-     * output a dropdown of the categories for the category filter on the event admin list table
1019
-     *
1020
-     * @deprecatd 5.0.0.p
1021
-     * @access  public
1022
-     * @return string html
1023
-     * @throws EE_Error
1024
-     * @throws ReflectionException
1025
-     */
1026
-    public function category_dropdown(): string
1027
-    {
1028
-        return EEH_Form_Fields::generate_event_category_dropdown(
1029
-            $this->request->getRequestParam('EVT_CAT', -1, 'int')
1030
-        );
1031
-    }
1032
-
1033
-
1034
-    /**
1035
-     * get total number of events today
1036
-     *
1037
-     * @access public
1038
-     * @return int
1039
-     * @throws EE_Error
1040
-     * @throws InvalidArgumentException
1041
-     * @throws InvalidDataTypeException
1042
-     * @throws InvalidInterfaceException
1043
-     * @throws ReflectionException
1044
-     */
1045
-    public function total_events_today(): int
1046
-    {
1047
-        $start = EEM_Datetime::instance()->convert_datetime_for_query(
1048
-            'DTT_EVT_start',
1049
-            date('Y-m-d') . ' 00:00:00',
1050
-            'Y-m-d H:i:s',
1051
-            'UTC'
1052
-        );
1053
-        $end   = EEM_Datetime::instance()->convert_datetime_for_query(
1054
-            'DTT_EVT_start',
1055
-            date('Y-m-d') . ' 23:59:59',
1056
-            'Y-m-d H:i:s',
1057
-            'UTC'
1058
-        );
1059
-        $where = [
1060
-            'Datetime.DTT_EVT_start' => ['BETWEEN', [$start, $end]],
1061
-        ];
1062
-        return EEM_Event::instance()->count([$where, 'caps' => 'read_admin'], 'EVT_ID', true);
1063
-    }
1064
-
1065
-
1066
-    /**
1067
-     * get total number of events this month
1068
-     *
1069
-     * @access public
1070
-     * @return int
1071
-     * @throws EE_Error
1072
-     * @throws InvalidArgumentException
1073
-     * @throws InvalidDataTypeException
1074
-     * @throws InvalidInterfaceException
1075
-     * @throws ReflectionException
1076
-     */
1077
-    public function total_events_this_month(): int
1078
-    {
1079
-        // Dates
1080
-        $this_year_r     = date('Y');
1081
-        $this_month_r    = date('m');
1082
-        $days_this_month = date('t');
1083
-        $start           = EEM_Datetime::instance()->convert_datetime_for_query(
1084
-            'DTT_EVT_start',
1085
-            $this_year_r . '-' . $this_month_r . '-01 00:00:00',
1086
-            'Y-m-d H:i:s',
1087
-            'UTC'
1088
-        );
1089
-        $end             = EEM_Datetime::instance()->convert_datetime_for_query(
1090
-            'DTT_EVT_start',
1091
-            $this_year_r . '-' . $this_month_r . '-' . $days_this_month . ' 23:59:59',
1092
-            'Y-m-d H:i:s',
1093
-            'UTC'
1094
-        );
1095
-        $where           = [
1096
-            'Datetime.DTT_EVT_start' => ['BETWEEN', [$start, $end]],
1097
-        ];
1098
-        return EEM_Event::instance()->count([$where, 'caps' => 'read_admin'], 'EVT_ID', true);
1099
-    }
1100
-
1101
-
1102
-    /** DEFAULT TICKETS STUFF **/
1103
-
1104
-    /**
1105
-     * Output default tickets list table view.
1106
-     *
1107
-     * @throws EE_Error
1108
-     */
1109
-    public function _tickets_overview_list_table()
1110
-    {
1111
-        if (
1112
-            $this->admin_config->useAdvancedEditor()
1113
-            && $this->feature->allowed('use_default_ticket_manager')
1114
-        ) {
1115
-            // check if the new EDTR reg options meta box is being used, and if so, don't load the legacy version
1116
-            $this->_template_args['admin_page_content'] = EEH_Template::display_template(
1117
-                EVENTS_CAF_TEMPLATE_PATH . 'default_tickets_moved_notice.template.php',
1118
-                [],
1119
-                true
1120
-            );
1121
-            $this->display_admin_page_with_no_sidebar();
1122
-        } else {
1123
-            $this->_search_btn_label = esc_html__('Tickets', 'event_espresso');
1124
-            $this->display_admin_list_table_page_with_no_sidebar();
1125
-        }
1126
-    }
1127
-
1128
-
1129
-    /**
1130
-     * @param int  $per_page
1131
-     * @param bool $count
1132
-     * @param bool $trashed
1133
-     * @return EE_Soft_Delete_Base_Class[]|int
1134
-     * @throws EE_Error
1135
-     * @throws ReflectionException
1136
-     */
1137
-    public function get_default_tickets(int $per_page = 10, bool $count = false, bool $trashed = false)
1138
-    {
1139
-        $orderby = $this->request->getRequestParam('orderby', 'TKT_name');
1140
-        $order   = $this->request->getRequestParam('order', 'ASC');
1141
-        switch ($orderby) {
1142
-            case 'TKT_name':
1143
-                $orderby = ['TKT_name' => $order];
1144
-                break;
1145
-            case 'TKT_price':
1146
-                $orderby = ['TKT_price' => $order];
1147
-                break;
1148
-            case 'TKT_uses':
1149
-                $orderby = ['TKT_uses' => $order];
1150
-                break;
1151
-            case 'TKT_min':
1152
-                $orderby = ['TKT_min' => $order];
1153
-                break;
1154
-            case 'TKT_max':
1155
-                $orderby = ['TKT_max' => $order];
1156
-                break;
1157
-            case 'TKT_qty':
1158
-                $orderby = ['TKT_qty' => $order];
1159
-                break;
1160
-        }
1161
-
1162
-        $current_page = $this->request->getRequestParam('paged', 1, 'int');
1163
-        $per_page     = $this->request->getRequestParam('perpage', $per_page, 'int');
1164
-        $offset       = ($current_page - 1) * $per_page;
1165
-
1166
-        $where = [
1167
-            'TKT_is_default' => 1,
1168
-            'TKT_deleted'    => $trashed,
1169
-        ];
1170
-
1171
-        $search_term = $this->request->getRequestParam('s');
1172
-        if ($search_term) {
1173
-            $search_term = '%' . $search_term . '%';
1174
-            $where['OR'] = [
1175
-                'TKT_name'        => ['LIKE', $search_term],
1176
-                'TKT_description' => ['LIKE', $search_term],
1177
-            ];
1178
-        }
1179
-
1180
-        return $count
1181
-            ? EEM_Ticket::instance()->count_deleted_and_undeleted([$where])
1182
-            : EEM_Ticket::instance()->get_all_deleted_and_undeleted(
1183
-                [
1184
-                    $where,
1185
-                    'order_by' => $orderby,
1186
-                    'limit'    => [$offset, $per_page],
1187
-                    'group_by' => 'TKT_ID',
1188
-                ]
1189
-            );
1190
-    }
1191
-
1192
-
1193
-    /**
1194
-     * @param bool $trash
1195
-     * @throws EE_Error
1196
-     * @throws InvalidArgumentException
1197
-     * @throws InvalidDataTypeException
1198
-     * @throws InvalidInterfaceException
1199
-     * @throws ReflectionException
1200
-     */
1201
-    protected function _trash_or_restore_ticket(bool $trash = false)
1202
-    {
1203
-        $success = 1;
1204
-        $TKT     = EEM_Ticket::instance();
1205
-        // checkboxes?
1206
-        $checkboxes = $this->request->getRequestParam('checkbox', [], 'int', true);
1207
-        if (! empty($checkboxes)) {
1208
-            // if array has more than one element then success message should be plural
1209
-            $success = count($checkboxes) > 1 ? 2 : 1;
1210
-            // cycle thru the boxes
1211
-            foreach ($checkboxes as $TKT_ID => $value) {
1212
-                if ($trash) {
1213
-                    if (! $TKT->delete_by_ID($TKT_ID)) {
1214
-                        $success = 0;
1215
-                    }
1216
-                } elseif (! $TKT->restore_by_ID($TKT_ID)) {
1217
-                    $success = 0;
1218
-                }
1219
-            }
1220
-        } else {
1221
-            // grab single id and trash
1222
-            $TKT_ID = $this->request->getRequestParam('TKT_ID', 0, 'int');
1223
-            if ($trash) {
1224
-                if (! $TKT->delete_by_ID($TKT_ID)) {
1225
-                    $success = 0;
1226
-                }
1227
-            } elseif (! $TKT->restore_by_ID($TKT_ID)) {
1228
-                $success = 0;
1229
-            }
1230
-        }
1231
-        $action_desc = $trash ? 'moved to the trash' : 'restored';
1232
-        $query_args  = [
1233
-            'action' => 'ticket_list_table',
1234
-            'status' => $trash ? '' : 'trashed',
1235
-        ];
1236
-        $this->_redirect_after_action($success, esc_html__('Tickets', 'event_espresso'), $action_desc, $query_args);
1237
-    }
1238
-
1239
-
1240
-    /**
1241
-     * Handles trashing default ticket.
1242
-     *
1243
-     * @throws EE_Error
1244
-     * @throws ReflectionException
1245
-     */
1246
-    protected function _delete_ticket()
1247
-    {
1248
-        $success = 1;
1249
-        // checkboxes?
1250
-        $checkboxes = $this->request->getRequestParam('checkbox', [], 'int', true);
1251
-        if (! empty($checkboxes)) {
1252
-            // if array has more than one element then success message should be plural
1253
-            $success = count($checkboxes) > 1 ? 2 : 1;
1254
-            // cycle thru the boxes
1255
-            foreach ($checkboxes as $TKT_ID => $value) {
1256
-                // delete
1257
-                if (! $this->_delete_the_ticket($TKT_ID)) {
1258
-                    $success = 0;
1259
-                }
1260
-            }
1261
-        } else {
1262
-            // grab single id and trash
1263
-            $TKT_ID = $this->request->getRequestParam('TKT_ID', 0, 'int');
1264
-            if (! $this->_delete_the_ticket($TKT_ID)) {
1265
-                $success = 0;
1266
-            }
1267
-        }
1268
-        $action_desc = 'deleted';
1269
-        $query_args  = [
1270
-            'action' => 'ticket_list_table',
1271
-            'status' => 'trashed',
1272
-        ];
1273
-        // fail safe.  If the default ticket count === 1 then we need to redirect to event overview.
1274
-        if (
1275
-        EEM_Ticket::instance()->count_deleted_and_undeleted(
1276
-            [['TKT_is_default' => 1]],
1277
-            'TKT_ID',
1278
-            true
1279
-        )
1280
-        ) {
1281
-            $query_args = [];
1282
-        }
1283
-        $this->_redirect_after_action($success, esc_html__('Tickets', 'event_espresso'), $action_desc, $query_args);
1284
-    }
1285
-
1286
-
1287
-    /**
1288
-     * @param int $TKT_ID
1289
-     * @return bool|int
1290
-     * @throws EE_Error
1291
-     * @throws ReflectionException
1292
-     */
1293
-    protected function _delete_the_ticket(int $TKT_ID)
1294
-    {
1295
-        $ticket = EEM_Ticket::instance()->get_one_by_ID($TKT_ID);
1296
-        if (! $ticket instanceof EE_Ticket) {
1297
-            return false;
1298
-        }
1299
-        $ticket->_remove_relations('Datetime');
1300
-        // delete all related prices first
1301
-        $ticket->delete_related_permanently('Price');
1302
-        return $ticket->delete_permanently();
1303
-    }
393
+		}
394
+		if (EE_Registry::instance()->CAP->current_user_can('ee_read_global_messages', 'view_filtered_messages')) {
395
+			EE_Registry::instance()->load_helper('MSG_Template');
396
+			$action_links[] = EEH_MSG_Template::get_message_action_link(
397
+				'see_notifications_for',
398
+				null,
399
+				['EVT_ID' => $event->ID()]
400
+			);
401
+		}
402
+		return $action_links;
403
+	}
404
+
405
+
406
+	/**
407
+	 * @param $items
408
+	 * @return mixed
409
+	 */
410
+	public function additional_legend_items($items)
411
+	{
412
+		if (
413
+		EE_Registry::instance()->CAP->current_user_can(
414
+			'ee_read_registrations',
415
+			'espresso_registrations_reports'
416
+		)
417
+		) {
418
+			$items['reports'] = [
419
+				'class' => 'dashicons dashicons-chart-bar',
420
+				'desc'  => esc_html__('Event Reports', 'event_espresso'),
421
+			];
422
+		}
423
+		if (EE_Registry::instance()->CAP->current_user_can('ee_read_global_messages', 'view_filtered_messages')) {
424
+			$related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
425
+			// $related_for_icon can sometimes be a string so 'css_class' would be an illegal offset
426
+			// (can only use numeric offsets when treating strings as arrays)
427
+			if (is_array($related_for_icon) && isset($related_for_icon['css_class'], $related_for_icon['label'])) {
428
+				$items['view_related_messages'] = [
429
+					'class' => $related_for_icon['css_class'],
430
+					'desc'  => $related_for_icon['label'],
431
+				];
432
+			}
433
+		}
434
+		return $items;
435
+	}
436
+
437
+
438
+	/**
439
+	 * This is the callback method for the duplicate event route
440
+	 * Method looks for 'EVT_ID' in the request and retrieves that event and its details and duplicates them
441
+	 * into a new event.  We add a hook so that any plugins that add extra event details can hook into this
442
+	 * action.  Note that the dupe will have **DUPLICATE** as its title and slug.
443
+	 * After duplication the redirect is to the new event edit page.
444
+	 *
445
+	 * @return void
446
+	 * @throws EE_Error If EE_Event is not available with given ID
447
+	 * @throws ReflectionException
448
+	 * @access protected
449
+	 */
450
+	protected function _duplicate_event()
451
+	{
452
+		// first make sure the ID for the event is in the request.
453
+		//  If it isn't then we need to bail and redirect back to overview list table (cause how did we get here?)
454
+		$EVT_ID = $this->request->getRequestParam('EVT_ID', 0, 'int');
455
+		if (! $EVT_ID) {
456
+			EE_Error::add_error(
457
+				esc_html__(
458
+					'In order to duplicate an event an Event ID is required.  None was given.',
459
+					'event_espresso'
460
+				),
461
+				__FILE__,
462
+				__FUNCTION__,
463
+				__LINE__
464
+			);
465
+			$this->_redirect_after_action(false, '', '', [], true);
466
+			return;
467
+		}
468
+		// k we've got EVT_ID so let's use that to get the event we'll duplicate
469
+		$orig_event = EEM_Event::instance()->get_one_by_ID($EVT_ID);
470
+		if (! $orig_event instanceof EE_Event) {
471
+			throw new EE_Error(
472
+				sprintf(
473
+					esc_html__('An EE_Event object could not be retrieved for the given ID (%s)', 'event_espresso'),
474
+					$EVT_ID
475
+				)
476
+			);
477
+		}
478
+		// k now let's clone the $orig_event before getting relations
479
+		$new_event = clone $orig_event;
480
+		// original datetimes
481
+		$orig_datetimes = $orig_event->get_many_related('Datetime');
482
+		// other original relations
483
+		$orig_ven = $orig_event->get_many_related('Venue');
484
+		// reset the ID and modify other details to make it clear this is a dupe
485
+		$new_event->set('EVT_ID', 0);
486
+		$new_name = $new_event->name() . ' ' . esc_html__('**DUPLICATE**', 'event_espresso');
487
+		$new_event->set('EVT_name', $new_name);
488
+		$new_event->set(
489
+			'EVT_slug',
490
+			wp_unique_post_slug(
491
+				sanitize_title($orig_event->name()),
492
+				0,
493
+				'publish',
494
+				'espresso_events',
495
+				0
496
+			)
497
+		);
498
+		$new_event->set('status', 'draft');
499
+		// duplicate discussion settings
500
+		$new_event->set('comment_status', $orig_event->get('comment_status'));
501
+		$new_event->set('ping_status', $orig_event->get('ping_status'));
502
+		// save the new event
503
+		$new_event->save();
504
+		// venues
505
+		foreach ($orig_ven as $ven) {
506
+			$new_event->_add_relation_to($ven, 'Venue');
507
+		}
508
+		$new_event->save();
509
+		// now we need to get the question group relations and handle that
510
+		// first primary question groups
511
+		$orig_primary_qgs = $orig_event->get_many_related(
512
+			'Question_Group',
513
+			[['Event_Question_Group.EQG_primary' => true]]
514
+		);
515
+		if (! empty($orig_primary_qgs)) {
516
+			foreach ($orig_primary_qgs as $obj) {
517
+				if ($obj instanceof EE_Question_Group) {
518
+					$new_event->_add_relation_to($obj, 'Question_Group', ['EQG_primary' => true]);
519
+				}
520
+			}
521
+		}
522
+		// next additional attendee question groups
523
+		$orig_additional_qgs = $orig_event->get_many_related(
524
+			'Question_Group',
525
+			[['Event_Question_Group.EQG_additional' => true]]
526
+		);
527
+		if (! empty($orig_additional_qgs)) {
528
+			foreach ($orig_additional_qgs as $obj) {
529
+				if ($obj instanceof EE_Question_Group) {
530
+					$new_event->_add_relation_to($obj, 'Question_Group', ['EQG_additional' => true]);
531
+				}
532
+			}
533
+		}
534
+
535
+		$new_event->save();
536
+
537
+		// k now that we have the new event saved we can loop through the datetimes and start adding relations.
538
+		$cloned_tickets = [];
539
+		foreach ($orig_datetimes as $orig_dtt) {
540
+			if (! $orig_dtt instanceof EE_Datetime) {
541
+				continue;
542
+			}
543
+			$new_dtt      = clone $orig_dtt;
544
+			$orig_tickets = $orig_dtt->tickets();
545
+			// save new dtt then add to event
546
+			$new_dtt->set('DTT_ID', 0);
547
+			$new_dtt->set('DTT_sold', 0);
548
+			$new_dtt->set_reserved(0);
549
+			$new_dtt->save();
550
+			$new_event->_add_relation_to($new_dtt, 'Datetime');
551
+			$new_event->save();
552
+			// now let's get the ticket relations setup.
553
+			foreach ((array) $orig_tickets as $orig_ticket) {
554
+				// it's possible a datetime will have no tickets so let's verify we HAVE a ticket first.
555
+				if (! $orig_ticket instanceof EE_Ticket) {
556
+					continue;
557
+				}
558
+				// is this ticket archived?  If it is then let's skip
559
+				if ($orig_ticket->get('TKT_deleted')) {
560
+					continue;
561
+				}
562
+				// does this original ticket already exist in the clone_tickets cache?
563
+				//  If so we'll just use the new ticket from it.
564
+				if (isset($cloned_tickets[ $orig_ticket->ID() ])) {
565
+					$new_ticket = $cloned_tickets[ $orig_ticket->ID() ];
566
+				} else {
567
+					$new_ticket = clone $orig_ticket;
568
+					// get relations on the $orig_ticket that we need to setup.
569
+					$orig_prices = $orig_ticket->prices();
570
+					$new_ticket->set('TKT_ID', 0);
571
+					$new_ticket->set('TKT_sold', 0);
572
+					$new_ticket->set('TKT_reserved', 0);
573
+					$new_ticket->save(); // make sure new ticket has ID.
574
+					// price relations on new ticket need to be setup.
575
+					foreach ($orig_prices as $orig_price) {
576
+						$new_price = clone $orig_price;
577
+						$new_price->set('PRC_ID', 0);
578
+						$new_price->save();
579
+						$new_ticket->_add_relation_to($new_price, 'Price');
580
+						$new_ticket->save();
581
+					}
582
+
583
+					do_action(
584
+						'AHEE__Extend_Events_Admin_Page___duplicate_event__duplicate_ticket__after',
585
+						$orig_ticket,
586
+						$new_ticket,
587
+						$orig_prices,
588
+						$orig_event,
589
+						$orig_dtt,
590
+						$new_dtt
591
+					);
592
+				}
593
+				// k now we can add the new ticket as a relation to the new datetime
594
+				// and make sure its added to our cached $cloned_tickets array
595
+				// for use with later datetimes that have the same ticket.
596
+				$new_dtt->_add_relation_to($new_ticket, 'Ticket');
597
+				$new_dtt->save();
598
+				$cloned_tickets[ $orig_ticket->ID() ] = $new_ticket;
599
+			}
600
+		}
601
+		// clone taxonomy information
602
+		$taxonomies_to_clone_with = apply_filters(
603
+			'FHEE__Extend_Events_Admin_Page___duplicate_event__taxonomies_to_clone',
604
+			['espresso_event_categories', 'espresso_event_type', 'post_tag']
605
+		);
606
+		// get terms for original event (notice)
607
+		$orig_terms = wp_get_object_terms($orig_event->ID(), $taxonomies_to_clone_with);
608
+		// loop through terms and add them to new event.
609
+		foreach ($orig_terms as $term) {
610
+			wp_set_object_terms($new_event->ID(), $term->term_id, $term->taxonomy, true);
611
+		}
612
+
613
+		// duplicate other core WP_Post items for this event.
614
+		// post thumbnail (feature image).
615
+		$feature_image_id = get_post_thumbnail_id($orig_event->ID());
616
+		if ($feature_image_id) {
617
+			update_post_meta($new_event->ID(), '_thumbnail_id', $feature_image_id);
618
+		}
619
+
620
+		// duplicate page_template setting
621
+		$page_template = get_post_meta($orig_event->ID(), '_wp_page_template', true);
622
+		if ($page_template) {
623
+			update_post_meta($new_event->ID(), '_wp_page_template', $page_template);
624
+		}
625
+
626
+		do_action('AHEE__Extend_Events_Admin_Page___duplicate_event__after', $new_event, $orig_event);
627
+		// now let's redirect to the edit page for this duplicated event if we have a new event id.
628
+		if ($new_event->ID()) {
629
+			$redirect_args = [
630
+				'post'   => $new_event->ID(),
631
+				'action' => 'edit',
632
+			];
633
+			EE_Error::add_success(
634
+				esc_html__(
635
+					'Event successfully duplicated.  Please review the details below and make any necessary edits',
636
+					'event_espresso'
637
+				)
638
+			);
639
+		} else {
640
+			$redirect_args = [
641
+				'action' => 'default',
642
+			];
643
+			EE_Error::add_error(
644
+				esc_html__('Not able to duplicate event.  Something went wrong.', 'event_espresso'),
645
+				__FILE__,
646
+				__FUNCTION__,
647
+				__LINE__
648
+			);
649
+		}
650
+		$this->_redirect_after_action(false, '', '', $redirect_args, true);
651
+	}
652
+
653
+
654
+	/**
655
+	 * Generates output for the import page.
656
+	 *
657
+	 * @throws EE_Error
658
+	 */
659
+	protected function _import_page()
660
+	{
661
+		$title = esc_html__('Import', 'event_espresso');
662
+		$intro = esc_html__(
663
+			'If you have a previously exported Event Espresso 4 information in a Comma Separated Value (CSV) file format, you can upload the file here: ',
664
+			'event_espresso'
665
+		);
666
+
667
+		$form_url = EVENTS_ADMIN_URL;
668
+		$action   = 'import_events';
669
+		$type     = 'csv';
670
+
671
+		$this->_template_args['form'] = EE_Import::instance()->upload_form(
672
+			$title,
673
+			$intro,
674
+			$form_url,
675
+			$action,
676
+			$type
677
+		);
678
+
679
+		$this->_template_args['sample_file_link']   = EE_Admin_Page::add_query_args_and_nonce(
680
+			['action' => 'sample_export_file'],
681
+			$this->_admin_base_url
682
+		);
683
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
684
+			EVENTS_CAF_TEMPLATE_PATH . 'import_page.template.php',
685
+			$this->_template_args,
686
+			true
687
+		);
688
+		$this->display_admin_page_with_sidebar();
689
+	}
690
+
691
+
692
+	/**
693
+	 * _import_events
694
+	 * This handles displaying the screen and running imports for importing events.
695
+	 *
696
+	 * @return void
697
+	 * @throws EE_Error
698
+	 */
699
+	protected function _import_events()
700
+	{
701
+		require_once(EE_CLASSES . 'EE_Import.class.php');
702
+		$success = EE_Import::instance()->import();
703
+		$this->_redirect_after_action(
704
+			$success,
705
+			esc_html__('Import File', 'event_espresso'),
706
+			'ran',
707
+			['action' => 'import_page'],
708
+			true
709
+		);
710
+	}
711
+
712
+
713
+	/**
714
+	 * _events_export
715
+	 * Will export all (or just the given event) to a Excel compatible file.
716
+	 *
717
+	 * @access protected
718
+	 * @return void
719
+	 */
720
+	protected function _events_export()
721
+	{
722
+		$EVT_ID = $this->request->getRequestParam('EVT_ID', 0, 'int');
723
+		$EVT_ID = $this->request->getRequestParam('EVT_IDs', $EVT_ID, 'int');
724
+		$this->request->mergeRequestParams(
725
+			[
726
+				'export' => 'report',
727
+				'action' => 'all_event_data',
728
+				'EVT_ID' => $EVT_ID,
729
+			]
730
+		);
731
+		if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
732
+			require_once(EE_CLASSES . 'EE_Export.class.php');
733
+			$EE_Export = EE_Export::instance($this->request->requestParams());
734
+			$EE_Export->export();
735
+		}
736
+	}
737
+
738
+
739
+	/**
740
+	 * handle category exports()
741
+	 *
742
+	 * @return void
743
+	 */
744
+	protected function _categories_export()
745
+	{
746
+		$EVT_ID = $this->request->getRequestParam('EVT_CAT_ID', 0, 'int');
747
+		$this->request->mergeRequestParams(
748
+			[
749
+				'export' => 'report',
750
+				'action' => 'categories',
751
+				'EVT_ID' => $EVT_ID,
752
+			]
753
+		);
754
+		if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
755
+			require_once(EE_CLASSES . 'EE_Export.class.php');
756
+			$EE_Export = EE_Export::instance($this->request->requestParams());
757
+			$EE_Export->export();
758
+		}
759
+	}
760
+
761
+
762
+	/**
763
+	 * Creates a sample CSV file for importing
764
+	 */
765
+	protected function _sample_export_file()
766
+	{
767
+		$EE_Export = EE_Export::instance();
768
+		if ($EE_Export instanceof EE_Export) {
769
+			$EE_Export->export();
770
+		}
771
+	}
772
+
773
+
774
+	/*************        Template Settings        *************/
775
+	/**
776
+	 * Generates template settings page output
777
+	 *
778
+	 * @throws DomainException
779
+	 * @throws EE_Error
780
+	 * @throws InvalidArgumentException
781
+	 * @throws InvalidDataTypeException
782
+	 * @throws InvalidInterfaceException
783
+	 */
784
+	protected function _template_settings()
785
+	{
786
+		$this->_template_args['values'] = $this->_yes_no_values;
787
+		/**
788
+		 * Note leaving this filter in for backward compatibility this was moved in 4.6.x
789
+		 * from General_Settings_Admin_Page to here.
790
+		 */
791
+		$this->_template_args = apply_filters(
792
+			'FHEE__General_Settings_Admin_Page__template_settings__template_args',
793
+			$this->_template_args
794
+		);
795
+		$this->_set_add_edit_form_tags('update_template_settings');
796
+		$this->_set_publish_post_box_vars();
797
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
798
+			EVENTS_CAF_TEMPLATE_PATH . 'template_settings.template.php',
799
+			$this->_template_args,
800
+			true
801
+		);
802
+		$this->display_admin_page_with_sidebar();
803
+	}
804
+
805
+
806
+	/**
807
+	 * Handler for updating template settings.
808
+	 *
809
+	 * @throws EE_Error
810
+	 */
811
+	protected function _update_template_settings()
812
+	{
813
+		/**
814
+		 * Note leaving this filter in for backward compatibility this was moved in 4.6.x
815
+		 * from General_Settings_Admin_Page to here.
816
+		 */
817
+		EE_Registry::instance()->CFG->template_settings = apply_filters(
818
+			'FHEE__General_Settings_Admin_Page__update_template_settings__data',
819
+			EE_Registry::instance()->CFG->template_settings,
820
+			$this->request->requestParams()
821
+		);
822
+		// update custom post type slugs and detect if we need to flush rewrite rules
823
+		$old_slug = EE_Registry::instance()->CFG->core->event_cpt_slug;
824
+
825
+		$event_cpt_slug = $this->request->getRequestParam('event_cpt_slug');
826
+
827
+		EE_Registry::instance()->CFG->core->event_cpt_slug = $event_cpt_slug
828
+			? EEH_URL::slugify($event_cpt_slug, 'events')
829
+			: EE_Registry::instance()->CFG->core->event_cpt_slug;
830
+
831
+		$what    = esc_html__('Template Settings', 'event_espresso');
832
+		$success = $this->_update_espresso_configuration(
833
+			$what,
834
+			EE_Registry::instance()->CFG->template_settings,
835
+			__FILE__,
836
+			__FUNCTION__,
837
+			__LINE__
838
+		);
839
+		if (EE_Registry::instance()->CFG->core->event_cpt_slug !== $old_slug) {
840
+			/** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
841
+			$rewrite_rules = LoaderFactory::getLoader()->getShared(
842
+				'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
843
+			);
844
+			$rewrite_rules->flush();
845
+		}
846
+		$this->_redirect_after_action($success, $what, 'updated', ['action' => 'template_settings']);
847
+	}
848
+
849
+
850
+	/**
851
+	 * _premium_event_editor_meta_boxes
852
+	 * add all metaboxes related to the event_editor
853
+	 *
854
+	 * @access protected
855
+	 * @return void
856
+	 * @throws EE_Error
857
+	 * @throws ReflectionException
858
+	 */
859
+	protected function _premium_event_editor_meta_boxes()
860
+	{
861
+		$this->verify_cpt_object();
862
+		// check if the new EDTR reg options meta box is being used, and if so, don't load the legacy version
863
+		if (
864
+			! $this->admin_config->useAdvancedEditor()
865
+			|| ! $this->feature->allowed('use_reg_options_meta_box')
866
+		) {
867
+			$this->addMetaBox(
868
+				'espresso_event_editor_event_options',
869
+				esc_html__('Event Registration Options', 'event_espresso'),
870
+				[$this, 'registration_options_meta_box'],
871
+				$this->page_slug,
872
+				'side',
873
+				'core'
874
+			);
875
+		}
876
+	}
877
+
878
+
879
+	/**
880
+	 * override caf metabox
881
+	 *
882
+	 * @return void
883
+	 * @throws EE_Error
884
+	 * @throws ReflectionException
885
+	 */
886
+	public function registration_options_meta_box()
887
+	{
888
+		$yes_no_values = [
889
+			['id' => true, 'text' => esc_html__('Yes', 'event_espresso')],
890
+			['id' => false, 'text' => esc_html__('No', 'event_espresso')],
891
+		];
892
+
893
+		$default_reg_status_values = EEM_Registration::reg_status_array(
894
+			[
895
+				EEM_Registration::status_id_cancelled,
896
+				EEM_Registration::status_id_declined,
897
+				EEM_Registration::status_id_incomplete,
898
+				EEM_Registration::status_id_wait_list,
899
+			],
900
+			true
901
+		);
902
+
903
+		$template_args['active_status']    = $this->_cpt_model_obj->pretty_active_status(false);
904
+		$template_args['_event']           = $this->_cpt_model_obj;
905
+		$template_args['additional_limit'] = $this->_cpt_model_obj->additional_limit();
906
+
907
+		$template_args['default_registration_status']     = EEH_Form_Fields::select_input(
908
+			'default_reg_status',
909
+			$default_reg_status_values,
910
+			$this->_cpt_model_obj->default_registration_status()
911
+		);
912
+		$template_args['display_description']             = EEH_Form_Fields::select_input(
913
+			'display_desc',
914
+			$yes_no_values,
915
+			$this->_cpt_model_obj->display_description()
916
+		);
917
+		$template_args['display_ticket_selector']         = EEH_Form_Fields::select_input(
918
+			'display_ticket_selector',
919
+			$yes_no_values,
920
+			$this->_cpt_model_obj->display_ticket_selector(),
921
+			'',
922
+			'',
923
+			false
924
+		);
925
+		$template_args['EVT_default_registration_status'] = EEH_Form_Fields::select_input(
926
+			'EVT_default_registration_status',
927
+			$default_reg_status_values,
928
+			$this->_cpt_model_obj->default_registration_status()
929
+		);
930
+		$template_args['additional_registration_options'] = apply_filters(
931
+			'FHEE__Events_Admin_Page__registration_options_meta_box__additional_registration_options',
932
+			'',
933
+			$template_args,
934
+			$yes_no_values,
935
+			$default_reg_status_values
936
+		);
937
+		EEH_Template::display_template(
938
+			EVENTS_CAF_TEMPLATE_PATH . 'event_registration_options.template.php',
939
+			$template_args
940
+		);
941
+	}
942
+
943
+
944
+
945
+	/**
946
+	 * wp_list_table_mods for caf
947
+	 * ============================
948
+	 */
949
+
950
+
951
+	/**
952
+	 * espresso_event_months_dropdown
953
+	 *
954
+	 * @deprecatd 5.0.0.p
955
+	 * @access public
956
+	 * @return string                dropdown listing month/year selections for events.
957
+	 * @throws EE_Error
958
+	 */
959
+	public function espresso_event_months_dropdown(): string
960
+	{
961
+		// what we need to do is get all PRIMARY datetimes for all events to filter on.
962
+		// Note we need to include any other filters that are set!
963
+		return EEH_Form_Fields::generate_event_months_dropdown(
964
+			$this->request->getRequestParam('month_range'),
965
+			$this->request->getRequestParam('status'),
966
+			$this->request->getRequestParam('EVT_CAT', 0, 'int'),
967
+			$this->request->getRequestParam('active_status')
968
+		);
969
+	}
970
+
971
+
972
+	/**
973
+	 * returns a list of "active" statuses on the event
974
+	 *
975
+	 * @deprecatd 5.0.0.p
976
+	 * @param string $current_value whatever the current active status is
977
+	 * @return string
978
+	 */
979
+	public function active_status_dropdown(string $current_value = ''): string
980
+	{
981
+		$select_name = 'active_status';
982
+		$values      = [
983
+			'none'     => esc_html__('Show Active/Inactive', 'event_espresso'),
984
+			'active'   => esc_html__('Active', 'event_espresso'),
985
+			'upcoming' => esc_html__('Upcoming', 'event_espresso'),
986
+			'expired'  => esc_html__('Expired', 'event_espresso'),
987
+			'inactive' => esc_html__('Inactive', 'event_espresso'),
988
+		];
989
+
990
+		return EEH_Form_Fields::select_input($select_name, $values, $current_value);
991
+	}
992
+
993
+
994
+	/**
995
+	 * returns a list of "venues"
996
+	 *
997
+	 * @deprecatd 5.0.0.p
998
+	 * @param string $current_value whatever the current active status is
999
+	 * @return string
1000
+	 * @throws EE_Error
1001
+	 * @throws ReflectionException
1002
+	 */
1003
+	protected function venuesDropdown(string $current_value = ''): string
1004
+	{
1005
+		$values = ['' => esc_html__('All Venues', 'event_espresso')];
1006
+		// populate the list of venues.
1007
+		$venues = EEM_Venue::instance()->get_all(['order_by' => ['VNU_name' => 'ASC']]);
1008
+
1009
+		foreach ($venues as $venue) {
1010
+			$values[ $venue->ID() ] = $venue->name();
1011
+		}
1012
+
1013
+		return EEH_Form_Fields::select_input('venue', $values, $current_value);
1014
+	}
1015
+
1016
+
1017
+	/**
1018
+	 * output a dropdown of the categories for the category filter on the event admin list table
1019
+	 *
1020
+	 * @deprecatd 5.0.0.p
1021
+	 * @access  public
1022
+	 * @return string html
1023
+	 * @throws EE_Error
1024
+	 * @throws ReflectionException
1025
+	 */
1026
+	public function category_dropdown(): string
1027
+	{
1028
+		return EEH_Form_Fields::generate_event_category_dropdown(
1029
+			$this->request->getRequestParam('EVT_CAT', -1, 'int')
1030
+		);
1031
+	}
1032
+
1033
+
1034
+	/**
1035
+	 * get total number of events today
1036
+	 *
1037
+	 * @access public
1038
+	 * @return int
1039
+	 * @throws EE_Error
1040
+	 * @throws InvalidArgumentException
1041
+	 * @throws InvalidDataTypeException
1042
+	 * @throws InvalidInterfaceException
1043
+	 * @throws ReflectionException
1044
+	 */
1045
+	public function total_events_today(): int
1046
+	{
1047
+		$start = EEM_Datetime::instance()->convert_datetime_for_query(
1048
+			'DTT_EVT_start',
1049
+			date('Y-m-d') . ' 00:00:00',
1050
+			'Y-m-d H:i:s',
1051
+			'UTC'
1052
+		);
1053
+		$end   = EEM_Datetime::instance()->convert_datetime_for_query(
1054
+			'DTT_EVT_start',
1055
+			date('Y-m-d') . ' 23:59:59',
1056
+			'Y-m-d H:i:s',
1057
+			'UTC'
1058
+		);
1059
+		$where = [
1060
+			'Datetime.DTT_EVT_start' => ['BETWEEN', [$start, $end]],
1061
+		];
1062
+		return EEM_Event::instance()->count([$where, 'caps' => 'read_admin'], 'EVT_ID', true);
1063
+	}
1064
+
1065
+
1066
+	/**
1067
+	 * get total number of events this month
1068
+	 *
1069
+	 * @access public
1070
+	 * @return int
1071
+	 * @throws EE_Error
1072
+	 * @throws InvalidArgumentException
1073
+	 * @throws InvalidDataTypeException
1074
+	 * @throws InvalidInterfaceException
1075
+	 * @throws ReflectionException
1076
+	 */
1077
+	public function total_events_this_month(): int
1078
+	{
1079
+		// Dates
1080
+		$this_year_r     = date('Y');
1081
+		$this_month_r    = date('m');
1082
+		$days_this_month = date('t');
1083
+		$start           = EEM_Datetime::instance()->convert_datetime_for_query(
1084
+			'DTT_EVT_start',
1085
+			$this_year_r . '-' . $this_month_r . '-01 00:00:00',
1086
+			'Y-m-d H:i:s',
1087
+			'UTC'
1088
+		);
1089
+		$end             = EEM_Datetime::instance()->convert_datetime_for_query(
1090
+			'DTT_EVT_start',
1091
+			$this_year_r . '-' . $this_month_r . '-' . $days_this_month . ' 23:59:59',
1092
+			'Y-m-d H:i:s',
1093
+			'UTC'
1094
+		);
1095
+		$where           = [
1096
+			'Datetime.DTT_EVT_start' => ['BETWEEN', [$start, $end]],
1097
+		];
1098
+		return EEM_Event::instance()->count([$where, 'caps' => 'read_admin'], 'EVT_ID', true);
1099
+	}
1100
+
1101
+
1102
+	/** DEFAULT TICKETS STUFF **/
1103
+
1104
+	/**
1105
+	 * Output default tickets list table view.
1106
+	 *
1107
+	 * @throws EE_Error
1108
+	 */
1109
+	public function _tickets_overview_list_table()
1110
+	{
1111
+		if (
1112
+			$this->admin_config->useAdvancedEditor()
1113
+			&& $this->feature->allowed('use_default_ticket_manager')
1114
+		) {
1115
+			// check if the new EDTR reg options meta box is being used, and if so, don't load the legacy version
1116
+			$this->_template_args['admin_page_content'] = EEH_Template::display_template(
1117
+				EVENTS_CAF_TEMPLATE_PATH . 'default_tickets_moved_notice.template.php',
1118
+				[],
1119
+				true
1120
+			);
1121
+			$this->display_admin_page_with_no_sidebar();
1122
+		} else {
1123
+			$this->_search_btn_label = esc_html__('Tickets', 'event_espresso');
1124
+			$this->display_admin_list_table_page_with_no_sidebar();
1125
+		}
1126
+	}
1127
+
1128
+
1129
+	/**
1130
+	 * @param int  $per_page
1131
+	 * @param bool $count
1132
+	 * @param bool $trashed
1133
+	 * @return EE_Soft_Delete_Base_Class[]|int
1134
+	 * @throws EE_Error
1135
+	 * @throws ReflectionException
1136
+	 */
1137
+	public function get_default_tickets(int $per_page = 10, bool $count = false, bool $trashed = false)
1138
+	{
1139
+		$orderby = $this->request->getRequestParam('orderby', 'TKT_name');
1140
+		$order   = $this->request->getRequestParam('order', 'ASC');
1141
+		switch ($orderby) {
1142
+			case 'TKT_name':
1143
+				$orderby = ['TKT_name' => $order];
1144
+				break;
1145
+			case 'TKT_price':
1146
+				$orderby = ['TKT_price' => $order];
1147
+				break;
1148
+			case 'TKT_uses':
1149
+				$orderby = ['TKT_uses' => $order];
1150
+				break;
1151
+			case 'TKT_min':
1152
+				$orderby = ['TKT_min' => $order];
1153
+				break;
1154
+			case 'TKT_max':
1155
+				$orderby = ['TKT_max' => $order];
1156
+				break;
1157
+			case 'TKT_qty':
1158
+				$orderby = ['TKT_qty' => $order];
1159
+				break;
1160
+		}
1161
+
1162
+		$current_page = $this->request->getRequestParam('paged', 1, 'int');
1163
+		$per_page     = $this->request->getRequestParam('perpage', $per_page, 'int');
1164
+		$offset       = ($current_page - 1) * $per_page;
1165
+
1166
+		$where = [
1167
+			'TKT_is_default' => 1,
1168
+			'TKT_deleted'    => $trashed,
1169
+		];
1170
+
1171
+		$search_term = $this->request->getRequestParam('s');
1172
+		if ($search_term) {
1173
+			$search_term = '%' . $search_term . '%';
1174
+			$where['OR'] = [
1175
+				'TKT_name'        => ['LIKE', $search_term],
1176
+				'TKT_description' => ['LIKE', $search_term],
1177
+			];
1178
+		}
1179
+
1180
+		return $count
1181
+			? EEM_Ticket::instance()->count_deleted_and_undeleted([$where])
1182
+			: EEM_Ticket::instance()->get_all_deleted_and_undeleted(
1183
+				[
1184
+					$where,
1185
+					'order_by' => $orderby,
1186
+					'limit'    => [$offset, $per_page],
1187
+					'group_by' => 'TKT_ID',
1188
+				]
1189
+			);
1190
+	}
1191
+
1192
+
1193
+	/**
1194
+	 * @param bool $trash
1195
+	 * @throws EE_Error
1196
+	 * @throws InvalidArgumentException
1197
+	 * @throws InvalidDataTypeException
1198
+	 * @throws InvalidInterfaceException
1199
+	 * @throws ReflectionException
1200
+	 */
1201
+	protected function _trash_or_restore_ticket(bool $trash = false)
1202
+	{
1203
+		$success = 1;
1204
+		$TKT     = EEM_Ticket::instance();
1205
+		// checkboxes?
1206
+		$checkboxes = $this->request->getRequestParam('checkbox', [], 'int', true);
1207
+		if (! empty($checkboxes)) {
1208
+			// if array has more than one element then success message should be plural
1209
+			$success = count($checkboxes) > 1 ? 2 : 1;
1210
+			// cycle thru the boxes
1211
+			foreach ($checkboxes as $TKT_ID => $value) {
1212
+				if ($trash) {
1213
+					if (! $TKT->delete_by_ID($TKT_ID)) {
1214
+						$success = 0;
1215
+					}
1216
+				} elseif (! $TKT->restore_by_ID($TKT_ID)) {
1217
+					$success = 0;
1218
+				}
1219
+			}
1220
+		} else {
1221
+			// grab single id and trash
1222
+			$TKT_ID = $this->request->getRequestParam('TKT_ID', 0, 'int');
1223
+			if ($trash) {
1224
+				if (! $TKT->delete_by_ID($TKT_ID)) {
1225
+					$success = 0;
1226
+				}
1227
+			} elseif (! $TKT->restore_by_ID($TKT_ID)) {
1228
+				$success = 0;
1229
+			}
1230
+		}
1231
+		$action_desc = $trash ? 'moved to the trash' : 'restored';
1232
+		$query_args  = [
1233
+			'action' => 'ticket_list_table',
1234
+			'status' => $trash ? '' : 'trashed',
1235
+		];
1236
+		$this->_redirect_after_action($success, esc_html__('Tickets', 'event_espresso'), $action_desc, $query_args);
1237
+	}
1238
+
1239
+
1240
+	/**
1241
+	 * Handles trashing default ticket.
1242
+	 *
1243
+	 * @throws EE_Error
1244
+	 * @throws ReflectionException
1245
+	 */
1246
+	protected function _delete_ticket()
1247
+	{
1248
+		$success = 1;
1249
+		// checkboxes?
1250
+		$checkboxes = $this->request->getRequestParam('checkbox', [], 'int', true);
1251
+		if (! empty($checkboxes)) {
1252
+			// if array has more than one element then success message should be plural
1253
+			$success = count($checkboxes) > 1 ? 2 : 1;
1254
+			// cycle thru the boxes
1255
+			foreach ($checkboxes as $TKT_ID => $value) {
1256
+				// delete
1257
+				if (! $this->_delete_the_ticket($TKT_ID)) {
1258
+					$success = 0;
1259
+				}
1260
+			}
1261
+		} else {
1262
+			// grab single id and trash
1263
+			$TKT_ID = $this->request->getRequestParam('TKT_ID', 0, 'int');
1264
+			if (! $this->_delete_the_ticket($TKT_ID)) {
1265
+				$success = 0;
1266
+			}
1267
+		}
1268
+		$action_desc = 'deleted';
1269
+		$query_args  = [
1270
+			'action' => 'ticket_list_table',
1271
+			'status' => 'trashed',
1272
+		];
1273
+		// fail safe.  If the default ticket count === 1 then we need to redirect to event overview.
1274
+		if (
1275
+		EEM_Ticket::instance()->count_deleted_and_undeleted(
1276
+			[['TKT_is_default' => 1]],
1277
+			'TKT_ID',
1278
+			true
1279
+		)
1280
+		) {
1281
+			$query_args = [];
1282
+		}
1283
+		$this->_redirect_after_action($success, esc_html__('Tickets', 'event_espresso'), $action_desc, $query_args);
1284
+	}
1285
+
1286
+
1287
+	/**
1288
+	 * @param int $TKT_ID
1289
+	 * @return bool|int
1290
+	 * @throws EE_Error
1291
+	 * @throws ReflectionException
1292
+	 */
1293
+	protected function _delete_the_ticket(int $TKT_ID)
1294
+	{
1295
+		$ticket = EEM_Ticket::instance()->get_one_by_ID($TKT_ID);
1296
+		if (! $ticket instanceof EE_Ticket) {
1297
+			return false;
1298
+		}
1299
+		$ticket->_remove_relations('Datetime');
1300
+		// delete all related prices first
1301
+		$ticket->delete_related_permanently('Price');
1302
+		return $ticket->delete_permanently();
1303
+	}
1304 1304
 }
Please login to merge, or discard this patch.
admin/extend/registrations/EE_Event_Registrations_List_Table.class.php 1 patch
Indentation   +646 added lines, -646 removed lines patch added patch discarded remove patch
@@ -16,255 +16,255 @@  discard block
 block discarded – undo
16 16
  */
17 17
 class EE_Event_Registrations_List_Table extends EE_Admin_List_Table
18 18
 {
19
-    /**
20
-     * @var RequestInterface
21
-     */
22
-    protected $request;
23
-
24
-    /**
25
-     * @var Extend_Registrations_Admin_Page
26
-     */
27
-    protected $_admin_page;
28
-
29
-    /**
30
-     * This property will hold the related Datetimes on an event IF the event id is included in the request.
31
-     *
32
-     * @var DatetimesForEventCheckIn
33
-     */
34
-    protected $datetimes_for_event;
35
-
36
-    /**
37
-     * The DTT_ID if the current view has a specified datetime.
38
-     *
39
-     * @var int
40
-     */
41
-    protected $datetime_id = 0;
42
-
43
-    /**
44
-     * @var EE_Datetime
45
-     */
46
-    protected $datetime;
47
-
48
-    /**
49
-     * The event ID if one is specified in the request
50
-     *
51
-     * @var int
52
-     */
53
-    protected $event_id = 0;
54
-
55
-    /**
56
-     * @var EE_Event
57
-     */
58
-    protected $event;
59
-
60
-    /**
61
-     * @var DatetimesForEventCheckIn
62
-     */
63
-    protected $datetimes_for_current_row;
64
-
65
-    /**
66
-     * @var bool
67
-     */
68
-    protected $hide_expired;
69
-
70
-    /**
71
-     * @var bool
72
-     */
73
-    protected $hide_upcoming;
74
-
75
-    /**
76
-     * @var   array
77
-     * @since 4.10.31.p
78
-     */
79
-    protected $_status;
80
-
81
-
82
-    /**
83
-     * EE_Event_Registrations_List_Table constructor.
84
-     *
85
-     * @param Registrations_Admin_Page $admin_page
86
-     * @throws EE_Error
87
-     * @throws ReflectionException
88
-     */
89
-    public function __construct($admin_page)
90
-    {
91
-        $this->request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
92
-        $this->resolveRequestVars();
93
-        parent::__construct($admin_page);
94
-    }
95
-
96
-
97
-    /**
98
-     * @throws EE_Error
99
-     * @throws ReflectionException
100
-     * @since 5.0.0.p
101
-     */
102
-    private function resolveRequestVars()
103
-    {
104
-        $this->event_id = $this->request->getRequestParam('event_id', 0, 'int');
105
-        $this->datetimes_for_event = DatetimesForEventCheckIn::fromEventID($this->event_id);
106
-        // if we're filtering for a specific event and it only has one datetime, then grab its ID
107
-        $datetime          = $this->datetimes_for_event->getOneDatetimeForEvent();
108
-        $this->datetime_id = $datetime instanceof EE_Datetime ? $datetime->ID() : 0;
109
-        // else check the request, but use the above as the default (and hope they match if BOTH exist, LOLZ)
110
-        $this->datetime_id = $this->request->getRequestParam(
111
-            'DTT_ID',
112
-            $this->datetime_id,
113
-            'int'
114
-        );
115
-    }
116
-
117
-
118
-    /**
119
-     * @throws EE_Error
120
-     */
121
-    protected function _setup_data()
122
-    {
123
-        $this->_data = $this->_view !== 'trash'
124
-            ? $this->_admin_page->get_event_attendees($this->_per_page)
125
-            : $this->_admin_page->get_event_attendees($this->_per_page, false, true);
126
-
127
-        $this->_all_data_count = $this->_view !== 'trash'
128
-            ? $this->_admin_page->get_event_attendees($this->_per_page, true)
129
-            : $this->_admin_page->get_event_attendees($this->_per_page, true, true);
130
-    }
131
-
132
-
133
-    /**
134
-     * @throws ReflectionException
135
-     * @throws EE_Error
136
-     */
137
-    protected function _set_properties()
138
-    {
139
-        $return_url = $this->getReturnUrl();
140
-
141
-        $this->_wp_list_args = [
142
-            'singular' => esc_html__('registrant', 'event_espresso'),
143
-            'plural'   => esc_html__('registrants', 'event_espresso'),
144
-            'ajax'     => true,
145
-            'screen'   => $this->_admin_page->get_current_screen()->id,
146
-        ];
147
-        $columns             = [];
148
-
149
-        $this->_columns = [
150
-            '_REG_att_checked_in' => '<span class="dashicons dashicons-yes ee-icon-size-18"></span>',
151
-            'ATT_name'            => esc_html__('Registrant', 'event_espresso'),
152
-            'ATT_email'           => esc_html__('Email Address', 'event_espresso'),
153
-            'Event'               => esc_html__('Event', 'event_espresso'),
154
-            'PRC_name'            => esc_html__('TKT Option', 'event_espresso'),
155
-            '_REG_final_price'    => esc_html__('Price', 'event_espresso'),
156
-            'TXN_paid'            => esc_html__('Paid', 'event_espresso'),
157
-            'TXN_total'           => esc_html__('Total', 'event_espresso'),
158
-        ];
159
-        // Add/remove columns when an event has been selected
160
-        if (! empty($this->event_id)) {
161
-            // Render a checkbox column
162
-            $columns['cb']              = '<input type="checkbox" />';
163
-            $this->_has_checkbox_column = true;
164
-            // Remove the 'Event' column
165
-            unset($this->_columns['Event']);
166
-            $this->setBottomButtons();
167
-        }
168
-        $this->_columns        = array_merge($columns, $this->_columns);
169
-        $this->_primary_column = '_REG_att_checked_in';
170
-
171
-        $csv_report = RegistrationsCsvReportParams::getRequestParams(
172
-            $return_url,
173
-            $this->_req_data,
174
-            $this->event_id,
175
-            $this->datetime_id
176
-        );
177
-        if (! empty($csv_report)) {
178
-            $this->_bottom_buttons['csv_reg_report'] = $csv_report;
179
-        }
180
-
181
-        $this->_sortable_columns = [
182
-            /**
183
-             * Allows users to change the default sort if they wish.
184
-             * Returning a falsey on this filter will result in the default sort to be by firstname rather than last name.
185
-             *
186
-             * Note: usual naming conventions for filters aren't followed here so that just one filter can be used to
187
-             * change the sorts on any list table involving registration contacts.  If you want to only change the filter
188
-             * for a specific list table you can use the provided reference to this object instance.
189
-             */
190
-            'ATT_name' => [
191
-                'FHEE__EE_Registrations_List_Table___set_properties__default_sort_by_registration_last_name',
192
-                true,
193
-                $this,
194
-            ]
195
-                ? ['ATT_lname' => true]
196
-                : ['ATT_fname' => true],
197
-            'Event'    => ['Event.EVT_name' => false],
198
-        ];
199
-        $this->_hidden_columns   = [];
200
-        $this->event              = EEM_Event::instance()->get_one_by_ID($this->event_id);
201
-        if ($this->event instanceof EE_Event) {
202
-            $this->datetimes_for_event = DatetimesForEventCheckIn::fromEvent($this->event);
203
-        }
204
-    }
205
-
206
-
207
-    /**
208
-     * @param EE_Registration $item
209
-     * @return string
210
-     */
211
-    protected function _get_row_class($item): string
212
-    {
213
-        $class = parent::_get_row_class($item);
214
-        if ($this->_has_checkbox_column) {
215
-            $class .= ' has-checkbox-column';
216
-        }
217
-        return $class;
218
-    }
219
-
220
-
221
-    /**
222
-     * @return array
223
-     * @throws EE_Error
224
-     * @throws ReflectionException
225
-     */
226
-    protected function _get_table_filters()
227
-    {
228
-        $filters = [];
229
-        $this->hide_expired = $this->request->getRequestParam('hide_expired', false, 'bool');
230
-        $this->hide_upcoming = $this->request->getRequestParam('hide_upcoming', false, 'bool');
231
-        $hide_expired_checked = $this->hide_expired ? 'checked' : '';
232
-        $hide_upcoming_checked = $this->hide_upcoming ? 'checked' : '';
233
-        // get datetimes for ALL active events (note possible capability restrictions)
234
-        $events   = $this->datetimes_for_event->getAllEvents();
235
-        $event_options[] = [
236
-            'id'   => 0,
237
-            'text' => esc_html__(' - select an event - ', 'event_espresso'),
238
-        ];
239
-        foreach ($events as $event) {
240
-            // any registrations for this event?
241
-            if (! $event instanceof EE_Event/* || ! $event->get_count_of_all_registrations()*/) {
242
-                continue;
243
-            }
244
-            $expired_class = $event->is_expired() ? 'ee-expired-event' : '';
245
-            $upcoming_class  = $event->is_upcoming() ? ' ee-upcoming-event' : '';
246
-
247
-            $event_options[] = [
248
-                'id'    => $event->ID(),
249
-                'text'  => apply_filters(
250
-                    'FHEE__EE_Event_Registrations___get_table_filters__event_name',
251
-                    $event->name(),
252
-                    $event
253
-                ),
254
-                'class' => $expired_class . $upcoming_class,
255
-            ];
256
-            if ($event->ID() === $this->event_id) {
257
-                $this->hide_expired = $expired_class === '' ? $this->hide_expired : false;
258
-                $hide_expired_checked  = $expired_class === '' ? $hide_expired_checked : '';
259
-                $this->hide_upcoming = $upcoming_class === '' ? $this->hide_upcoming : false;
260
-                $hide_upcoming_checked = $upcoming_class === '' ? $hide_upcoming_checked : '';
261
-            }
262
-        }
263
-
264
-        $select_class = $this->hide_expired ? 'ee-hide-expired-events' : '';
265
-        $select_class .= $this->hide_upcoming ? ' ee-hide-upcoming-events' : '';
266
-
267
-        $filters[] = '
19
+	/**
20
+	 * @var RequestInterface
21
+	 */
22
+	protected $request;
23
+
24
+	/**
25
+	 * @var Extend_Registrations_Admin_Page
26
+	 */
27
+	protected $_admin_page;
28
+
29
+	/**
30
+	 * This property will hold the related Datetimes on an event IF the event id is included in the request.
31
+	 *
32
+	 * @var DatetimesForEventCheckIn
33
+	 */
34
+	protected $datetimes_for_event;
35
+
36
+	/**
37
+	 * The DTT_ID if the current view has a specified datetime.
38
+	 *
39
+	 * @var int
40
+	 */
41
+	protected $datetime_id = 0;
42
+
43
+	/**
44
+	 * @var EE_Datetime
45
+	 */
46
+	protected $datetime;
47
+
48
+	/**
49
+	 * The event ID if one is specified in the request
50
+	 *
51
+	 * @var int
52
+	 */
53
+	protected $event_id = 0;
54
+
55
+	/**
56
+	 * @var EE_Event
57
+	 */
58
+	protected $event;
59
+
60
+	/**
61
+	 * @var DatetimesForEventCheckIn
62
+	 */
63
+	protected $datetimes_for_current_row;
64
+
65
+	/**
66
+	 * @var bool
67
+	 */
68
+	protected $hide_expired;
69
+
70
+	/**
71
+	 * @var bool
72
+	 */
73
+	protected $hide_upcoming;
74
+
75
+	/**
76
+	 * @var   array
77
+	 * @since 4.10.31.p
78
+	 */
79
+	protected $_status;
80
+
81
+
82
+	/**
83
+	 * EE_Event_Registrations_List_Table constructor.
84
+	 *
85
+	 * @param Registrations_Admin_Page $admin_page
86
+	 * @throws EE_Error
87
+	 * @throws ReflectionException
88
+	 */
89
+	public function __construct($admin_page)
90
+	{
91
+		$this->request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
92
+		$this->resolveRequestVars();
93
+		parent::__construct($admin_page);
94
+	}
95
+
96
+
97
+	/**
98
+	 * @throws EE_Error
99
+	 * @throws ReflectionException
100
+	 * @since 5.0.0.p
101
+	 */
102
+	private function resolveRequestVars()
103
+	{
104
+		$this->event_id = $this->request->getRequestParam('event_id', 0, 'int');
105
+		$this->datetimes_for_event = DatetimesForEventCheckIn::fromEventID($this->event_id);
106
+		// if we're filtering for a specific event and it only has one datetime, then grab its ID
107
+		$datetime          = $this->datetimes_for_event->getOneDatetimeForEvent();
108
+		$this->datetime_id = $datetime instanceof EE_Datetime ? $datetime->ID() : 0;
109
+		// else check the request, but use the above as the default (and hope they match if BOTH exist, LOLZ)
110
+		$this->datetime_id = $this->request->getRequestParam(
111
+			'DTT_ID',
112
+			$this->datetime_id,
113
+			'int'
114
+		);
115
+	}
116
+
117
+
118
+	/**
119
+	 * @throws EE_Error
120
+	 */
121
+	protected function _setup_data()
122
+	{
123
+		$this->_data = $this->_view !== 'trash'
124
+			? $this->_admin_page->get_event_attendees($this->_per_page)
125
+			: $this->_admin_page->get_event_attendees($this->_per_page, false, true);
126
+
127
+		$this->_all_data_count = $this->_view !== 'trash'
128
+			? $this->_admin_page->get_event_attendees($this->_per_page, true)
129
+			: $this->_admin_page->get_event_attendees($this->_per_page, true, true);
130
+	}
131
+
132
+
133
+	/**
134
+	 * @throws ReflectionException
135
+	 * @throws EE_Error
136
+	 */
137
+	protected function _set_properties()
138
+	{
139
+		$return_url = $this->getReturnUrl();
140
+
141
+		$this->_wp_list_args = [
142
+			'singular' => esc_html__('registrant', 'event_espresso'),
143
+			'plural'   => esc_html__('registrants', 'event_espresso'),
144
+			'ajax'     => true,
145
+			'screen'   => $this->_admin_page->get_current_screen()->id,
146
+		];
147
+		$columns             = [];
148
+
149
+		$this->_columns = [
150
+			'_REG_att_checked_in' => '<span class="dashicons dashicons-yes ee-icon-size-18"></span>',
151
+			'ATT_name'            => esc_html__('Registrant', 'event_espresso'),
152
+			'ATT_email'           => esc_html__('Email Address', 'event_espresso'),
153
+			'Event'               => esc_html__('Event', 'event_espresso'),
154
+			'PRC_name'            => esc_html__('TKT Option', 'event_espresso'),
155
+			'_REG_final_price'    => esc_html__('Price', 'event_espresso'),
156
+			'TXN_paid'            => esc_html__('Paid', 'event_espresso'),
157
+			'TXN_total'           => esc_html__('Total', 'event_espresso'),
158
+		];
159
+		// Add/remove columns when an event has been selected
160
+		if (! empty($this->event_id)) {
161
+			// Render a checkbox column
162
+			$columns['cb']              = '<input type="checkbox" />';
163
+			$this->_has_checkbox_column = true;
164
+			// Remove the 'Event' column
165
+			unset($this->_columns['Event']);
166
+			$this->setBottomButtons();
167
+		}
168
+		$this->_columns        = array_merge($columns, $this->_columns);
169
+		$this->_primary_column = '_REG_att_checked_in';
170
+
171
+		$csv_report = RegistrationsCsvReportParams::getRequestParams(
172
+			$return_url,
173
+			$this->_req_data,
174
+			$this->event_id,
175
+			$this->datetime_id
176
+		);
177
+		if (! empty($csv_report)) {
178
+			$this->_bottom_buttons['csv_reg_report'] = $csv_report;
179
+		}
180
+
181
+		$this->_sortable_columns = [
182
+			/**
183
+			 * Allows users to change the default sort if they wish.
184
+			 * Returning a falsey on this filter will result in the default sort to be by firstname rather than last name.
185
+			 *
186
+			 * Note: usual naming conventions for filters aren't followed here so that just one filter can be used to
187
+			 * change the sorts on any list table involving registration contacts.  If you want to only change the filter
188
+			 * for a specific list table you can use the provided reference to this object instance.
189
+			 */
190
+			'ATT_name' => [
191
+				'FHEE__EE_Registrations_List_Table___set_properties__default_sort_by_registration_last_name',
192
+				true,
193
+				$this,
194
+			]
195
+				? ['ATT_lname' => true]
196
+				: ['ATT_fname' => true],
197
+			'Event'    => ['Event.EVT_name' => false],
198
+		];
199
+		$this->_hidden_columns   = [];
200
+		$this->event              = EEM_Event::instance()->get_one_by_ID($this->event_id);
201
+		if ($this->event instanceof EE_Event) {
202
+			$this->datetimes_for_event = DatetimesForEventCheckIn::fromEvent($this->event);
203
+		}
204
+	}
205
+
206
+
207
+	/**
208
+	 * @param EE_Registration $item
209
+	 * @return string
210
+	 */
211
+	protected function _get_row_class($item): string
212
+	{
213
+		$class = parent::_get_row_class($item);
214
+		if ($this->_has_checkbox_column) {
215
+			$class .= ' has-checkbox-column';
216
+		}
217
+		return $class;
218
+	}
219
+
220
+
221
+	/**
222
+	 * @return array
223
+	 * @throws EE_Error
224
+	 * @throws ReflectionException
225
+	 */
226
+	protected function _get_table_filters()
227
+	{
228
+		$filters = [];
229
+		$this->hide_expired = $this->request->getRequestParam('hide_expired', false, 'bool');
230
+		$this->hide_upcoming = $this->request->getRequestParam('hide_upcoming', false, 'bool');
231
+		$hide_expired_checked = $this->hide_expired ? 'checked' : '';
232
+		$hide_upcoming_checked = $this->hide_upcoming ? 'checked' : '';
233
+		// get datetimes for ALL active events (note possible capability restrictions)
234
+		$events   = $this->datetimes_for_event->getAllEvents();
235
+		$event_options[] = [
236
+			'id'   => 0,
237
+			'text' => esc_html__(' - select an event - ', 'event_espresso'),
238
+		];
239
+		foreach ($events as $event) {
240
+			// any registrations for this event?
241
+			if (! $event instanceof EE_Event/* || ! $event->get_count_of_all_registrations()*/) {
242
+				continue;
243
+			}
244
+			$expired_class = $event->is_expired() ? 'ee-expired-event' : '';
245
+			$upcoming_class  = $event->is_upcoming() ? ' ee-upcoming-event' : '';
246
+
247
+			$event_options[] = [
248
+				'id'    => $event->ID(),
249
+				'text'  => apply_filters(
250
+					'FHEE__EE_Event_Registrations___get_table_filters__event_name',
251
+					$event->name(),
252
+					$event
253
+				),
254
+				'class' => $expired_class . $upcoming_class,
255
+			];
256
+			if ($event->ID() === $this->event_id) {
257
+				$this->hide_expired = $expired_class === '' ? $this->hide_expired : false;
258
+				$hide_expired_checked  = $expired_class === '' ? $hide_expired_checked : '';
259
+				$this->hide_upcoming = $upcoming_class === '' ? $this->hide_upcoming : false;
260
+				$hide_upcoming_checked = $upcoming_class === '' ? $hide_upcoming_checked : '';
261
+			}
262
+		}
263
+
264
+		$select_class = $this->hide_expired ? 'ee-hide-expired-events' : '';
265
+		$select_class .= $this->hide_upcoming ? ' ee-hide-upcoming-events' : '';
266
+
267
+		$filters[] = '
268 268
         <div class="ee-event-filter__wrapper">
269 269
             <label class="ee-event-filter-main-label">
270 270
                 ' . esc_html__('Check-in Status for', 'event_espresso') . '
@@ -273,439 +273,439 @@  discard block
 block discarded – undo
273 273
                 <span class="ee-event-selector">
274 274
                     <label for="event_id">' . esc_html__('Event', 'event_espresso') . '</label>
275 275
                     ' . EEH_Form_Fields::select_input(
276
-                        'event_id',
277
-                        $event_options,
278
-                        $this->event_id,
279
-                        '',
280
-                        $select_class
281
-                    ) . '
276
+						'event_id',
277
+						$event_options,
278
+						$this->event_id,
279
+						'',
280
+						$select_class
281
+					) . '
282 282
                 </span>';
283
-        // DTT datetimes filter
284
-        $datetimes_for_event = $this->datetimes_for_event->getAllDatetimesForEvent(
285
-            $hide_upcoming_checked === 'checked'
286
-        );
287
-        if (count($datetimes_for_event) > 1) {
288
-            $datetimes[0] = esc_html__(' - select a datetime - ', 'event_espresso');
289
-            foreach ($datetimes_for_event as $datetime) {
290
-                if ($datetime instanceof EE_Datetime) {
291
-                    $datetime_string = $datetime->name();
292
-                    $datetime_string = ! empty($datetime_string) ? $datetime_string . ': ' : '';
293
-                    $datetime_string .= $datetime->date_and_time_range();
294
-                    $datetime_string .= $datetime->is_active() ? ' ∗' : '';
295
-                    $datetime_string .= $datetime->is_expired() ? ' «' : '';
296
-                    $datetime_string .= $datetime->is_upcoming() ? ' »' : '';
297
-                    // now put it all together
298
-                    $datetimes[ $datetime->ID() ] = $datetime_string;
299
-                }
300
-            }
301
-            $filters[] = '
283
+		// DTT datetimes filter
284
+		$datetimes_for_event = $this->datetimes_for_event->getAllDatetimesForEvent(
285
+			$hide_upcoming_checked === 'checked'
286
+		);
287
+		if (count($datetimes_for_event) > 1) {
288
+			$datetimes[0] = esc_html__(' - select a datetime - ', 'event_espresso');
289
+			foreach ($datetimes_for_event as $datetime) {
290
+				if ($datetime instanceof EE_Datetime) {
291
+					$datetime_string = $datetime->name();
292
+					$datetime_string = ! empty($datetime_string) ? $datetime_string . ': ' : '';
293
+					$datetime_string .= $datetime->date_and_time_range();
294
+					$datetime_string .= $datetime->is_active() ? ' ∗' : '';
295
+					$datetime_string .= $datetime->is_expired() ? ' «' : '';
296
+					$datetime_string .= $datetime->is_upcoming() ? ' »' : '';
297
+					// now put it all together
298
+					$datetimes[ $datetime->ID() ] = $datetime_string;
299
+				}
300
+			}
301
+			$filters[] = '
302 302
                 <span class="ee-datetime-selector">
303 303
                     <label for="DTT_ID">' . esc_html__('Datetime', 'event_espresso') . '</label>
304 304
                     ' . EEH_Form_Fields::select_input(
305
-                        'DTT_ID',
306
-                        $datetimes,
307
-                        $this->datetime_id
308
-                    ) . '
305
+						'DTT_ID',
306
+						$datetimes,
307
+						$this->datetime_id
308
+					) . '
309 309
                 </span>';
310
-        }
311
-        $filters[] = '
310
+		}
311
+		$filters[] = '
312 312
                 <span class="ee-hide-upcoming-check">
313 313
                     <label for="js-ee-hide-upcoming-events">
314 314
                         <input type="checkbox" id="js-ee-hide-upcoming-events" name="hide_upcoming" '
315
-                         . $hide_upcoming_checked
316
-                         . '>
315
+						 . $hide_upcoming_checked
316
+						 . '>
317 317
                         '
318
-                         . esc_html__('Hide Upcoming Events', 'event_espresso')
319
-                         . '
318
+						 . esc_html__('Hide Upcoming Events', 'event_espresso')
319
+						 . '
320 320
                     </label>
321 321
                     <span class="ee-help-btn dashicons dashicons-editor-help ee-aria-tooltip" aria-label="'
322
-                         . esc_html__(
323
-                             'Will not display events with start dates in the future (ie: have not yet begun)',
324
-                             'event_espresso'
325
-                         )
326
-                         . '"></span>
322
+						 . esc_html__(
323
+							 'Will not display events with start dates in the future (ie: have not yet begun)',
324
+							 'event_espresso'
325
+						 )
326
+						 . '"></span>
327 327
                 </span>
328 328
                 <span class="ee-hide-expired-check">
329 329
                     <label for="js-ee-hide-expired-events">
330 330
                         <input type="checkbox" id="js-ee-hide-expired-events" name="hide_expired" '
331
-                         . $hide_expired_checked
332
-                         . '>
331
+						 . $hide_expired_checked
332
+						 . '>
333 333
                         '
334
-                         . esc_html__('Hide Expired Events', 'event_espresso')
335
-                         . '
334
+						 . esc_html__('Hide Expired Events', 'event_espresso')
335
+						 . '
336 336
                     </label>
337 337
                     <span class="ee-help-btn dashicons dashicons-editor-help ee-aria-tooltip" aria-label="'
338
-                         . esc_html__(
339
-                             'Will not display events with end dates in the past (ie: have already finished)',
340
-                             'event_espresso'
341
-                         )
342
-                         . '"></span>
338
+						 . esc_html__(
339
+							 'Will not display events with end dates in the past (ie: have already finished)',
340
+							 'event_espresso'
341
+						 )
342
+						 . '"></span>
343 343
                 </span>
344 344
             </div>
345 345
         </div>';
346
-        return $filters;
347
-    }
348
-
349
-
350
-    /**
351
-     * @throws EE_Error
352
-     * @throws ReflectionException
353
-     */
354
-    protected function _add_view_counts()
355
-    {
356
-        $this->_views['all']['count'] = $this->_get_total_event_attendees();
357
-    }
358
-
359
-
360
-    /**
361
-     * @return int
362
-     * @throws EE_Error
363
-     * @throws ReflectionException
364
-     */
365
-    protected function _get_total_event_attendees(): int
366
-    {
367
-        $query_params      = [];
368
-        if ($this->event_id) {
369
-            $query_params[0]['EVT_ID'] = $this->event_id;
370
-        }
371
-        // if DTT is included we only show for that datetime.  Otherwise we're showing for all datetimes (the event).
372
-        if ($this->datetime_id) {
373
-            $query_params[0]['Ticket.Datetime.DTT_ID'] = $this->datetime_id;
374
-        }
375
-        $status_ids_array          = apply_filters(
376
-            'FHEE__Extend_Registrations_Admin_Page__get_event_attendees__status_ids_array',
377
-            [EEM_Registration::status_id_pending_payment, EEM_Registration::status_id_approved]
378
-        );
379
-        $query_params[0]['STS_ID'] = ['IN', $status_ids_array];
380
-        return EEM_Registration::instance()->count($query_params);
381
-    }
382
-
383
-
384
-    /**
385
-     * @param EE_Registration $item
386
-     * @return string
387
-     * @throws EE_Error
388
-     * @throws ReflectionException
389
-     */
390
-    public function column_cb($item): string
391
-    {
392
-        return sprintf('<input type="checkbox" name="checkbox[%1$s]" value="%1$s" />', $item->ID());
393
-    }
394
-
395
-
396
-    /**
397
-     * column_REG_att_checked_in
398
-     *
399
-     * @param EE_Registration $registration
400
-     * @return string
401
-     * @throws EE_Error
402
-     * @throws InvalidArgumentException
403
-     * @throws InvalidDataTypeException
404
-     * @throws InvalidInterfaceException
405
-     * @throws ReflectionException
406
-     */
407
-    public function column__REG_att_checked_in(EE_Registration $registration): string
408
-    {
409
-        // we need a local variable for the datetime for each row
410
-        // (so that we don't pollute state for the entire table)
411
-        // so let's try to get it from the registration's event
412
-        $DTT_ID = $this->datetime_id;
413
-        if (! $DTT_ID) {
414
-            $reg_ticket_datetimes = $registration->ticket()->datetimes();
415
-            if (count($reg_ticket_datetimes) === 1) {
416
-                $reg_ticket_datetime = reset($reg_ticket_datetimes);
417
-                $DTT_ID = $reg_ticket_datetime instanceof EE_Datetime ? $reg_ticket_datetime->ID() : 0;
418
-            }
419
-        }
420
-
421
-        if (! $DTT_ID) {
422
-            $this->datetimes_for_current_row = DatetimesForEventCheckIn::fromRegistration($registration);
423
-            $datetime = $this->datetimes_for_current_row->getOneDatetimeForEvent($DTT_ID);
424
-            $DTT_ID = $datetime instanceof EE_Datetime ? $datetime->ID() : 0;
425
-        }
426
-
427
-        $checkin_status_dashicon = CheckinStatusDashicon::fromRegistrationAndDatetimeId(
428
-            $registration,
429
-            $DTT_ID
430
-        );
431
-
432
-        $aria_label = $checkin_status_dashicon->ariaLabel();
433
-        $dashicon_class = $checkin_status_dashicon->cssClasses();
434
-        $attributes = ' onClick="return false"';
435
-        $button_class = 'button button--secondary button--icon-only ee-aria-tooltip ee-aria-tooltip--big-box';
436
-
437
-        if (
438
-            $DTT_ID
439
-            && EE_Registry::instance()->CAP->current_user_can(
440
-                'ee_edit_checkin',
441
-                'espresso_registrations_toggle_checkin_status',
442
-                $registration->ID()
443
-            )
444
-        ) {
445
-            // overwrite the disabled attribute with data attributes for performing checkin
446
-            $attributes = 'data-_regid="' . $registration->ID() . '"';
447
-            $attributes .= ' data-dttid="' . $DTT_ID . '"';
448
-            $attributes .= ' data-nonce="' . wp_create_nonce('checkin_nonce') . '"';
449
-            $button_class .= ' clickable trigger-checkin';
450
-        }
451
-
452
-        $content = '
346
+		return $filters;
347
+	}
348
+
349
+
350
+	/**
351
+	 * @throws EE_Error
352
+	 * @throws ReflectionException
353
+	 */
354
+	protected function _add_view_counts()
355
+	{
356
+		$this->_views['all']['count'] = $this->_get_total_event_attendees();
357
+	}
358
+
359
+
360
+	/**
361
+	 * @return int
362
+	 * @throws EE_Error
363
+	 * @throws ReflectionException
364
+	 */
365
+	protected function _get_total_event_attendees(): int
366
+	{
367
+		$query_params      = [];
368
+		if ($this->event_id) {
369
+			$query_params[0]['EVT_ID'] = $this->event_id;
370
+		}
371
+		// if DTT is included we only show for that datetime.  Otherwise we're showing for all datetimes (the event).
372
+		if ($this->datetime_id) {
373
+			$query_params[0]['Ticket.Datetime.DTT_ID'] = $this->datetime_id;
374
+		}
375
+		$status_ids_array          = apply_filters(
376
+			'FHEE__Extend_Registrations_Admin_Page__get_event_attendees__status_ids_array',
377
+			[EEM_Registration::status_id_pending_payment, EEM_Registration::status_id_approved]
378
+		);
379
+		$query_params[0]['STS_ID'] = ['IN', $status_ids_array];
380
+		return EEM_Registration::instance()->count($query_params);
381
+	}
382
+
383
+
384
+	/**
385
+	 * @param EE_Registration $item
386
+	 * @return string
387
+	 * @throws EE_Error
388
+	 * @throws ReflectionException
389
+	 */
390
+	public function column_cb($item): string
391
+	{
392
+		return sprintf('<input type="checkbox" name="checkbox[%1$s]" value="%1$s" />', $item->ID());
393
+	}
394
+
395
+
396
+	/**
397
+	 * column_REG_att_checked_in
398
+	 *
399
+	 * @param EE_Registration $registration
400
+	 * @return string
401
+	 * @throws EE_Error
402
+	 * @throws InvalidArgumentException
403
+	 * @throws InvalidDataTypeException
404
+	 * @throws InvalidInterfaceException
405
+	 * @throws ReflectionException
406
+	 */
407
+	public function column__REG_att_checked_in(EE_Registration $registration): string
408
+	{
409
+		// we need a local variable for the datetime for each row
410
+		// (so that we don't pollute state for the entire table)
411
+		// so let's try to get it from the registration's event
412
+		$DTT_ID = $this->datetime_id;
413
+		if (! $DTT_ID) {
414
+			$reg_ticket_datetimes = $registration->ticket()->datetimes();
415
+			if (count($reg_ticket_datetimes) === 1) {
416
+				$reg_ticket_datetime = reset($reg_ticket_datetimes);
417
+				$DTT_ID = $reg_ticket_datetime instanceof EE_Datetime ? $reg_ticket_datetime->ID() : 0;
418
+			}
419
+		}
420
+
421
+		if (! $DTT_ID) {
422
+			$this->datetimes_for_current_row = DatetimesForEventCheckIn::fromRegistration($registration);
423
+			$datetime = $this->datetimes_for_current_row->getOneDatetimeForEvent($DTT_ID);
424
+			$DTT_ID = $datetime instanceof EE_Datetime ? $datetime->ID() : 0;
425
+		}
426
+
427
+		$checkin_status_dashicon = CheckinStatusDashicon::fromRegistrationAndDatetimeId(
428
+			$registration,
429
+			$DTT_ID
430
+		);
431
+
432
+		$aria_label = $checkin_status_dashicon->ariaLabel();
433
+		$dashicon_class = $checkin_status_dashicon->cssClasses();
434
+		$attributes = ' onClick="return false"';
435
+		$button_class = 'button button--secondary button--icon-only ee-aria-tooltip ee-aria-tooltip--big-box';
436
+
437
+		if (
438
+			$DTT_ID
439
+			&& EE_Registry::instance()->CAP->current_user_can(
440
+				'ee_edit_checkin',
441
+				'espresso_registrations_toggle_checkin_status',
442
+				$registration->ID()
443
+			)
444
+		) {
445
+			// overwrite the disabled attribute with data attributes for performing checkin
446
+			$attributes = 'data-_regid="' . $registration->ID() . '"';
447
+			$attributes .= ' data-dttid="' . $DTT_ID . '"';
448
+			$attributes .= ' data-nonce="' . wp_create_nonce('checkin_nonce') . '"';
449
+			$button_class .= ' clickable trigger-checkin';
450
+		}
451
+
452
+		$content = '
453 453
         <button aria-label="' . $aria_label . '" class="' . $button_class . '" ' . $attributes . '>
454 454
             <span class="' . $dashicon_class . '" ></span>
455 455
         </button>
456 456
         <span class="show-on-mobile-view-only">' . $this->column_ATT_name($registration) . '</span>';
457
-        return $this->columnContent('_REG_att_checked_in', $content, 'center');
458
-    }
459
-
460
-
461
-    /**
462
-     * @param EE_Registration $registration
463
-     * @return string
464
-     * @throws EE_Error
465
-     * @throws ReflectionException
466
-     */
467
-    public function column_ATT_name(EE_Registration $registration): string
468
-    {
469
-        $attendee = $registration->attendee();
470
-        if (! $attendee instanceof EE_Attendee) {
471
-            return esc_html__('No contact record for this registration.', 'event_espresso');
472
-        }
473
-        // edit attendee link
474
-        $edit_lnk_url = EE_Admin_Page::add_query_args_and_nonce(
475
-            ['action' => 'view_registration', '_REG_ID' => $registration->ID()],
476
-            REG_ADMIN_URL
477
-        );
478
-        $name_link    = '
457
+		return $this->columnContent('_REG_att_checked_in', $content, 'center');
458
+	}
459
+
460
+
461
+	/**
462
+	 * @param EE_Registration $registration
463
+	 * @return string
464
+	 * @throws EE_Error
465
+	 * @throws ReflectionException
466
+	 */
467
+	public function column_ATT_name(EE_Registration $registration): string
468
+	{
469
+		$attendee = $registration->attendee();
470
+		if (! $attendee instanceof EE_Attendee) {
471
+			return esc_html__('No contact record for this registration.', 'event_espresso');
472
+		}
473
+		// edit attendee link
474
+		$edit_lnk_url = EE_Admin_Page::add_query_args_and_nonce(
475
+			['action' => 'view_registration', '_REG_ID' => $registration->ID()],
476
+			REG_ADMIN_URL
477
+		);
478
+		$name_link    = '
479 479
             <span class="ee-status-dot ee-status-bg--' . esc_attr($registration->status_ID()) . ' ee-aria-tooltip"
480 480
             aria-label="' . EEH_Template::pretty_status($registration->status_ID(), false, 'sentence') . '">
481 481
             </span>';
482
-        $name_link    .= EE_Registry::instance()->CAP->current_user_can(
483
-            'ee_edit_contacts',
484
-            'espresso_registrations_edit_attendee'
485
-        )
486
-            ? '<a class="ee-aria-tooltip" href="' . $edit_lnk_url . '" aria-label="' . esc_attr__(
487
-                'View Registration Details',
488
-                'event_espresso'
489
-            ) . '">'
490
-              . $registration->attendee()->full_name()
491
-              . '</a>'
492
-            : $registration->attendee()->full_name();
493
-        $name_link    .= $registration->count() === 1
494
-            ? '&nbsp;<sup><div class="dashicons dashicons-star-filled gold-icon"></div></sup>	'
495
-            : '';
496
-        // add group details
497
-        $name_link .= '&nbsp;' . sprintf(
498
-            esc_html__('(%s of %s)', 'event_espresso'),
499
-            $registration->count(),
500
-            $registration->group_size()
501
-        );
502
-        // add regcode
503
-        $link      = EE_Admin_Page::add_query_args_and_nonce(
504
-            ['action' => 'view_registration', '_REG_ID' => $registration->ID()],
505
-            REG_ADMIN_URL
506
-        );
507
-        $name_link .= '<br>';
508
-        $name_link .= EE_Registry::instance()->instance()->CAP->current_user_can(
509
-            'ee_read_registration',
510
-            'view_registration',
511
-            $registration->ID()
512
-        )
513
-            ? '<a class="ee-aria-tooltip" href="' . $link . '" aria-label="' . esc_attr__(
514
-                'View Registration Details',
515
-                'event_espresso'
516
-            ) . '">'
517
-              . $registration->reg_code()
518
-              . '</a>'
519
-            : $registration->reg_code();
520
-
521
-        $actions                 = [];
522
-        if (
523
-            $this->datetime_id
524
-            && EE_Registry::instance()->CAP->current_user_can(
525
-                'ee_read_checkins',
526
-                'espresso_registrations_registration_checkins'
527
-            )
528
-        ) {
529
-            $checkin_list_url = EE_Admin_Page::add_query_args_and_nonce(
530
-                ['action' => 'registration_checkins', '_REG_ID' => $registration->ID(), 'DTT_ID' => $this->datetime_id],
531
-                REG_ADMIN_URL
532
-            );
533
-            // get the timestamps for this registration's checkins, related to the selected datetime
534
-            /** @var EE_Checkin[] $checkins */
535
-            $checkins = $registration->get_many_related('Checkin', [['DTT_ID' => $this->datetime_id]]);
536
-            if (! empty($checkins)) {
537
-                // get the last timestamp
538
-                $last_checkin = end($checkins);
539
-                // get timestamp string
540
-                $timestamp_string   = $last_checkin->get_datetime('CHK_timestamp');
541
-                $actions['checkin'] = '
482
+		$name_link    .= EE_Registry::instance()->CAP->current_user_can(
483
+			'ee_edit_contacts',
484
+			'espresso_registrations_edit_attendee'
485
+		)
486
+			? '<a class="ee-aria-tooltip" href="' . $edit_lnk_url . '" aria-label="' . esc_attr__(
487
+				'View Registration Details',
488
+				'event_espresso'
489
+			) . '">'
490
+			  . $registration->attendee()->full_name()
491
+			  . '</a>'
492
+			: $registration->attendee()->full_name();
493
+		$name_link    .= $registration->count() === 1
494
+			? '&nbsp;<sup><div class="dashicons dashicons-star-filled gold-icon"></div></sup>	'
495
+			: '';
496
+		// add group details
497
+		$name_link .= '&nbsp;' . sprintf(
498
+			esc_html__('(%s of %s)', 'event_espresso'),
499
+			$registration->count(),
500
+			$registration->group_size()
501
+		);
502
+		// add regcode
503
+		$link      = EE_Admin_Page::add_query_args_and_nonce(
504
+			['action' => 'view_registration', '_REG_ID' => $registration->ID()],
505
+			REG_ADMIN_URL
506
+		);
507
+		$name_link .= '<br>';
508
+		$name_link .= EE_Registry::instance()->instance()->CAP->current_user_can(
509
+			'ee_read_registration',
510
+			'view_registration',
511
+			$registration->ID()
512
+		)
513
+			? '<a class="ee-aria-tooltip" href="' . $link . '" aria-label="' . esc_attr__(
514
+				'View Registration Details',
515
+				'event_espresso'
516
+			) . '">'
517
+			  . $registration->reg_code()
518
+			  . '</a>'
519
+			: $registration->reg_code();
520
+
521
+		$actions                 = [];
522
+		if (
523
+			$this->datetime_id
524
+			&& EE_Registry::instance()->CAP->current_user_can(
525
+				'ee_read_checkins',
526
+				'espresso_registrations_registration_checkins'
527
+			)
528
+		) {
529
+			$checkin_list_url = EE_Admin_Page::add_query_args_and_nonce(
530
+				['action' => 'registration_checkins', '_REG_ID' => $registration->ID(), 'DTT_ID' => $this->datetime_id],
531
+				REG_ADMIN_URL
532
+			);
533
+			// get the timestamps for this registration's checkins, related to the selected datetime
534
+			/** @var EE_Checkin[] $checkins */
535
+			$checkins = $registration->get_many_related('Checkin', [['DTT_ID' => $this->datetime_id]]);
536
+			if (! empty($checkins)) {
537
+				// get the last timestamp
538
+				$last_checkin = end($checkins);
539
+				// get timestamp string
540
+				$timestamp_string   = $last_checkin->get_datetime('CHK_timestamp');
541
+				$actions['checkin'] = '
542 542
                     <a  class="ee-aria-tooltip"
543 543
                         href="' . $checkin_list_url . '"
544 544
                         aria-label="' . esc_attr__(
545
-                            'View this registrant\'s check-ins/checkouts for the datetime',
546
-                            'event_espresso'
547
-                        ) . '"
545
+							'View this registrant\'s check-ins/checkouts for the datetime',
546
+							'event_espresso'
547
+						) . '"
548 548
                     >
549 549
                         ' . $last_checkin->getCheckInText() . ': ' . $timestamp_string . '
550 550
                     </a>';
551
-            }
552
-        }
553
-        $content = (! empty($this->datetime_id) && ! empty($checkins))
554
-            ? sprintf('%1$s %2$s', $name_link, $this->row_actions($actions, true))
555
-            : $name_link;
556
-        return $this->columnContent('ATT_name', $content);
557
-    }
558
-
559
-
560
-    /**
561
-     * @param EE_Registration $registration
562
-     * @return string
563
-     * @throws EE_Error
564
-     * @throws EE_Error
565
-     * @throws ReflectionException
566
-     */
567
-    public function column_ATT_email(EE_Registration $registration): string
568
-    {
569
-        $attendee = $registration->attendee();
570
-        $content = $attendee instanceof EE_Attendee ? $attendee->email() : '';
571
-        return $this->columnContent('ATT_email', $content);
572
-    }
573
-
574
-
575
-    /**
576
-     * @param EE_Registration $registration
577
-     * @return string
578
-     * @throws EE_Error
579
-     * @throws ReflectionException
580
-     */
581
-    public function column_Event(EE_Registration $registration): string
582
-    {
583
-        try {
584
-            $event            = $this->event instanceof EE_Event ? $this->event : $registration->event();
585
-            $checkin_link_url = EE_Admin_Page::add_query_args_and_nonce(
586
-                ['action' => 'event_registrations', 'event_id' => $event->ID()],
587
-                REG_ADMIN_URL
588
-            );
589
-            $content      = EE_Registry::instance()->CAP->current_user_can(
590
-                'ee_read_checkins',
591
-                'espresso_registrations_registration_checkins'
592
-            ) ? '<a class="ee-aria-tooltip" href="' . $checkin_link_url . '" aria-label="'
593
-                . esc_attr__(
594
-                    'View Checkins for this Event',
595
-                    'event_espresso'
596
-                ) . '">' . $event->name() . '</a>' : $event->name();
597
-        } catch (EntityNotFoundException $e) {
598
-            $content = esc_html__('Unknown', 'event_espresso');
599
-        }
600
-        return $this->columnContent('Event', $content);
601
-    }
602
-
603
-
604
-    /**
605
-     * @param EE_Registration $registration
606
-     * @return string
607
-     * @throws EE_Error
608
-     * @throws ReflectionException
609
-     */
610
-    public function column_PRC_name(EE_Registration $registration): string
611
-    {
612
-        $content = $registration->ticket() instanceof EE_Ticket
613
-            ? $registration->ticket()->name()
614
-            : esc_html__(
615
-                "Unknown",
616
-                "event_espresso"
617
-            );
618
-        return $this->columnContent('PRC_name', $content);
619
-    }
620
-
621
-
622
-    /**
623
-     * column_REG_final_price
624
-     *
625
-     * @param EE_Registration $registration
626
-     * @return string
627
-     * @throws EE_Error
628
-     */
629
-    public function column__REG_final_price(EE_Registration $registration): string
630
-    {
631
-        return $this->columnContent('_REG_final_price', $registration->pretty_final_price(), 'end');
632
-    }
633
-
634
-
635
-    /**
636
-     * column_TXN_paid
637
-     *
638
-     * @param EE_Registration $registration
639
-     * @return string
640
-     * @throws EE_Error
641
-     * @throws ReflectionException
642
-     */
643
-    public function column_TXN_paid(EE_Registration $registration): string
644
-    {
645
-        $content = '';
646
-        if ($registration->count() === 1) {
647
-            if ($registration->transaction()->paid() >= $registration->transaction()->total()) {
648
-                return '<div class="dashicons dashicons-yes green-icon"></div>';
649
-            } else {
650
-                $view_txn_lnk_url = EE_Admin_Page::add_query_args_and_nonce(
651
-                    ['action' => 'view_transaction', 'TXN_ID' => $registration->transaction_ID()],
652
-                    TXN_ADMIN_URL
653
-                );
654
-                $content = EE_Registry::instance()->CAP->current_user_can(
655
-                    'ee_read_transaction',
656
-                    'espresso_transactions_view_transaction'
657
-                ) ? '
551
+			}
552
+		}
553
+		$content = (! empty($this->datetime_id) && ! empty($checkins))
554
+			? sprintf('%1$s %2$s', $name_link, $this->row_actions($actions, true))
555
+			: $name_link;
556
+		return $this->columnContent('ATT_name', $content);
557
+	}
558
+
559
+
560
+	/**
561
+	 * @param EE_Registration $registration
562
+	 * @return string
563
+	 * @throws EE_Error
564
+	 * @throws EE_Error
565
+	 * @throws ReflectionException
566
+	 */
567
+	public function column_ATT_email(EE_Registration $registration): string
568
+	{
569
+		$attendee = $registration->attendee();
570
+		$content = $attendee instanceof EE_Attendee ? $attendee->email() : '';
571
+		return $this->columnContent('ATT_email', $content);
572
+	}
573
+
574
+
575
+	/**
576
+	 * @param EE_Registration $registration
577
+	 * @return string
578
+	 * @throws EE_Error
579
+	 * @throws ReflectionException
580
+	 */
581
+	public function column_Event(EE_Registration $registration): string
582
+	{
583
+		try {
584
+			$event            = $this->event instanceof EE_Event ? $this->event : $registration->event();
585
+			$checkin_link_url = EE_Admin_Page::add_query_args_and_nonce(
586
+				['action' => 'event_registrations', 'event_id' => $event->ID()],
587
+				REG_ADMIN_URL
588
+			);
589
+			$content      = EE_Registry::instance()->CAP->current_user_can(
590
+				'ee_read_checkins',
591
+				'espresso_registrations_registration_checkins'
592
+			) ? '<a class="ee-aria-tooltip" href="' . $checkin_link_url . '" aria-label="'
593
+				. esc_attr__(
594
+					'View Checkins for this Event',
595
+					'event_espresso'
596
+				) . '">' . $event->name() . '</a>' : $event->name();
597
+		} catch (EntityNotFoundException $e) {
598
+			$content = esc_html__('Unknown', 'event_espresso');
599
+		}
600
+		return $this->columnContent('Event', $content);
601
+	}
602
+
603
+
604
+	/**
605
+	 * @param EE_Registration $registration
606
+	 * @return string
607
+	 * @throws EE_Error
608
+	 * @throws ReflectionException
609
+	 */
610
+	public function column_PRC_name(EE_Registration $registration): string
611
+	{
612
+		$content = $registration->ticket() instanceof EE_Ticket
613
+			? $registration->ticket()->name()
614
+			: esc_html__(
615
+				"Unknown",
616
+				"event_espresso"
617
+			);
618
+		return $this->columnContent('PRC_name', $content);
619
+	}
620
+
621
+
622
+	/**
623
+	 * column_REG_final_price
624
+	 *
625
+	 * @param EE_Registration $registration
626
+	 * @return string
627
+	 * @throws EE_Error
628
+	 */
629
+	public function column__REG_final_price(EE_Registration $registration): string
630
+	{
631
+		return $this->columnContent('_REG_final_price', $registration->pretty_final_price(), 'end');
632
+	}
633
+
634
+
635
+	/**
636
+	 * column_TXN_paid
637
+	 *
638
+	 * @param EE_Registration $registration
639
+	 * @return string
640
+	 * @throws EE_Error
641
+	 * @throws ReflectionException
642
+	 */
643
+	public function column_TXN_paid(EE_Registration $registration): string
644
+	{
645
+		$content = '';
646
+		if ($registration->count() === 1) {
647
+			if ($registration->transaction()->paid() >= $registration->transaction()->total()) {
648
+				return '<div class="dashicons dashicons-yes green-icon"></div>';
649
+			} else {
650
+				$view_txn_lnk_url = EE_Admin_Page::add_query_args_and_nonce(
651
+					['action' => 'view_transaction', 'TXN_ID' => $registration->transaction_ID()],
652
+					TXN_ADMIN_URL
653
+				);
654
+				$content = EE_Registry::instance()->CAP->current_user_can(
655
+					'ee_read_transaction',
656
+					'espresso_transactions_view_transaction'
657
+				) ? '
658 658
 				<a class="ee-aria-tooltip ee-status-color--'
659
-                    . $registration->transaction()->status_ID()
660
-                    . '" href="'
661
-                    . $view_txn_lnk_url
662
-                    . '"  aria-label="'
663
-                    . esc_attr__('View Transaction', 'event_espresso')
664
-                    . '">
659
+					. $registration->transaction()->status_ID()
660
+					. '" href="'
661
+					. $view_txn_lnk_url
662
+					. '"  aria-label="'
663
+					. esc_attr__('View Transaction', 'event_espresso')
664
+					. '">
665 665
 						'
666
-                    . $registration->transaction()->pretty_paid()
667
-                    . '
666
+					. $registration->transaction()->pretty_paid()
667
+					. '
668 668
 					</a>
669 669
 				' : $registration->transaction()->pretty_paid();
670
-            }
671
-        }
672
-        return $this->columnContent('TXN_paid', $content, 'end');
673
-    }
674
-
675
-
676
-    /**
677
-     *        column_TXN_total
678
-     *
679
-     * @param EE_Registration $registration
680
-     * @return string
681
-     * @throws EE_Error
682
-     * @throws ReflectionException
683
-     */
684
-    public function column_TXN_total(EE_Registration $registration): string
685
-    {
686
-        $content = '';
687
-        $txn = $registration->transaction();
688
-        $view_txn_url = add_query_arg(['action' => 'view_transaction', 'TXN_ID' => $txn->ID()], TXN_ADMIN_URL);
689
-        if ($registration->get('REG_count') === 1) {
690
-            $line_total_obj = $txn->total_line_item();
691
-            $txn_total      = $line_total_obj instanceof EE_Line_Item
692
-                ? $line_total_obj->get_pretty('LIN_total')
693
-                : esc_html__(
694
-                    'View Transaction',
695
-                    'event_espresso'
696
-                );
697
-            $content = EE_Registry::instance()->CAP->current_user_can(
698
-                'ee_read_transaction',
699
-                'espresso_transactions_view_transaction'
700
-            ) ? '<a class="ee-aria-tooltip" href="'
701
-                . $view_txn_url
702
-                . '" aria-label="'
703
-                . esc_attr__('View Transaction', 'event_espresso')
704
-                . '">'
705
-                . $txn_total
706
-                . '</a>'
707
-                : $txn_total;
708
-        }
709
-        return $this->columnContent('TXN_total', $content, 'end');
710
-    }
670
+			}
671
+		}
672
+		return $this->columnContent('TXN_paid', $content, 'end');
673
+	}
674
+
675
+
676
+	/**
677
+	 *        column_TXN_total
678
+	 *
679
+	 * @param EE_Registration $registration
680
+	 * @return string
681
+	 * @throws EE_Error
682
+	 * @throws ReflectionException
683
+	 */
684
+	public function column_TXN_total(EE_Registration $registration): string
685
+	{
686
+		$content = '';
687
+		$txn = $registration->transaction();
688
+		$view_txn_url = add_query_arg(['action' => 'view_transaction', 'TXN_ID' => $txn->ID()], TXN_ADMIN_URL);
689
+		if ($registration->get('REG_count') === 1) {
690
+			$line_total_obj = $txn->total_line_item();
691
+			$txn_total      = $line_total_obj instanceof EE_Line_Item
692
+				? $line_total_obj->get_pretty('LIN_total')
693
+				: esc_html__(
694
+					'View Transaction',
695
+					'event_espresso'
696
+				);
697
+			$content = EE_Registry::instance()->CAP->current_user_can(
698
+				'ee_read_transaction',
699
+				'espresso_transactions_view_transaction'
700
+			) ? '<a class="ee-aria-tooltip" href="'
701
+				. $view_txn_url
702
+				. '" aria-label="'
703
+				. esc_attr__('View Transaction', 'event_espresso')
704
+				. '">'
705
+				. $txn_total
706
+				. '</a>'
707
+				: $txn_total;
708
+		}
709
+		return $this->columnContent('TXN_total', $content, 'end');
710
+	}
711 711
 }
Please login to merge, or discard this patch.
caffeinated/core/domain/entities/routing/handlers/admin/PueRequests.php 1 patch
Indentation   +110 added lines, -110 removed lines patch added patch discarded remove patch
@@ -20,125 +20,125 @@
 block discarded – undo
20 20
  */
21 21
 class PueRequests extends Route
22 22
 {
23
-    /**
24
-     * @var   bool
25
-     * @since 5.0.0.p
26
-     */
27
-    private $load_pue = true;
23
+	/**
24
+	 * @var   bool
25
+	 * @since 5.0.0.p
26
+	 */
27
+	private $load_pue = true;
28 28
 
29 29
 
30
-    /**
31
-     * returns true if the current request matches this route
32
-     *
33
-     * @return bool
34
-     * @since   5.0.0.p
35
-     */
36
-    public function matchesCurrentRequest(): bool
37
-    {
38
-        // route may match, but PUE loading is still conditional based on this filter
39
-        $this->load_pue = apply_filters('FHEE__EE_System__brew_espresso__load_pue', true);
40
-        return $this->request->isAdmin() || $this->request->isAdminAjax() || $this->request->isActivation();
41
-    }
30
+	/**
31
+	 * returns true if the current request matches this route
32
+	 *
33
+	 * @return bool
34
+	 * @since   5.0.0.p
35
+	 */
36
+	public function matchesCurrentRequest(): bool
37
+	{
38
+		// route may match, but PUE loading is still conditional based on this filter
39
+		$this->load_pue = apply_filters('FHEE__EE_System__brew_espresso__load_pue', true);
40
+		return $this->request->isAdmin() || $this->request->isAdminAjax() || $this->request->isActivation();
41
+	}
42 42
 
43 43
 
44
-    /**
45
-     * @since 5.0.0.p
46
-     */
47
-    protected function registerDependencies()
48
-    {
49
-        if ($this->load_pue) {
50
-            $this->dependency_map->registerDependencies(
51
-                'EventEspresso\caffeinated\core\services\licensing\LicenseService',
52
-                [
53
-                    'EventEspresso\caffeinated\core\domain\services\pue\Stats'  => EE_Dependency_Map::load_from_cache,
54
-                    'EventEspresso\caffeinated\core\domain\services\pue\Config' => EE_Dependency_Map::load_from_cache,
55
-                ]
56
-            );
57
-            $this->dependency_map->registerDependencies(
58
-                'EventEspresso\caffeinated\core\domain\services\pue\Stats',
59
-                [
60
-                    'EventEspresso\caffeinated\core\domain\services\pue\Config'        => EE_Dependency_Map::load_from_cache,
61
-                    'EE_Maintenance_Mode'                                              => EE_Dependency_Map::load_from_cache,
62
-                    'EventEspresso\caffeinated\core\domain\services\pue\StatsGatherer' => EE_Dependency_Map::load_from_cache,
63
-                ]
64
-            );
65
-            $this->dependency_map->registerDependencies(
66
-                'EventEspresso\caffeinated\core\domain\services\pue\Config',
67
-                [
68
-                    'EE_Network_Config' => EE_Dependency_Map::load_from_cache,
69
-                    'EE_Config'         => EE_Dependency_Map::load_from_cache,
70
-                ]
71
-            );
72
-            $this->dependency_map->registerDependencies(
73
-                'EventEspresso\caffeinated\core\domain\services\pue\StatsGatherer',
74
-                [
75
-                    'EEM_Payment_Method' => EE_Dependency_Map::load_from_cache,
76
-                    'EEM_Event'          => EE_Dependency_Map::load_from_cache,
77
-                    'EEM_Datetime'       => EE_Dependency_Map::load_from_cache,
78
-                    'EEM_Ticket'         => EE_Dependency_Map::load_from_cache,
79
-                    'EEM_Registration'   => EE_Dependency_Map::load_from_cache,
80
-                    'EEM_Transaction'    => EE_Dependency_Map::load_from_cache,
81
-                    'EE_Config'          => EE_Dependency_Map::load_from_cache,
82
-                ]
83
-            );
84
-            $this->dependency_map->registerDependencies(
85
-                'EventEspresso\caffeinated\core\services\licensing\UserExperienceForm',
86
-                [
87
-                    'EE_Core_Config'         => EE_Dependency_Map::load_from_cache,
88
-                    'EE_Network_Core_Config' => EE_Dependency_Map::load_from_cache,
89
-                ]
90
-            );
91
-        }
92
-    }
44
+	/**
45
+	 * @since 5.0.0.p
46
+	 */
47
+	protected function registerDependencies()
48
+	{
49
+		if ($this->load_pue) {
50
+			$this->dependency_map->registerDependencies(
51
+				'EventEspresso\caffeinated\core\services\licensing\LicenseService',
52
+				[
53
+					'EventEspresso\caffeinated\core\domain\services\pue\Stats'  => EE_Dependency_Map::load_from_cache,
54
+					'EventEspresso\caffeinated\core\domain\services\pue\Config' => EE_Dependency_Map::load_from_cache,
55
+				]
56
+			);
57
+			$this->dependency_map->registerDependencies(
58
+				'EventEspresso\caffeinated\core\domain\services\pue\Stats',
59
+				[
60
+					'EventEspresso\caffeinated\core\domain\services\pue\Config'        => EE_Dependency_Map::load_from_cache,
61
+					'EE_Maintenance_Mode'                                              => EE_Dependency_Map::load_from_cache,
62
+					'EventEspresso\caffeinated\core\domain\services\pue\StatsGatherer' => EE_Dependency_Map::load_from_cache,
63
+				]
64
+			);
65
+			$this->dependency_map->registerDependencies(
66
+				'EventEspresso\caffeinated\core\domain\services\pue\Config',
67
+				[
68
+					'EE_Network_Config' => EE_Dependency_Map::load_from_cache,
69
+					'EE_Config'         => EE_Dependency_Map::load_from_cache,
70
+				]
71
+			);
72
+			$this->dependency_map->registerDependencies(
73
+				'EventEspresso\caffeinated\core\domain\services\pue\StatsGatherer',
74
+				[
75
+					'EEM_Payment_Method' => EE_Dependency_Map::load_from_cache,
76
+					'EEM_Event'          => EE_Dependency_Map::load_from_cache,
77
+					'EEM_Datetime'       => EE_Dependency_Map::load_from_cache,
78
+					'EEM_Ticket'         => EE_Dependency_Map::load_from_cache,
79
+					'EEM_Registration'   => EE_Dependency_Map::load_from_cache,
80
+					'EEM_Transaction'    => EE_Dependency_Map::load_from_cache,
81
+					'EE_Config'          => EE_Dependency_Map::load_from_cache,
82
+				]
83
+			);
84
+			$this->dependency_map->registerDependencies(
85
+				'EventEspresso\caffeinated\core\services\licensing\UserExperienceForm',
86
+				[
87
+					'EE_Core_Config'         => EE_Dependency_Map::load_from_cache,
88
+					'EE_Network_Core_Config' => EE_Dependency_Map::load_from_cache,
89
+				]
90
+			);
91
+		}
92
+	}
93 93
 
94 94
 
95
-    /**
96
-     * implements logic required to run during request
97
-     *
98
-     * @return bool
99
-     * @since   5.0.0.p
100
-     */
101
-    protected function requestHandler(): bool
102
-    {
103
-        add_filter(
104
-            'FHEE__EE_Register_Addon__register',
105
-            [RegisterAddonPUE::class, 'registerPUE'],
106
-            10,
107
-            4
108
-        );
109
-        add_action(
110
-            'AHEE__EE_Register_Addon___load_and_init_addon_class',
111
-            [RegisterAddonPUE::class, 'setAddonPueSlug'],
112
-            10,
113
-            2
114
-        );
115
-        if ($this->load_pue) {
116
-            add_action('AHEE__EE_System__brew_espresso__complete', [$this, 'loadLicenseService']);
117
-            add_filter(
118
-                'FHEE__EventEspresso_admin_pages_general_settings_OrganizationSettings__generate__form',
119
-                [$this, 'loadUserExperienceForm']
120
-            );
121
-        }
95
+	/**
96
+	 * implements logic required to run during request
97
+	 *
98
+	 * @return bool
99
+	 * @since   5.0.0.p
100
+	 */
101
+	protected function requestHandler(): bool
102
+	{
103
+		add_filter(
104
+			'FHEE__EE_Register_Addon__register',
105
+			[RegisterAddonPUE::class, 'registerPUE'],
106
+			10,
107
+			4
108
+		);
109
+		add_action(
110
+			'AHEE__EE_Register_Addon___load_and_init_addon_class',
111
+			[RegisterAddonPUE::class, 'setAddonPueSlug'],
112
+			10,
113
+			2
114
+		);
115
+		if ($this->load_pue) {
116
+			add_action('AHEE__EE_System__brew_espresso__complete', [$this, 'loadLicenseService']);
117
+			add_filter(
118
+				'FHEE__EventEspresso_admin_pages_general_settings_OrganizationSettings__generate__form',
119
+				[$this, 'loadUserExperienceForm']
120
+			);
121
+		}
122 122
 
123
-        return true;
124
-    }
123
+		return true;
124
+	}
125 125
 
126 126
 
127
-    public function loadLicenseService()
128
-    {
129
-        /** @var LicenseService $license_service */
130
-        $license_service = $this->loader->getShared(LicenseService::class);
131
-        $license_service->loadPueClient();
132
-    }
127
+	public function loadLicenseService()
128
+	{
129
+		/** @var LicenseService $license_service */
130
+		$license_service = $this->loader->getShared(LicenseService::class);
131
+		$license_service->loadPueClient();
132
+	}
133 133
 
134 134
 
135
-    /**
136
-     * @throws EE_Error
137
-     */
138
-    public function loadUserExperienceForm(EE_Form_Section_Proper $org_settings_form): EE_Form_Section_Proper
139
-    {
140
-        /** @var UserExperienceForm $uxip_form */
141
-        $uxip_form = $this->loader->getShared(UserExperienceForm::class);
142
-        return $uxip_form->uxipFormSections($org_settings_form);
143
-    }
135
+	/**
136
+	 * @throws EE_Error
137
+	 */
138
+	public function loadUserExperienceForm(EE_Form_Section_Proper $org_settings_form): EE_Form_Section_Proper
139
+	{
140
+		/** @var UserExperienceForm $uxip_form */
141
+		$uxip_form = $this->loader->getShared(UserExperienceForm::class);
142
+		return $uxip_form->uxipFormSections($org_settings_form);
143
+	}
144 144
 }
Please login to merge, or discard this patch.
registration_form/Registration_Form_Questions_Admin_List_Table.class.php 1 patch
Indentation   +212 added lines, -212 removed lines patch added patch discarded remove patch
@@ -15,223 +15,223 @@
 block discarded – undo
15 15
  */
16 16
 class Registration_Form_Questions_Admin_List_Table extends EE_Admin_List_Table
17 17
 {
18
-    /**
19
-     * @var Registration_Form_Admin_Page $_admin_page
20
-     */
21
-    protected $_admin_page;
22
-
23
-    /**
24
-     * @var RegFormListTableUserCapabilities
25
-     */
26
-    protected $caps_handler;
27
-
28
-
29
-    public function __construct($admin_page)
30
-    {
31
-        $this->caps_handler = new RegFormListTableUserCapabilities(EE_Registry::instance()->CAP);
32
-        parent::__construct($admin_page);
33
-
34
-        if (! defined('REG_ADMIN_URL')) {
35
-            define('REG_ADMIN_URL', EVENTS_ADMIN_URL);
36
-        }
37
-    }
38
-
39
-
40
-    /**
41
-     * @throws EE_Error
42
-     */
43
-    protected function _setup_data()
44
-    {
45
-        if (isset($this->_req_data['status']) && $this->_req_data['status'] == 'trash') {
46
-            $this->_data = $this->_admin_page->get_trashed_questions($this->_per_page, $this->_current_page);
47
-        } else {
48
-            $this->_data = $this->_admin_page->get_questions($this->_per_page, $this->_current_page);
49
-        }
50
-        $this->_all_data_count = $this->_admin_page->get_questions($this->_per_page, $this->_current_page, true);
51
-    }
52
-
53
-
54
-    protected function _set_properties()
55
-    {
56
-        $this->_wp_list_args = [
57
-            'singular' => esc_html__('question', 'event_espresso'),
58
-            'plural'   => esc_html__('questions', 'event_espresso'),
59
-            'ajax'     => true, // for now,
60
-            'screen'   => $this->_admin_page->get_current_screen()->id,
61
-        ];
62
-
63
-        $this->_columns = [
64
-            'cb'           => '<input type="checkbox" />',
65
-            'id'           => esc_html__('ID', 'event_espresso'),
66
-            'display_text' => esc_html__('Question', 'event_espresso'),
67
-            'admin_label'  => esc_html__('Admin Label', 'event_espresso'),
68
-            'type'         => esc_html__('Type', 'event_espresso'),
69
-            'values'       => esc_html__('Values', 'event_espresso'),
70
-            'required'     => esc_html__('Req', 'event_espresso'),
71
-        ];
72
-
73
-        $this->_primary_column = 'id';
74
-
75
-        $this->_sortable_columns = [
76
-            'id'           => ['QST_ID' => false],
77
-            'display_text' => ['QST_display_text' => false],
78
-        ];
79
-
80
-        $this->_hidden_columns = [];
81
-    }
82
-
83
-
84
-    // not needed
85
-    protected function _get_table_filters()
86
-    {
87
-        return [];
88
-    }
89
-
90
-
91
-    /**
92
-     * @throws EE_Error
93
-     */
94
-    protected function _add_view_counts()
95
-    {
96
-        $this->_views['all']['count'] = $this->_admin_page->get_questions($this->_per_page, $this->_current_page, true);
97
-        if ($this->caps_handler->userCanTrashQuestions()) {
98
-            $this->_views['trash']['count'] = $this->_admin_page->get_trashed_questions(-1, $this->_current_page, true);
99
-        }
100
-    }
101
-
102
-
103
-    /**
104
-     * @param EE_Question $item
105
-     * @return string
106
-     * @throws EE_Error
107
-     * @throws ReflectionException
108
-     */
109
-    public function column_cb($item): string
110
-    {
111
-        $system_question      = $item->is_system_question();
112
-        $related_answer_count = $item->count_related('Answer');
113
-        $has_answers          = ! $system_question && $related_answer_count > 0 && $this->_view == 'trash';
114
-        $notice               = $has_answers
115
-            ? esc_html__(
116
-                'This question has answers attached to it from registrations that have the question.  It cannot be permanently deleted.',
117
-                'event_espresso'
118
-            )
119
-            : esc_html__('This question is a system question and cannot be trashed', 'event_espresso');
120
-
121
-        return $system_question || $has_answers
122
-            ? '
18
+	/**
19
+	 * @var Registration_Form_Admin_Page $_admin_page
20
+	 */
21
+	protected $_admin_page;
22
+
23
+	/**
24
+	 * @var RegFormListTableUserCapabilities
25
+	 */
26
+	protected $caps_handler;
27
+
28
+
29
+	public function __construct($admin_page)
30
+	{
31
+		$this->caps_handler = new RegFormListTableUserCapabilities(EE_Registry::instance()->CAP);
32
+		parent::__construct($admin_page);
33
+
34
+		if (! defined('REG_ADMIN_URL')) {
35
+			define('REG_ADMIN_URL', EVENTS_ADMIN_URL);
36
+		}
37
+	}
38
+
39
+
40
+	/**
41
+	 * @throws EE_Error
42
+	 */
43
+	protected function _setup_data()
44
+	{
45
+		if (isset($this->_req_data['status']) && $this->_req_data['status'] == 'trash') {
46
+			$this->_data = $this->_admin_page->get_trashed_questions($this->_per_page, $this->_current_page);
47
+		} else {
48
+			$this->_data = $this->_admin_page->get_questions($this->_per_page, $this->_current_page);
49
+		}
50
+		$this->_all_data_count = $this->_admin_page->get_questions($this->_per_page, $this->_current_page, true);
51
+	}
52
+
53
+
54
+	protected function _set_properties()
55
+	{
56
+		$this->_wp_list_args = [
57
+			'singular' => esc_html__('question', 'event_espresso'),
58
+			'plural'   => esc_html__('questions', 'event_espresso'),
59
+			'ajax'     => true, // for now,
60
+			'screen'   => $this->_admin_page->get_current_screen()->id,
61
+		];
62
+
63
+		$this->_columns = [
64
+			'cb'           => '<input type="checkbox" />',
65
+			'id'           => esc_html__('ID', 'event_espresso'),
66
+			'display_text' => esc_html__('Question', 'event_espresso'),
67
+			'admin_label'  => esc_html__('Admin Label', 'event_espresso'),
68
+			'type'         => esc_html__('Type', 'event_espresso'),
69
+			'values'       => esc_html__('Values', 'event_espresso'),
70
+			'required'     => esc_html__('Req', 'event_espresso'),
71
+		];
72
+
73
+		$this->_primary_column = 'id';
74
+
75
+		$this->_sortable_columns = [
76
+			'id'           => ['QST_ID' => false],
77
+			'display_text' => ['QST_display_text' => false],
78
+		];
79
+
80
+		$this->_hidden_columns = [];
81
+	}
82
+
83
+
84
+	// not needed
85
+	protected function _get_table_filters()
86
+	{
87
+		return [];
88
+	}
89
+
90
+
91
+	/**
92
+	 * @throws EE_Error
93
+	 */
94
+	protected function _add_view_counts()
95
+	{
96
+		$this->_views['all']['count'] = $this->_admin_page->get_questions($this->_per_page, $this->_current_page, true);
97
+		if ($this->caps_handler->userCanTrashQuestions()) {
98
+			$this->_views['trash']['count'] = $this->_admin_page->get_trashed_questions(-1, $this->_current_page, true);
99
+		}
100
+	}
101
+
102
+
103
+	/**
104
+	 * @param EE_Question $item
105
+	 * @return string
106
+	 * @throws EE_Error
107
+	 * @throws ReflectionException
108
+	 */
109
+	public function column_cb($item): string
110
+	{
111
+		$system_question      = $item->is_system_question();
112
+		$related_answer_count = $item->count_related('Answer');
113
+		$has_answers          = ! $system_question && $related_answer_count > 0 && $this->_view == 'trash';
114
+		$notice               = $has_answers
115
+			? esc_html__(
116
+				'This question has answers attached to it from registrations that have the question.  It cannot be permanently deleted.',
117
+				'event_espresso'
118
+			)
119
+			: esc_html__('This question is a system question and cannot be trashed', 'event_espresso');
120
+
121
+		return $system_question || $has_answers
122
+			? '
123 123
             <span class="dashicons dashicons-lock ee-locked-entity ee-aria-tooltip"
124 124
                     aria-label="' . $notice . '"></span>
125 125
             ' . sprintf('<input type="hidden" name="hdnchk[%1$d]" value="%1$d" />', $item->ID())
126
-            : sprintf('<input type="checkbox" class="QST_ID" name="checkbox[%1$d]" value="%1$d" />', $item->ID());
127
-    }
128
-
129
-
130
-    /**
131
-     * @param EE_Question $item
132
-     * @return string
133
-     * @throws EE_Error
134
-     * @throws ReflectionException
135
-     */
136
-    public function column_id(EE_Question $item): string
137
-    {
138
-        $content = '
126
+			: sprintf('<input type="checkbox" class="QST_ID" name="checkbox[%1$d]" value="%1$d" />', $item->ID());
127
+	}
128
+
129
+
130
+	/**
131
+	 * @param EE_Question $item
132
+	 * @return string
133
+	 * @throws EE_Error
134
+	 * @throws ReflectionException
135
+	 */
136
+	public function column_id(EE_Question $item): string
137
+	{
138
+		$content = '
139 139
             <span class="ee-entity-id">' . $item->ID() . '</span>
140 140
             <span class="show-on-mobile-view-only">
141 141
                 ' . $this->column_display_text($item, false) . '
142 142
             </span>';
143
-        return $this->columnContent('id', $content, 'end');
144
-    }
145
-
146
-
147
-    /**
148
-     * @param EE_Question $question
149
-     * @param bool        $prep_content
150
-     * @return string
151
-     * @throws EE_Error
152
-     * @throws ReflectionException
153
-     */
154
-    public function column_display_text(EE_Question $question, bool $prep_content = true): string
155
-    {
156
-        if ($this->caps_handler->userCanEditQuestion($question)) {
157
-            $content = $this->$this->getActionLink(
158
-                $this->getActionUrl($question, self::ACTION_EDIT),
159
-                $prep_content ? $question->display_text() : $question->admin_label(),
160
-                esc_attr__('Edit Question', 'event_espresso'),
161
-                'row-title'
162
-            );
163
-            $content .= $this->row_actions(
164
-                [
165
-                    'edit' => $this->getActionLink(
166
-                        $this->getActionUrl($question, self::ACTION_EDIT),
167
-                        esc_html__('Edit', 'event_espresso'),
168
-                        esc_attr__('Edit Question', 'event_espresso')
169
-                    ),
170
-                ]
171
-            );
172
-        } else {
173
-            $content = $question->display_text();
174
-        }
175
-
176
-        return $prep_content ? $this->columnContent('display_text', $content) : $content;
177
-    }
178
-
179
-
180
-    /**
181
-     * @param EE_Question $question
182
-     * @param string      $action
183
-     * @return string
184
-     * @throws EE_Error
185
-     * @throws ReflectionException
186
-     * @since 5.0.0.p
187
-     */
188
-    protected function getActionUrl(EE_Question $question, string $action): string
189
-    {
190
-        if (! in_array($action, self::$actions)) {
191
-            throw new DomainException(esc_html__('Invalid Action', 'event_espresso'));
192
-        }
193
-        return EE_Admin_Page::add_query_args_and_nonce(
194
-            [
195
-                'action'   => $action === self::ACTION_DELETE ? "{$action}_questions" : "{$action}_question",
196
-                'QST_ID'   => $question->ID(),
197
-                'noheader' => $action !== self::ACTION_EDIT,
198
-            ],
199
-            EE_FORMS_ADMIN_URL
200
-        );
201
-    }
202
-
203
-
204
-    public function column_admin_label(EE_Question $item): string
205
-    {
206
-        return $this->columnContent('admin_label', $item->admin_label());
207
-    }
208
-
209
-
210
-    public function column_values(EE_Question $item): string
211
-    {
212
-        $optionNames = [];
213
-        $options     = $item->options();
214
-        if (empty($options)) {
215
-            $content = "N/A";
216
-        } else {
217
-            foreach ($options as $option) {
218
-                $optionNames[] = $option->value();
219
-            }
220
-            $content = implode(', ', $optionNames);
221
-        }
222
-        return $this->columnContent('values', $content);
223
-    }
224
-
225
-
226
-    public function column_type(EE_Question $item): string
227
-    {
228
-        return $this->columnContent('type', $item->type());
229
-    }
230
-
231
-
232
-    public function column_required(EE_Question $item): string
233
-    {
234
-        $content = $item->required() ? 'Yes' : '';
235
-        return $this->columnContent('required', $content);
236
-    }
143
+		return $this->columnContent('id', $content, 'end');
144
+	}
145
+
146
+
147
+	/**
148
+	 * @param EE_Question $question
149
+	 * @param bool        $prep_content
150
+	 * @return string
151
+	 * @throws EE_Error
152
+	 * @throws ReflectionException
153
+	 */
154
+	public function column_display_text(EE_Question $question, bool $prep_content = true): string
155
+	{
156
+		if ($this->caps_handler->userCanEditQuestion($question)) {
157
+			$content = $this->$this->getActionLink(
158
+				$this->getActionUrl($question, self::ACTION_EDIT),
159
+				$prep_content ? $question->display_text() : $question->admin_label(),
160
+				esc_attr__('Edit Question', 'event_espresso'),
161
+				'row-title'
162
+			);
163
+			$content .= $this->row_actions(
164
+				[
165
+					'edit' => $this->getActionLink(
166
+						$this->getActionUrl($question, self::ACTION_EDIT),
167
+						esc_html__('Edit', 'event_espresso'),
168
+						esc_attr__('Edit Question', 'event_espresso')
169
+					),
170
+				]
171
+			);
172
+		} else {
173
+			$content = $question->display_text();
174
+		}
175
+
176
+		return $prep_content ? $this->columnContent('display_text', $content) : $content;
177
+	}
178
+
179
+
180
+	/**
181
+	 * @param EE_Question $question
182
+	 * @param string      $action
183
+	 * @return string
184
+	 * @throws EE_Error
185
+	 * @throws ReflectionException
186
+	 * @since 5.0.0.p
187
+	 */
188
+	protected function getActionUrl(EE_Question $question, string $action): string
189
+	{
190
+		if (! in_array($action, self::$actions)) {
191
+			throw new DomainException(esc_html__('Invalid Action', 'event_espresso'));
192
+		}
193
+		return EE_Admin_Page::add_query_args_and_nonce(
194
+			[
195
+				'action'   => $action === self::ACTION_DELETE ? "{$action}_questions" : "{$action}_question",
196
+				'QST_ID'   => $question->ID(),
197
+				'noheader' => $action !== self::ACTION_EDIT,
198
+			],
199
+			EE_FORMS_ADMIN_URL
200
+		);
201
+	}
202
+
203
+
204
+	public function column_admin_label(EE_Question $item): string
205
+	{
206
+		return $this->columnContent('admin_label', $item->admin_label());
207
+	}
208
+
209
+
210
+	public function column_values(EE_Question $item): string
211
+	{
212
+		$optionNames = [];
213
+		$options     = $item->options();
214
+		if (empty($options)) {
215
+			$content = "N/A";
216
+		} else {
217
+			foreach ($options as $option) {
218
+				$optionNames[] = $option->value();
219
+			}
220
+			$content = implode(', ', $optionNames);
221
+		}
222
+		return $this->columnContent('values', $content);
223
+	}
224
+
225
+
226
+	public function column_type(EE_Question $item): string
227
+	{
228
+		return $this->columnContent('type', $item->type());
229
+	}
230
+
231
+
232
+	public function column_required(EE_Question $item): string
233
+	{
234
+		$content = $item->required() ? 'Yes' : '';
235
+		return $this->columnContent('required', $content);
236
+	}
237 237
 }
Please login to merge, or discard this patch.
admin_pages/events/Events_Admin_Page.core.php 1 patch
Indentation   +2956 added lines, -2956 removed lines patch added patch discarded remove patch
@@ -18,2963 +18,2963 @@
 block discarded – undo
18 18
  */
19 19
 class Events_Admin_Page extends EE_Admin_Page_CPT
20 20
 {
21
-    /**
22
-     * This will hold the event object for event_details screen.
21
+	/**
22
+	 * This will hold the event object for event_details screen.
23
+	 *
24
+	 * @var EE_Event $_event
25
+	 */
26
+	protected $_event;
27
+
28
+
29
+	/**
30
+	 * This will hold the category object for category_details screen.
31
+	 *
32
+	 * @var stdClass $_category
33
+	 */
34
+	protected $_category;
35
+
36
+
37
+	/**
38
+	 * This will hold the event model instance
39
+	 *
40
+	 * @var EEM_Event $_event_model
41
+	 */
42
+	protected $_event_model;
43
+
44
+
45
+	/**
46
+	 * @var EE_Event
47
+	 */
48
+	protected $_cpt_model_obj = false;
49
+
50
+
51
+	/**
52
+	 * @var NodeGroupDao
53
+	 */
54
+	protected $model_obj_node_group_persister;
55
+
56
+	/**
57
+	 * @var AdvancedEditorAdminFormSection
58
+	 */
59
+	protected $advanced_editor_admin_form;
60
+
61
+
62
+	/**
63
+	 * Initialize page props for this admin page group.
64
+	 */
65
+	protected function _init_page_props()
66
+	{
67
+		$this->page_slug        = EVENTS_PG_SLUG;
68
+		$this->page_label       = EVENTS_LABEL;
69
+		$this->_admin_base_url  = EVENTS_ADMIN_URL;
70
+		$this->_admin_base_path = EVENTS_ADMIN;
71
+		$this->_cpt_model_names = [
72
+			'create_new' => 'EEM_Event',
73
+			'edit'       => 'EEM_Event',
74
+		];
75
+		$this->_cpt_edit_routes = [
76
+			'espresso_events' => 'edit',
77
+		];
78
+		add_action(
79
+			'AHEE__EE_Admin_Page_CPT__set_model_object__after_set_object',
80
+			[$this, 'verify_event_edit'],
81
+			10,
82
+			2
83
+		);
84
+	}
85
+
86
+
87
+	/**
88
+	 * Sets the ajax hooks used for this admin page group.
89
+	 */
90
+	protected function _ajax_hooks()
91
+	{
92
+		add_action('wp_ajax_ee_save_timezone_setting', [$this, 'saveTimezoneString']);
93
+	}
94
+
95
+
96
+	/**
97
+	 * Sets the page properties for this admin page group.
98
+	 */
99
+	protected function _define_page_props()
100
+	{
101
+		$event_id = $this->request->getRequestParam('post', 0, DataType::INT);
102
+		if ($event_id) {
103
+			$event_post = get_post($event_id);
104
+		}
105
+
106
+		$this->_admin_page_title = EVENTS_LABEL;
107
+		$this->_labels           = [
108
+			'buttons'      => [
109
+				'add'             => esc_html__('Add New Event', 'event_espresso'),
110
+				'edit'            => esc_html__('Edit Event', 'event_espresso'),
111
+				'delete'          => esc_html__('Delete Event', 'event_espresso'),
112
+				'add_category'    => esc_html__('Add New Category', 'event_espresso'),
113
+				'edit_category'   => esc_html__('Edit Category', 'event_espresso'),
114
+				'delete_category' => esc_html__('Delete Category', 'event_espresso'),
115
+			],
116
+			'editor_title' => [
117
+				'espresso_events' => isset($event_post) && $event_post instanceof WP_Post
118
+					? $event_post->post_title
119
+					: esc_html__('Edit Event', 'event_espresso'),
120
+			],
121
+			'publishbox'   => [
122
+				'create_new'        => esc_html__('Save New Event', 'event_espresso'),
123
+				'edit'              => esc_html__('Update Event', 'event_espresso'),
124
+				'add_category'      => esc_html__('Save New Category', 'event_espresso'),
125
+				'edit_category'     => esc_html__('Update Category', 'event_espresso'),
126
+				'template_settings' => esc_html__('Update Settings', 'event_espresso'),
127
+			],
128
+		];
129
+	}
130
+
131
+
132
+	/**
133
+	 * Sets the page routes property for this admin page group.
134
+	 */
135
+	protected function _set_page_routes()
136
+	{
137
+		// load formatter helper
138
+		// load field generator helper
139
+		// is there a evt_id in the request?
140
+		$EVT_ID = $this->request->getRequestParam('EVT_ID', 0, DataType::INT);
141
+		$EVT_ID = $this->request->getRequestParam('post', $EVT_ID, DataType::INT);
142
+
143
+		$this->_page_routes = [
144
+			'default'                       => [
145
+				'func'       => [$this, '_events_overview_list_table'],
146
+				'capability' => 'ee_read_events',
147
+			],
148
+			'create_new'                    => [
149
+				'func'       => [$this, '_create_new_cpt_item'],
150
+				'capability' => 'ee_edit_events',
151
+			],
152
+			'edit'                          => [
153
+				'func'       => [$this, '_edit_cpt_item'],
154
+				'capability' => 'ee_edit_event',
155
+				'obj_id'     => $EVT_ID,
156
+			],
157
+			'copy_event'                    => [
158
+				'func'       => [$this, '_copy_events'],
159
+				'capability' => 'ee_edit_event',
160
+				'obj_id'     => $EVT_ID,
161
+				'noheader'   => true,
162
+			],
163
+			'trash_event'                   => [
164
+				'func'       => [$this, '_trash_or_restore_event'],
165
+				'args'       => ['event_status' => 'trash'],
166
+				'capability' => 'ee_delete_event',
167
+				'obj_id'     => $EVT_ID,
168
+				'noheader'   => true,
169
+			],
170
+			'trash_events'                  => [
171
+				'func'       => [$this, '_trash_or_restore_events'],
172
+				'args'       => ['event_status' => 'trash'],
173
+				'capability' => 'ee_delete_events',
174
+				'noheader'   => true,
175
+			],
176
+			'restore_event'                 => [
177
+				'func'       => [$this, '_trash_or_restore_event'],
178
+				'args'       => ['event_status' => 'draft'],
179
+				'capability' => 'ee_delete_event',
180
+				'obj_id'     => $EVT_ID,
181
+				'noheader'   => true,
182
+			],
183
+			'restore_events'                => [
184
+				'func'       => [$this, '_trash_or_restore_events'],
185
+				'args'       => ['event_status' => 'draft'],
186
+				'capability' => 'ee_delete_events',
187
+				'noheader'   => true,
188
+			],
189
+			'delete_event'                  => [
190
+				'func'       => [$this, '_delete_event'],
191
+				'capability' => 'ee_delete_event',
192
+				'obj_id'     => $EVT_ID,
193
+				'noheader'   => true,
194
+			],
195
+			'delete_events'                 => [
196
+				'func'       => [$this, '_delete_events'],
197
+				'capability' => 'ee_delete_events',
198
+				'noheader'   => true,
199
+			],
200
+			'view_report'                   => [
201
+				'func'       => [$this, '_view_report'],
202
+				'capability' => 'ee_edit_events',
203
+			],
204
+			'default_event_settings'        => [
205
+				'func'       => [$this, '_default_event_settings'],
206
+				'capability' => 'manage_options',
207
+			],
208
+			'update_default_event_settings' => [
209
+				'func'       => [$this, '_update_default_event_settings'],
210
+				'capability' => 'manage_options',
211
+				'noheader'   => true,
212
+			],
213
+			'template_settings'             => [
214
+				'func'       => [$this, '_template_settings'],
215
+				'capability' => 'manage_options',
216
+			],
217
+			// event category tab related
218
+			'add_category'                  => [
219
+				'func'       => [$this, '_category_details'],
220
+				'capability' => 'ee_edit_event_category',
221
+				'args'       => ['view' => 'add'],
222
+			],
223
+			'edit_category'                 => [
224
+				'func'       => [$this, '_category_details'],
225
+				'capability' => 'ee_edit_event_category',
226
+				'args'       => ['view' => 'edit'],
227
+			],
228
+			'delete_categories'             => [
229
+				'func'       => [$this, '_delete_categories'],
230
+				'capability' => 'ee_delete_event_category',
231
+				'noheader'   => true,
232
+			],
233
+			'delete_category'               => [
234
+				'func'       => [$this, '_delete_categories'],
235
+				'capability' => 'ee_delete_event_category',
236
+				'noheader'   => true,
237
+			],
238
+			'insert_category'               => [
239
+				'func'       => [$this, '_insert_or_update_category'],
240
+				'args'       => ['new_category' => true],
241
+				'capability' => 'ee_edit_event_category',
242
+				'noheader'   => true,
243
+			],
244
+			'update_category'               => [
245
+				'func'       => [$this, '_insert_or_update_category'],
246
+				'args'       => ['new_category' => false],
247
+				'capability' => 'ee_edit_event_category',
248
+				'noheader'   => true,
249
+			],
250
+			'category_list'                 => [
251
+				'func'       => [$this, '_category_list_table'],
252
+				'capability' => 'ee_manage_event_categories',
253
+			],
254
+			'preview_deletion'              => [
255
+				'func'       => [$this, 'previewDeletion'],
256
+				'capability' => 'ee_delete_events',
257
+			],
258
+			'confirm_deletion'              => [
259
+				'func'       => [$this, 'confirmDeletion'],
260
+				'capability' => 'ee_delete_events',
261
+				'noheader'   => true,
262
+			],
263
+		];
264
+	}
265
+
266
+
267
+	/**
268
+	 * Set the _page_config property for this admin page group.
269
+	 */
270
+	protected function _set_page_config()
271
+	{
272
+		$post_id            = $this->request->getRequestParam('post', 0, DataType::INT);
273
+		$EVT_CAT_ID         = $this->request->getRequestParam('EVT_CAT_ID', 0, DataType::INT);
274
+		$this->_page_config = [
275
+			'default'                => [
276
+				'nav'           => [
277
+					'label' => esc_html__('Overview', 'event_espresso'),
278
+					'icon'  => 'dashicons-list-view',
279
+					'order' => 10,
280
+				],
281
+				'list_table'    => 'Events_Admin_List_Table',
282
+				'help_tabs'     => [
283
+					'events_overview_help_tab'                       => [
284
+						'title'    => esc_html__('Events Overview', 'event_espresso'),
285
+						'filename' => 'events_overview',
286
+					],
287
+					'events_overview_table_column_headings_help_tab' => [
288
+						'title'    => esc_html__('Events Overview Table Column Headings', 'event_espresso'),
289
+						'filename' => 'events_overview_table_column_headings',
290
+					],
291
+					'events_overview_filters_help_tab'               => [
292
+						'title'    => esc_html__('Events Overview Filters', 'event_espresso'),
293
+						'filename' => 'events_overview_filters',
294
+					],
295
+					'events_overview_view_help_tab'                  => [
296
+						'title'    => esc_html__('Events Overview Views', 'event_espresso'),
297
+						'filename' => 'events_overview_views',
298
+					],
299
+					'events_overview_other_help_tab'                 => [
300
+						'title'    => esc_html__('Events Overview Other', 'event_espresso'),
301
+						'filename' => 'events_overview_other',
302
+					],
303
+				],
304
+				'require_nonce' => false,
305
+			],
306
+			'create_new'             => [
307
+				'nav'           => [
308
+					'label'      => esc_html__('Add New Event', 'event_espresso'),
309
+					'icon'       => 'dashicons-plus-alt',
310
+					'order'      => 15,
311
+					'persistent' => false,
312
+				],
313
+				'metaboxes'     => ['_register_event_editor_meta_boxes'],
314
+				'help_tabs'     => [
315
+					'event_editor_help_tab'                            => [
316
+						'title'    => esc_html__('Event Editor', 'event_espresso'),
317
+						'filename' => 'event_editor',
318
+					],
319
+					'event_editor_title_richtexteditor_help_tab'       => [
320
+						'title'    => esc_html__('Event Title & Rich Text Editor', 'event_espresso'),
321
+						'filename' => 'event_editor_title_richtexteditor',
322
+					],
323
+					'event_editor_venue_details_help_tab'              => [
324
+						'title'    => esc_html__('Event Venue Details', 'event_espresso'),
325
+						'filename' => 'event_editor_venue_details',
326
+					],
327
+					'event_editor_event_datetimes_help_tab'            => [
328
+						'title'    => esc_html__('Event Datetimes', 'event_espresso'),
329
+						'filename' => 'event_editor_event_datetimes',
330
+					],
331
+					'event_editor_event_tickets_help_tab'              => [
332
+						'title'    => esc_html__('Event Tickets', 'event_espresso'),
333
+						'filename' => 'event_editor_event_tickets',
334
+					],
335
+					'event_editor_event_registration_options_help_tab' => [
336
+						'title'    => esc_html__('Event Registration Options', 'event_espresso'),
337
+						'filename' => 'event_editor_event_registration_options',
338
+					],
339
+					'event_editor_tags_categories_help_tab'            => [
340
+						'title'    => esc_html__('Event Tags & Categories', 'event_espresso'),
341
+						'filename' => 'event_editor_tags_categories',
342
+					],
343
+					'event_editor_questions_registrants_help_tab'      => [
344
+						'title'    => esc_html__('Questions for Registrants', 'event_espresso'),
345
+						'filename' => 'event_editor_questions_registrants',
346
+					],
347
+					'event_editor_save_new_event_help_tab'             => [
348
+						'title'    => esc_html__('Save New Event', 'event_espresso'),
349
+						'filename' => 'event_editor_save_new_event',
350
+					],
351
+					'event_editor_other_help_tab'                      => [
352
+						'title'    => esc_html__('Event Other', 'event_espresso'),
353
+						'filename' => 'event_editor_other',
354
+					],
355
+				],
356
+				'qtips'         => ['EE_Event_Editor_Decaf_Tips'],
357
+				'require_nonce' => false,
358
+			],
359
+			'edit'                   => [
360
+				'nav'           => [
361
+					'label'      => esc_html__('Edit Event', 'event_espresso'),
362
+					'icon'       => 'dashicons-edit',
363
+					'order'      => 15,
364
+					'persistent' => false,
365
+					'url'        => $post_id
366
+						? EE_Admin_Page::add_query_args_and_nonce(
367
+							['post' => $post_id, 'action' => 'edit'],
368
+							$this->_current_page_view_url
369
+						)
370
+						: $this->_admin_base_url,
371
+				],
372
+				'metaboxes'     => ['_register_event_editor_meta_boxes'],
373
+				'help_tabs'     => [
374
+					'event_editor_help_tab'                            => [
375
+						'title'    => esc_html__('Event Editor', 'event_espresso'),
376
+						'filename' => 'event_editor',
377
+					],
378
+					'event_editor_title_richtexteditor_help_tab'       => [
379
+						'title'    => esc_html__('Event Title & Rich Text Editor', 'event_espresso'),
380
+						'filename' => 'event_editor_title_richtexteditor',
381
+					],
382
+					'event_editor_venue_details_help_tab'              => [
383
+						'title'    => esc_html__('Event Venue Details', 'event_espresso'),
384
+						'filename' => 'event_editor_venue_details',
385
+					],
386
+					'event_editor_event_datetimes_help_tab'            => [
387
+						'title'    => esc_html__('Event Datetimes', 'event_espresso'),
388
+						'filename' => 'event_editor_event_datetimes',
389
+					],
390
+					'event_editor_event_tickets_help_tab'              => [
391
+						'title'    => esc_html__('Event Tickets', 'event_espresso'),
392
+						'filename' => 'event_editor_event_tickets',
393
+					],
394
+					'event_editor_event_registration_options_help_tab' => [
395
+						'title'    => esc_html__('Event Registration Options', 'event_espresso'),
396
+						'filename' => 'event_editor_event_registration_options',
397
+					],
398
+					'event_editor_tags_categories_help_tab'            => [
399
+						'title'    => esc_html__('Event Tags & Categories', 'event_espresso'),
400
+						'filename' => 'event_editor_tags_categories',
401
+					],
402
+					'event_editor_questions_registrants_help_tab'      => [
403
+						'title'    => esc_html__('Questions for Registrants', 'event_espresso'),
404
+						'filename' => 'event_editor_questions_registrants',
405
+					],
406
+					'event_editor_save_new_event_help_tab'             => [
407
+						'title'    => esc_html__('Save New Event', 'event_espresso'),
408
+						'filename' => 'event_editor_save_new_event',
409
+					],
410
+					'event_editor_other_help_tab'                      => [
411
+						'title'    => esc_html__('Event Other', 'event_espresso'),
412
+						'filename' => 'event_editor_other',
413
+					],
414
+				],
415
+				'require_nonce' => false,
416
+			],
417
+			'default_event_settings' => [
418
+				'nav'           => [
419
+					'label' => esc_html__('Default Settings', 'event_espresso'),
420
+					'icon'  => 'dashicons-admin-generic',
421
+					'order' => 40,
422
+				],
423
+				'metaboxes'     => array_merge(['_publish_post_box'], $this->_default_espresso_metaboxes),
424
+				'labels'        => [
425
+					'publishbox' => esc_html__('Update Settings', 'event_espresso'),
426
+				],
427
+				'help_tabs'     => [
428
+					'default_settings_help_tab'        => [
429
+						'title'    => esc_html__('Default Event Settings', 'event_espresso'),
430
+						'filename' => 'events_default_settings',
431
+					],
432
+					'default_settings_status_help_tab' => [
433
+						'title'    => esc_html__('Default Registration Status', 'event_espresso'),
434
+						'filename' => 'events_default_settings_status',
435
+					],
436
+					'default_maximum_tickets_help_tab' => [
437
+						'title'    => esc_html__('Default Maximum Tickets Per Order', 'event_espresso'),
438
+						'filename' => 'events_default_settings_max_tickets',
439
+					],
440
+				],
441
+				'require_nonce' => false,
442
+			],
443
+			// template settings
444
+			'template_settings'      => [
445
+				'nav'           => [
446
+					'label' => esc_html__('Templates', 'event_espresso'),
447
+					'icon'  => 'dashicons-layout',
448
+					'order' => 30,
449
+				],
450
+				'metaboxes'     => $this->_default_espresso_metaboxes,
451
+				'help_tabs'     => [
452
+					'general_settings_templates_help_tab' => [
453
+						'title'    => esc_html__('Templates', 'event_espresso'),
454
+						'filename' => 'general_settings_templates',
455
+					],
456
+				],
457
+				'require_nonce' => false,
458
+			],
459
+			// event category stuff
460
+			'add_category'           => [
461
+				'nav'           => [
462
+					'label'      => esc_html__('Add Category', 'event_espresso'),
463
+					'icon'       => 'dashicons-plus-alt',
464
+					'order'      => 25,
465
+					'persistent' => false,
466
+				],
467
+				'help_tabs'     => [
468
+					'add_category_help_tab' => [
469
+						'title'    => esc_html__('Add New Event Category', 'event_espresso'),
470
+						'filename' => 'events_add_category',
471
+					],
472
+				],
473
+				'metaboxes'     => ['_publish_post_box'],
474
+				'require_nonce' => false,
475
+			],
476
+			'edit_category'          => [
477
+				'nav'           => [
478
+					'label'      => esc_html__('Edit Category', 'event_espresso'),
479
+					'icon'       => 'dashicons-edit',
480
+					'order'      => 25,
481
+					'persistent' => false,
482
+					'url'        => $EVT_CAT_ID
483
+						? add_query_arg(
484
+							['EVT_CAT_ID' => $EVT_CAT_ID],
485
+							$this->_current_page_view_url
486
+						)
487
+						: $this->_admin_base_url,
488
+				],
489
+				'help_tabs'     => [
490
+					'edit_category_help_tab' => [
491
+						'title'    => esc_html__('Edit Event Category', 'event_espresso'),
492
+						'filename' => 'events_edit_category',
493
+					],
494
+				],
495
+				'metaboxes'     => ['_publish_post_box'],
496
+				'require_nonce' => false,
497
+			],
498
+			'category_list'          => [
499
+				'nav'           => [
500
+					'label' => esc_html__('Categories', 'event_espresso'),
501
+					'icon'  => 'dashicons-networking',
502
+					'order' => 20,
503
+				],
504
+				'list_table'    => 'Event_Categories_Admin_List_Table',
505
+				'help_tabs'     => [
506
+					'events_categories_help_tab'                       => [
507
+						'title'    => esc_html__('Event Categories', 'event_espresso'),
508
+						'filename' => 'events_categories',
509
+					],
510
+					'events_categories_table_column_headings_help_tab' => [
511
+						'title'    => esc_html__('Event Categories Table Column Headings', 'event_espresso'),
512
+						'filename' => 'events_categories_table_column_headings',
513
+					],
514
+					'events_categories_view_help_tab'                  => [
515
+						'title'    => esc_html__('Event Categories Views', 'event_espresso'),
516
+						'filename' => 'events_categories_views',
517
+					],
518
+					'events_categories_other_help_tab'                 => [
519
+						'title'    => esc_html__('Event Categories Other', 'event_espresso'),
520
+						'filename' => 'events_categories_other',
521
+					],
522
+				],
523
+				'metaboxes'     => $this->_default_espresso_metaboxes,
524
+				'require_nonce' => false,
525
+			],
526
+			'preview_deletion'       => [
527
+				'nav'           => [
528
+					'label'      => esc_html__('Preview Deletion', 'event_espresso'),
529
+					'icon'       => 'dashicons-remove',
530
+					'order'      => 15,
531
+					'persistent' => false,
532
+					'url'        => '',
533
+				],
534
+				'require_nonce' => false,
535
+			],
536
+		];
537
+	}
538
+
539
+
540
+	/**
541
+	 * Used to register any global screen options if necessary for every route in this admin page group.
542
+	 */
543
+	protected function _add_screen_options()
544
+	{
545
+	}
546
+
547
+
548
+	/**
549
+	 * Implementing the screen options for the 'default' route.
550
+	 *
551
+	 * @throws InvalidArgumentException
552
+	 * @throws InvalidDataTypeException
553
+	 * @throws InvalidInterfaceException
554
+	 */
555
+	protected function _add_screen_options_default()
556
+	{
557
+		$this->_per_page_screen_option();
558
+	}
559
+
560
+
561
+	/**
562
+	 * Implementing screen options for the category list route.
563
+	 *
564
+	 * @throws InvalidArgumentException
565
+	 * @throws InvalidDataTypeException
566
+	 * @throws InvalidInterfaceException
567
+	 */
568
+	protected function _add_screen_options_category_list()
569
+	{
570
+		$page_title              = $this->_admin_page_title;
571
+		$this->_admin_page_title = esc_html__('Categories', 'event_espresso');
572
+		$this->_per_page_screen_option();
573
+		$this->_admin_page_title = $page_title;
574
+	}
575
+
576
+
577
+	/**
578
+	 * Used to register any global feature pointers for the admin page group.
579
+	 */
580
+	protected function _add_feature_pointers()
581
+	{
582
+	}
583
+
584
+
585
+	/**
586
+	 * Registers and enqueues any global scripts and styles for the entire admin page group.
587
+	 */
588
+	public function load_scripts_styles()
589
+	{
590
+		wp_register_style(
591
+			'events-admin-css',
592
+			EVENTS_ASSETS_URL . 'events-admin-page.css',
593
+			[],
594
+			EVENT_ESPRESSO_VERSION
595
+		);
596
+		wp_register_style(
597
+			'ee-cat-admin',
598
+			EVENTS_ASSETS_URL . 'ee-cat-admin.css',
599
+			[],
600
+			EVENT_ESPRESSO_VERSION
601
+		);
602
+		wp_enqueue_style('events-admin-css');
603
+		wp_enqueue_style('ee-cat-admin');
604
+		// scripts
605
+		wp_register_script(
606
+			'event_editor_js',
607
+			EVENTS_ASSETS_URL . 'event_editor.js',
608
+			['ee_admin_js', 'jquery-ui-slider', 'jquery-ui-timepicker-addon'],
609
+			EVENT_ESPRESSO_VERSION,
610
+			true
611
+		);
612
+	}
613
+
614
+
615
+	/**
616
+	 * Enqueuing scripts and styles specific to this view
617
+	 */
618
+	public function load_scripts_styles_create_new()
619
+	{
620
+		$this->load_scripts_styles_edit();
621
+	}
622
+
623
+
624
+	/**
625
+	 * Enqueuing scripts and styles specific to this view
626
+	 */
627
+	public function load_scripts_styles_edit()
628
+	{
629
+		// styles
630
+		wp_enqueue_style('espresso-ui-theme');
631
+		wp_register_style(
632
+			'event-editor-css',
633
+			EVENTS_ASSETS_URL . 'event-editor.css',
634
+			['ee-admin-css'],
635
+			EVENT_ESPRESSO_VERSION
636
+		);
637
+		wp_enqueue_style('event-editor-css');
638
+		// scripts
639
+		if (! $this->admin_config->useAdvancedEditor()) {
640
+			wp_register_script(
641
+				'event-datetime-metabox',
642
+				EVENTS_ASSETS_URL . 'event-datetime-metabox.js',
643
+				['event_editor_js', 'ee-datepicker'],
644
+				EVENT_ESPRESSO_VERSION
645
+			);
646
+			wp_enqueue_script('event-datetime-metabox');
647
+		}
648
+	}
649
+
650
+
651
+	/**
652
+	 * Populating the _views property for the category list table view.
653
+	 */
654
+	protected function _set_list_table_views_category_list()
655
+	{
656
+		$this->_views = [
657
+			'all' => [
658
+				'slug'        => 'all',
659
+				'label'       => esc_html__('All', 'event_espresso'),
660
+				'count'       => 0,
661
+				'bulk_action' => [
662
+					'delete_categories' => esc_html__('Delete Permanently', 'event_espresso'),
663
+				],
664
+			],
665
+		];
666
+	}
667
+
668
+
669
+	/**
670
+	 * For adding anything that fires on the admin_init hook for any route within this admin page group.
671
+	 */
672
+	public function admin_init()
673
+	{
674
+		EE_Registry::$i18n_js_strings['image_confirm'] = esc_html__(
675
+			'Do you really want to delete this image? Please remember to update your event to complete the removal.',
676
+			'event_espresso'
677
+		);
678
+	}
679
+
680
+
681
+	/**
682
+	 * For adding anything that should be triggered on the admin_notices hook for any route within this admin page
683
+	 * group.
684
+	 */
685
+	public function admin_notices()
686
+	{
687
+	}
688
+
689
+
690
+	/**
691
+	 * For adding anything that should be triggered on the `admin_print_footer_scripts` hook for any route within
692
+	 * this admin page group.
693
+	 */
694
+	public function admin_footer_scripts()
695
+	{
696
+	}
697
+
698
+
699
+	/**
700
+	 * Call this function to verify if an event is public and has tickets for sale.  If it does, then we need to show a
701
+	 * warning (via EE_Error::add_error());
702
+	 *
703
+	 * @param EE_Event|null $event Event object
704
+	 * @param string        $req_type
705
+	 * @return void
706
+	 * @throws EE_Error
707
+	 * @throws ReflectionException
708
+	 */
709
+	public function verify_event_edit(?EE_Base_Class $event = null, string $req_type = '')
710
+	{
711
+		// don't need to do this when processing
712
+		if (! empty($req_type)) {
713
+			return;
714
+		}
715
+		// no event?
716
+		if (! $event instanceof EE_Event) {
717
+			$event = $this->_cpt_model_obj;
718
+		}
719
+		// STILL no event?
720
+		if (! $event instanceof EE_Event) {
721
+			return;
722
+		}
723
+		// don't need to keep calling this
724
+		remove_action(
725
+			'AHEE__EE_Admin_Page_CPT__set_model_object__after_set_object',
726
+			[$this, 'verify_event_edit']
727
+		);
728
+		$orig_status = $event->status();
729
+		// first check if event is active.
730
+		if (
731
+			$orig_status === EEM_Event::cancelled
732
+			|| $orig_status === EEM_Event::postponed
733
+			|| $event->is_expired()
734
+			|| $event->is_inactive()
735
+		) {
736
+			return;
737
+		}
738
+		// made it here so it IS active... next check that any of the tickets are sold.
739
+		if ($event->is_sold_out(true)) {
740
+			if ($orig_status !== EEM_Event::sold_out && $event->status() !== $orig_status) {
741
+				EE_Error::add_attention(
742
+					sprintf(
743
+						esc_html__(
744
+							'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.',
745
+							'event_espresso'
746
+						),
747
+						EEH_Template::pretty_status(EEM_Event::sold_out, false, 'sentence')
748
+					)
749
+				);
750
+			}
751
+			return;
752
+		}
753
+		if ($orig_status === EEM_Event::sold_out) {
754
+			EE_Error::add_attention(
755
+				sprintf(
756
+					esc_html__(
757
+						'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.',
758
+						'event_espresso'
759
+					),
760
+					EEH_Template::pretty_status($event->status(), false, 'sentence')
761
+				)
762
+			);
763
+		}
764
+		// now we need to determine if the event has any tickets on sale.  If not then we dont' show the error
765
+		if (! $event->tickets_on_sale()) {
766
+			return;
767
+		}
768
+		// made it here so show warning
769
+		$this->_edit_event_warning();
770
+	}
771
+
772
+
773
+	/**
774
+	 * This is the text used for when an event is being edited that is public and has tickets for sale.
775
+	 * When needed, hook this into a EE_Error::add_error() notice.
776
+	 *
777
+	 * @access protected
778
+	 * @return void
779
+	 */
780
+	protected function _edit_event_warning()
781
+	{
782
+		// we don't want to add warnings during these requests
783
+		if ($this->request->getRequestParam('action') === 'editpost') {
784
+			return;
785
+		}
786
+		EE_Error::add_attention(
787
+			sprintf(
788
+				esc_html__(
789
+					'Your event is open for registration. Making changes may disrupt any transactions in progress. %sLearn more%s',
790
+					'event_espresso'
791
+				),
792
+				'<a class="espresso-help-tab-lnk ee-help-tab-link">',
793
+				'</a>'
794
+			)
795
+		);
796
+	}
797
+
798
+
799
+	/**
800
+	 * When a user is creating a new event, notify them if they haven't set their timezone.
801
+	 * Otherwise, do the normal logic
802
+	 *
803
+	 * @return void
804
+	 * @throws EE_Error
805
+	 * @throws InvalidArgumentException
806
+	 * @throws InvalidDataTypeException
807
+	 * @throws InvalidInterfaceException
808
+	 * @throws ReflectionException
809
+	 */
810
+	protected function _create_new_cpt_item()
811
+	{
812
+		$has_timezone_string = get_option('timezone_string');
813
+		// only nag them about setting their timezone if it's their first event, and they haven't already done it
814
+		if (! $has_timezone_string && ! EEM_Event::instance()->exists([])) {
815
+			EE_Error::add_attention(
816
+				sprintf(
817
+					esc_html__(
818
+						'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',
819
+						'event_espresso'
820
+					),
821
+					'<br>',
822
+					'<select id="timezone_string" name="timezone_string" aria-describedby="timezone-description">'
823
+					. EEH_DTT_Helper::wp_timezone_choice('', EEH_DTT_Helper::get_user_locale())
824
+					. '</select>',
825
+					'<button class="button button--secondary timezone-submit">',
826
+					'</button><span class="spinner"></span>'
827
+				),
828
+				__FILE__,
829
+				__FUNCTION__,
830
+				__LINE__
831
+			);
832
+		}
833
+		parent::_create_new_cpt_item();
834
+	}
835
+
836
+
837
+	/**
838
+	 * Sets the _views property for the default route in this admin page group.
839
+	 */
840
+	protected function _set_list_table_views_default()
841
+	{
842
+		$this->_views = [
843
+			'all'   => [
844
+				'slug'        => 'all',
845
+				'label'       => esc_html__('View All Events', 'event_espresso'),
846
+				'count'       => 0,
847
+				'bulk_action' => [
848
+					'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
849
+				],
850
+			],
851
+			'draft' => [
852
+				'slug'        => 'draft',
853
+				'label'       => esc_html__('Draft', 'event_espresso'),
854
+				'count'       => 0,
855
+				'bulk_action' => [
856
+					'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
857
+				],
858
+			],
859
+		];
860
+		if (EE_Registry::instance()->CAP->current_user_can('ee_delete_events', 'espresso_events_trash_events')) {
861
+			$this->_views['trash'] = [
862
+				'slug'        => 'trash',
863
+				'label'       => esc_html__('Trash', 'event_espresso'),
864
+				'count'       => 0,
865
+				'bulk_action' => [
866
+					'restore_events' => esc_html__('Restore From Trash', 'event_espresso'),
867
+					'delete_events'  => esc_html__('Delete Permanently', 'event_espresso'),
868
+				],
869
+			];
870
+		}
871
+	}
872
+
873
+
874
+	/**
875
+	 * Provides the legend item array for the default list table view.
876
+	 *
877
+	 * @return array
878
+	 * @throws EE_Error
879
+	 * @throws EE_Error
880
+	 */
881
+	protected function _event_legend_items(): array
882
+	{
883
+		$items    = [
884
+			'view_details'   => [
885
+				'class' => 'dashicons dashicons-visibility',
886
+				'desc'  => esc_html__('View Event', 'event_espresso'),
887
+			],
888
+			'edit_event'     => [
889
+				'class' => 'dashicons dashicons-calendar-alt',
890
+				'desc'  => esc_html__('Edit Event Details', 'event_espresso'),
891
+			],
892
+			'view_attendees' => [
893
+				'class' => 'dashicons dashicons-groups',
894
+				'desc'  => esc_html__('View Registrations for Event', 'event_espresso'),
895
+			],
896
+		];
897
+		$items    = apply_filters('FHEE__Events_Admin_Page___event_legend_items__items', $items);
898
+		$statuses = [
899
+			'sold_out_status'  => [
900
+				'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::sold_out,
901
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::sold_out, false, 'sentence'),
902
+			],
903
+			'active_status'    => [
904
+				'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::active,
905
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::active, false, 'sentence'),
906
+			],
907
+			'upcoming_status'  => [
908
+				'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::upcoming,
909
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::upcoming, false, 'sentence'),
910
+			],
911
+			'postponed_status' => [
912
+				'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::postponed,
913
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::postponed, false, 'sentence'),
914
+			],
915
+			'cancelled_status' => [
916
+				'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::cancelled,
917
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::cancelled, false, 'sentence'),
918
+			],
919
+			'expired_status'   => [
920
+				'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::expired,
921
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::expired, false, 'sentence'),
922
+			],
923
+			'inactive_status'  => [
924
+				'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::inactive,
925
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::inactive, false, 'sentence'),
926
+			],
927
+		];
928
+		$statuses = apply_filters('FHEE__Events_Admin_Page__event_legend_items__statuses', $statuses);
929
+		return array_merge($items, $statuses);
930
+	}
931
+
932
+
933
+	/**
934
+	 * @return EEM_Event
935
+	 * @throws EE_Error
936
+	 * @throws InvalidArgumentException
937
+	 * @throws InvalidDataTypeException
938
+	 * @throws InvalidInterfaceException
939
+	 * @throws ReflectionException
940
+	 */
941
+	private function _event_model(): EEM_Event
942
+	{
943
+		if (! $this->_event_model instanceof EEM_Event) {
944
+			$this->_event_model = EE_Registry::instance()->load_model('Event');
945
+		}
946
+		return $this->_event_model;
947
+	}
948
+
949
+
950
+	/**
951
+	 * Adds extra buttons to the WP CPT permalink field row.
952
+	 * Method is called from parent and is hooked into the wp 'get_sample_permalink_html' filter.
953
+	 *
954
+	 * @param string      $return    the current html
955
+	 * @param int         $id        the post id for the page
956
+	 * @param string|null $new_title What the title is
957
+	 * @param string|null $new_slug  what the slug is
958
+	 * @return string            The new html string for the permalink area
959
+	 * @deprecated 5.0.0.p
960
+	 * @see TicketSelectorShortcodeButton::addButton
961
+	 */
962
+	public function extra_permalink_field_buttons(
963
+		string $return,
964
+		int $id,
965
+		?string $new_title,
966
+		?string $new_slug
967
+	): string {
968
+		return TicketSelectorShortcodeButton::addButton($return, $id, $new_title, $new_slug);
969
+	}
970
+
971
+
972
+	/**
973
+	 * _events_overview_list_table
974
+	 * This contains the logic for showing the events_overview list
975
+	 *
976
+	 * @access protected
977
+	 * @return void
978
+	 * @throws DomainException
979
+	 * @throws EE_Error
980
+	 * @throws InvalidArgumentException
981
+	 * @throws InvalidDataTypeException
982
+	 * @throws InvalidInterfaceException
983
+	 */
984
+	protected function _events_overview_list_table()
985
+	{
986
+		$after_list_table = [];
987
+		$links_html       = EEH_HTML::div('', '', 'ee-admin-section ee-layout-stack');
988
+		$links_html       .= EEH_HTML::h3(esc_html__('Links', 'event_espresso'));
989
+		$links_html       .= EEH_HTML::div(
990
+			EEH_Template::get_button_or_link(
991
+				get_post_type_archive_link('espresso_events'),
992
+				esc_html__('View Event Archive Page', 'event_espresso'),
993
+				'button button--small button--secondary'
994
+			),
995
+			'',
996
+			'ee-admin-button-row ee-admin-button-row--align-start'
997
+		);
998
+		$links_html       .= EEH_HTML::divx();
999
+
1000
+		$after_list_table['view_event_list_button'] = $links_html;
1001
+
1002
+		$after_list_table['legend'] = $this->_display_legend($this->_event_legend_items());
1003
+		$this->_admin_page_title    .= ' ' . $this->get_action_link_or_button(
1004
+			'create_new',
1005
+			'add',
1006
+			[],
1007
+			'add-new-h2'
1008
+		);
1009
+
1010
+		$this->_template_args['after_list_table'] = array_merge(
1011
+			(array) $this->_template_args['after_list_table'],
1012
+			$after_list_table
1013
+		);
1014
+		$this->display_admin_list_table_page_with_no_sidebar();
1015
+	}
1016
+
1017
+
1018
+	/**
1019
+	 * this allows for extra misc actions in the default WP publish box
1020
+	 *
1021
+	 * @return void
1022
+	 * @throws DomainException
1023
+	 * @throws EE_Error
1024
+	 * @throws InvalidArgumentException
1025
+	 * @throws InvalidDataTypeException
1026
+	 * @throws InvalidInterfaceException
1027
+	 * @throws ReflectionException
1028
+	 */
1029
+	public function extra_misc_actions_publish_box()
1030
+	{
1031
+		$this->_generate_publish_box_extra_content();
1032
+	}
1033
+
1034
+
1035
+	/**
1036
+	 * This is hooked into the WordPress do_action('save_post') hook and runs after the custom post type has been
1037
+	 * saved.
1038
+	 * Typically you would use this to save any additional data.
1039
+	 * Keep in mind also that "save_post" runs on EVERY post update to the database.
1040
+	 * ALSO very important.  When a post transitions from scheduled to published,
1041
+	 * the save_post action is fired but you will NOT have any _POST data containing any extra info you may have from
1042
+	 * other meta saves. So MAKE sure that you handle this accordingly.
1043
+	 *
1044
+	 * @access protected
1045
+	 * @abstract
1046
+	 * @param string  $post_id The ID of the cpt that was saved (so you can link relationally)
1047
+	 * @param WP_Post $post    The post object of the cpt that was saved.
1048
+	 * @return void
1049
+	 * @throws EE_Error
1050
+	 * @throws InvalidArgumentException
1051
+	 * @throws InvalidDataTypeException
1052
+	 * @throws InvalidInterfaceException
1053
+	 * @throws ReflectionException
1054
+	 */
1055
+	protected function _insert_update_cpt_item($post_id, $post)
1056
+	{
1057
+		if ($post instanceof WP_Post && $post->post_type !== 'espresso_events') {
1058
+			// get out we're not processing an event save.
1059
+			return;
1060
+		}
1061
+		$event_values = [
1062
+			'EVT_member_only'     => $this->request->getRequestParam('member_only', false, DataType::BOOL),
1063
+			'EVT_allow_overflow'  => $this->request->getRequestParam('EVT_allow_overflow', false, DataType::BOOL),
1064
+			'EVT_timezone_string' => $this->request->getRequestParam('timezone_string'),
1065
+		];
1066
+		// check if the new EDTR reg options meta box is being used, and if so, don't run updates for legacy version
1067
+		if (! $this->admin_config->useAdvancedEditor() || ! $this->feature->allowed('use_reg_options_meta_box')) {
1068
+			$event_values['EVT_display_ticket_selector']     = $this->request->getRequestParam(
1069
+				'display_ticket_selector',
1070
+				false,
1071
+				'bool'
1072
+			);
1073
+			$event_values['EVT_additional_limit']            = min(
1074
+				apply_filters('FHEE__EE_Events_Admin__insert_update_cpt_item__EVT_additional_limit_max', 255),
1075
+				$this->request->getRequestParam(
1076
+					'additional_limit',
1077
+					EEM_Event::get_default_additional_limit(),
1078
+					'int'
1079
+				)
1080
+			);
1081
+			$event_values['EVT_default_registration_status'] = $this->request->getRequestParam(
1082
+				'EVT_default_registration_status',
1083
+				EE_Registry::instance()->CFG->registration->default_STS_ID
1084
+			);
1085
+
1086
+			$event_values['EVT_external_URL'] = $this->request->getRequestParam('externalURL');
1087
+			$event_values['EVT_phone']        = $this->request->getRequestParam('event_phone');
1088
+			$event_values['EVT_display_desc'] = $this->request->getRequestParam('display_desc', false, DataType::BOOL);
1089
+		} elseif ($post instanceof WP_Post) {
1090
+			$event_values['EVT_name'] = $post->post_title;
1091
+			$event_values['EVT_desc'] = $post->post_content;
1092
+		}
1093
+		// update event
1094
+		$success = $this->_event_model()->update_by_ID($event_values, $post_id);
1095
+		// get event_object for other metaboxes...
1096
+		// though it would seem to make sense to just use $this->_event_model()->get_one_by_ID( $post_id )..
1097
+		// i have to setup where conditions to override the filters in the model
1098
+		// that filter out auto-draft and inherit statuses so we GET the inherit id!
1099
+		/** @var EE_Event $event */
1100
+		$event = $this->_event_model()->get_one(
1101
+			[
1102
+				[
1103
+					$this->_event_model()->primary_key_name() => $post_id,
1104
+					'OR'                                      => [
1105
+						'status'   => $post->post_status,
1106
+						// if trying to "Publish" a sold out event, it's status will get switched back to "sold_out" in the db,
1107
+						// but the returned object here has a status of "publish", so use the original post status as well
1108
+						'status*1' => $this->request->getRequestParam('original_post_status'),
1109
+					],
1110
+				],
1111
+			]
1112
+		);
1113
+
1114
+		// the following are default callbacks for event attachment updates
1115
+		// that can be overridden by caffeinated functionality and/or addons.
1116
+		$event_update_callbacks = [];
1117
+		if (! $this->admin_config->useAdvancedEditor()) {
1118
+			$event_update_callbacks['_default_venue_update']   = [$this, '_default_venue_update'];
1119
+			$event_update_callbacks['_default_tickets_update'] = [$this, '_default_tickets_update'];
1120
+		}
1121
+		$event_update_callbacks = apply_filters(
1122
+			'FHEE__Events_Admin_Page___insert_update_cpt_item__event_update_callbacks',
1123
+			$event_update_callbacks
1124
+		);
1125
+
1126
+		$att_success = true;
1127
+		foreach ($event_update_callbacks as $e_callback) {
1128
+			$_success = is_callable($e_callback)
1129
+				? $e_callback($event, $this->request->requestParams())
1130
+				: false;
1131
+			// if ANY of these updates fail then we want the appropriate global error message
1132
+			$att_success = $_success !== false ? $att_success : false;
1133
+		}
1134
+		// any errors?
1135
+		if ($success && $att_success === false) {
1136
+			EE_Error::add_error(
1137
+				esc_html__(
1138
+					'Event Details saved successfully but something went wrong with saving attachments.',
1139
+					'event_espresso'
1140
+				),
1141
+				__FILE__,
1142
+				__FUNCTION__,
1143
+				__LINE__
1144
+			);
1145
+		} elseif ($success === false) {
1146
+			EE_Error::add_error(
1147
+				esc_html__('Event Details did not save successfully.', 'event_espresso'),
1148
+				__FILE__,
1149
+				__FUNCTION__,
1150
+				__LINE__
1151
+			);
1152
+		}
1153
+	}
1154
+
1155
+
1156
+	/**
1157
+	 * @param int $post_id
1158
+	 * @param int $revision_id
1159
+	 * @throws EE_Error
1160
+	 * @throws EE_Error
1161
+	 * @throws ReflectionException
1162
+	 * @see parent::restore_item()
1163
+	 */
1164
+	protected function _restore_cpt_item(int $post_id, int $revision_id)
1165
+	{
1166
+		// copy existing event meta to new post
1167
+		$post_evt = $this->_event_model()->get_one_by_ID($post_id);
1168
+		if ($post_evt instanceof EE_Event) {
1169
+			// meta revision restore
1170
+			$post_evt->restore_revision($revision_id);
1171
+			// related objs restore
1172
+			$post_evt->restore_revision($revision_id, ['Venue', 'Datetime', 'Price']);
1173
+		}
1174
+	}
1175
+
1176
+
1177
+	/**
1178
+	 * Attach the venue to the Event
1179
+	 *
1180
+	 * @param EE_Event $event Event Object to add the venue to
1181
+	 * @param array    $data  The request data from the form
1182
+	 * @return bool           Success or fail.
1183
+	 * @throws EE_Error
1184
+	 * @throws ReflectionException
1185
+	 */
1186
+	protected function _default_venue_update(EE_Event $event, array $data): bool
1187
+	{
1188
+		require_once(EE_MODELS . 'EEM_Venue.model.php');
1189
+		$venue_model = EE_Registry::instance()->load_model('Venue');
1190
+		$venue_id    = ! empty($data['venue_id']) ? $data['venue_id'] : null;
1191
+		// very important.  If we don't have a venue name...
1192
+		// then we'll get out because not necessary to create empty venue
1193
+		if (empty($data['venue_title'])) {
1194
+			return false;
1195
+		}
1196
+		$venue_array = [
1197
+			'VNU_wp_user'         => $event->get('EVT_wp_user'),
1198
+			'VNU_name'            => $data['venue_title'],
1199
+			'VNU_desc'            => ! empty($data['venue_description']) ? $data['venue_description'] : null,
1200
+			'VNU_identifier'      => ! empty($data['venue_identifier']) ? $data['venue_identifier'] : null,
1201
+			'VNU_short_desc'      => ! empty($data['venue_short_description'])
1202
+				? $data['venue_short_description']
1203
+				: null,
1204
+			'VNU_address'         => ! empty($data['address']) ? $data['address'] : null,
1205
+			'VNU_address2'        => ! empty($data['address2']) ? $data['address2'] : null,
1206
+			'VNU_city'            => ! empty($data['city']) ? $data['city'] : null,
1207
+			'STA_ID'              => ! empty($data['state']) ? $data['state'] : null,
1208
+			'CNT_ISO'             => ! empty($data['countries']) ? $data['countries'] : null,
1209
+			'VNU_zip'             => ! empty($data['zip']) ? $data['zip'] : null,
1210
+			'VNU_phone'           => ! empty($data['venue_phone']) ? $data['venue_phone'] : null,
1211
+			'VNU_capacity'        => ! empty($data['venue_capacity']) ? $data['venue_capacity'] : null,
1212
+			'VNU_url'             => ! empty($data['venue_url']) ? $data['venue_url'] : null,
1213
+			'VNU_virtual_phone'   => ! empty($data['virtual_phone']) ? $data['virtual_phone'] : null,
1214
+			'VNU_virtual_url'     => ! empty($data['virtual_url']) ? $data['virtual_url'] : null,
1215
+			'VNU_enable_for_gmap' => isset($data['enable_for_gmap']) ? 1 : 0,
1216
+			'status'              => 'publish',
1217
+		];
1218
+		// if we've got the venue_id then we're just updating the existing venue so let's do that and then get out.
1219
+		if (! empty($venue_id)) {
1220
+			$update_where  = [$venue_model->primary_key_name() => $venue_id];
1221
+			$rows_affected = $venue_model->update($venue_array, [$update_where]);
1222
+			// we've gotta make sure that the venue is always attached to a revision..
1223
+			// add_relation_to should take care of making sure that the relation is already present.
1224
+			$event->_add_relation_to($venue_id, 'Venue');
1225
+			return $rows_affected > 0;
1226
+		}
1227
+		// we insert the venue
1228
+		$venue_id = $venue_model->insert($venue_array);
1229
+		$event->_add_relation_to($venue_id, 'Venue');
1230
+		return ! empty($venue_id);
1231
+		// when we have the ancestor come in it's already been handled by the revision save.
1232
+	}
1233
+
1234
+
1235
+	/**
1236
+	 * Handles saving everything related to Tickets (datetimes, tickets, prices)
1237
+	 *
1238
+	 * @param EE_Event $event The Event object we're attaching data to
1239
+	 * @param array    $data  The request data from the form
1240
+	 * @return array
1241
+	 * @throws EE_Error
1242
+	 * @throws ReflectionException
1243
+	 * @throws Exception
1244
+	 */
1245
+	protected function _default_tickets_update(EE_Event $event, array $data): array
1246
+	{
1247
+		if ($this->admin_config->useAdvancedEditor()) {
1248
+			return [];
1249
+		}
1250
+		$datetime       = null;
1251
+		$saved_tickets  = [];
1252
+		$event_timezone = $event->get_timezone();
1253
+		$date_formats   = ['Y-m-d', 'h:i a'];
1254
+		foreach ($data['edit_event_datetimes'] as $row => $datetime_data) {
1255
+			// trim all values to ensure any excess whitespace is removed.
1256
+			$datetime_data                = array_map('trim', $datetime_data);
1257
+			$datetime_data['DTT_EVT_end'] =
1258
+				isset($datetime_data['DTT_EVT_end']) && ! empty($datetime_data['DTT_EVT_end'])
1259
+					? $datetime_data['DTT_EVT_end']
1260
+					: $datetime_data['DTT_EVT_start'];
1261
+			$datetime_values              = [
1262
+				'DTT_ID'        => ! empty($datetime_data['DTT_ID']) ? $datetime_data['DTT_ID'] : null,
1263
+				'DTT_EVT_start' => $datetime_data['DTT_EVT_start'],
1264
+				'DTT_EVT_end'   => $datetime_data['DTT_EVT_end'],
1265
+				'DTT_reg_limit' => empty($datetime_data['DTT_reg_limit']) ? EE_INF : $datetime_data['DTT_reg_limit'],
1266
+				'DTT_order'     => $row,
1267
+			];
1268
+			// if we have an id then let's get existing object first and then set the new values.
1269
+			//  Otherwise we instantiate a new object for save.
1270
+			if (! empty($datetime_data['DTT_ID'])) {
1271
+				$datetime = EEM_Datetime::instance($event_timezone)->get_one_by_ID($datetime_data['DTT_ID']);
1272
+				if (! $datetime instanceof EE_Datetime) {
1273
+					throw new RuntimeException(
1274
+						sprintf(
1275
+							esc_html__(
1276
+								'Something went wrong! A valid Datetime could not be retrieved from the database using the supplied ID: %1$d',
1277
+								'event_espresso'
1278
+							),
1279
+							$datetime_data['DTT_ID']
1280
+						)
1281
+					);
1282
+				}
1283
+				$datetime->set_date_format($date_formats[0]);
1284
+				$datetime->set_time_format($date_formats[1]);
1285
+				foreach ($datetime_values as $field => $value) {
1286
+					$datetime->set($field, $value);
1287
+				}
1288
+			} else {
1289
+				$datetime = EE_Datetime::new_instance($datetime_values, $event_timezone, $date_formats);
1290
+			}
1291
+			if (! $datetime instanceof EE_Datetime) {
1292
+				throw new RuntimeException(
1293
+					sprintf(
1294
+						esc_html__(
1295
+							'Something went wrong! A valid Datetime could not be generated or retrieved using the supplied data: %1$s',
1296
+							'event_espresso'
1297
+						),
1298
+						print_r($datetime_values, true)
1299
+					)
1300
+				);
1301
+			}
1302
+			// before going any further make sure our dates are setup correctly
1303
+			// so that the end date is always equal or greater than the start date.
1304
+			if ($datetime->get_raw('DTT_EVT_start') > $datetime->get_raw('DTT_EVT_end')) {
1305
+				$datetime->set('DTT_EVT_end', $datetime->get('DTT_EVT_start'));
1306
+				$datetime = EEH_DTT_Helper::date_time_add($datetime, 'DTT_EVT_end', 'days');
1307
+			}
1308
+			$datetime->save();
1309
+			$event->_add_relation_to($datetime, 'Datetime');
1310
+		}
1311
+		// no datetimes get deleted so we don't do any of that logic here.
1312
+		// update tickets next
1313
+		$old_tickets = isset($data['ticket_IDs']) ? explode(',', $data['ticket_IDs']) : [];
1314
+
1315
+		// set up some default start and end dates in case those are not present in the incoming data
1316
+		$default_start_date = new DateTime('now', new DateTimeZone($event->get_timezone()));
1317
+		$default_start_date = $default_start_date->format($date_formats[0] . ' ' . $date_formats[1]);
1318
+		// use the start date of the first datetime for the end date
1319
+		$first_datetime   = $event->first_datetime();
1320
+		$default_end_date = $first_datetime->start_date_and_time($date_formats[0], $date_formats[1]);
1321
+
1322
+		// now process the incoming data
1323
+		foreach ($data['edit_tickets'] as $row => $ticket_data) {
1324
+			$update_prices = false;
1325
+			$ticket_price  = $data['edit_prices'][ $row ][1]['PRC_amount'] ?? 0;
1326
+			// trim inputs to ensure any excess whitespace is removed.
1327
+			$ticket_data   = array_map('trim', $ticket_data);
1328
+			$ticket_values = [
1329
+				'TKT_ID'          => ! empty($ticket_data['TKT_ID']) ? $ticket_data['TKT_ID'] : null,
1330
+				'TTM_ID'          => ! empty($ticket_data['TTM_ID']) ? $ticket_data['TTM_ID'] : 0,
1331
+				'TKT_name'        => ! empty($ticket_data['TKT_name']) ? $ticket_data['TKT_name'] : '',
1332
+				'TKT_description' => ! empty($ticket_data['TKT_description']) ? $ticket_data['TKT_description'] : '',
1333
+				'TKT_start_date'  => ! empty($ticket_data['TKT_start_date'])
1334
+					? $ticket_data['TKT_start_date']
1335
+					: $default_start_date,
1336
+				'TKT_end_date'    => ! empty($ticket_data['TKT_end_date'])
1337
+					? $ticket_data['TKT_end_date']
1338
+					: $default_end_date,
1339
+				'TKT_qty'         => ! empty($ticket_data['TKT_qty'])
1340
+									 || (isset($ticket_data['TKT_qty']) && (int) $ticket_data['TKT_qty'] === 0)
1341
+					? $ticket_data['TKT_qty']
1342
+					: EE_INF,
1343
+				'TKT_uses'        => ! empty($ticket_data['TKT_uses'])
1344
+									 || (isset($ticket_data['TKT_uses']) && (int) $ticket_data['TKT_uses'] === 0)
1345
+					? $ticket_data['TKT_uses']
1346
+					: EE_INF,
1347
+				'TKT_min'         => ! empty($ticket_data['TKT_min']) ? $ticket_data['TKT_min'] : 0,
1348
+				'TKT_max'         => ! empty($ticket_data['TKT_max']) ? $ticket_data['TKT_max'] : EE_INF,
1349
+				'TKT_order'       => $ticket_data['TKT_order'] ?? $row,
1350
+				'TKT_price'       => $ticket_price,
1351
+				'TKT_row'         => $row,
1352
+			];
1353
+			// if this is a default ticket, then we need to set the TKT_ID to 0 and update accordingly,
1354
+			// which means in turn that the prices will become new prices as well.
1355
+			if (isset($ticket_data['TKT_is_default']) && $ticket_data['TKT_is_default']) {
1356
+				$ticket_values['TKT_ID']         = 0;
1357
+				$ticket_values['TKT_is_default'] = 0;
1358
+				$update_prices                   = true;
1359
+			}
1360
+			// if we have a TKT_ID then we need to get that existing TKT_obj and update it
1361
+			// we actually do our saves ahead of adding any relations because its entirely possible that this
1362
+			// ticket didn't get removed or added to any datetime in the session but DID have it's items modified.
1363
+			// keep in mind that if the ticket has been sold (and we have changed pricing information),
1364
+			// then we won't be updating the tkt but instead a new tkt will be created and the old one archived.
1365
+			if (! empty($ticket_data['TKT_ID'])) {
1366
+				$existing_ticket = EEM_Ticket::instance($event_timezone)->get_one_by_ID($ticket_data['TKT_ID']);
1367
+				if (! $existing_ticket instanceof EE_Ticket) {
1368
+					throw new RuntimeException(
1369
+						sprintf(
1370
+							esc_html__(
1371
+								'Something went wrong! A valid Ticket could not be retrieved from the database using the supplied ID: %1$d',
1372
+								'event_espresso'
1373
+							),
1374
+							$ticket_data['TKT_ID']
1375
+						)
1376
+					);
1377
+				}
1378
+				$ticket_sold = $existing_ticket->count_related(
1379
+					'Registration',
1380
+					[
1381
+							[
1382
+								'STS_ID' => [
1383
+									'NOT IN',
1384
+									[EEM_Registration::status_id_incomplete],
1385
+								],
1386
+							],
1387
+						]
1388
+				) > 0;
1389
+				// let's just check the total price for the existing ticket and determine if it matches the new total price.
1390
+				// if they are different then we create a new ticket (if $ticket_sold)
1391
+				// if they aren't different then we go ahead and modify existing ticket.
1392
+				$create_new_ticket = $ticket_sold
1393
+									 && $ticket_price !== $existing_ticket->price()
1394
+									 && ! $existing_ticket->deleted();
1395
+				$existing_ticket->set_date_format($date_formats[0]);
1396
+				$existing_ticket->set_time_format($date_formats[1]);
1397
+				// set new values
1398
+				foreach ($ticket_values as $field => $value) {
1399
+					if ($field == 'TKT_qty') {
1400
+						$existing_ticket->set_qty($value);
1401
+					} elseif ($field == 'TKT_price') {
1402
+						$existing_ticket->set('TKT_price', $ticket_price);
1403
+					} else {
1404
+						$existing_ticket->set($field, $value);
1405
+					}
1406
+				}
1407
+				$ticket = $existing_ticket;
1408
+				// if $create_new_ticket is false then we can safely update the existing ticket.
1409
+				//  Otherwise we have to create a new ticket.
1410
+				if ($create_new_ticket) {
1411
+					// archive the old ticket first
1412
+					$existing_ticket->set('TKT_deleted', 1);
1413
+					$existing_ticket->save();
1414
+					// make sure this ticket is still recorded in our $saved_tickets
1415
+					// so we don't run it through the regular trash routine.
1416
+					$saved_tickets[ $existing_ticket->ID() ] = $existing_ticket;
1417
+					// create new ticket that's a copy of the existing except,
1418
+					// (a new id of course and not archived) AND has the new TKT_price associated with it.
1419
+					$new_ticket = clone $existing_ticket;
1420
+					$new_ticket->set('TKT_ID', 0);
1421
+					$new_ticket->set('TKT_deleted', 0);
1422
+					$new_ticket->set('TKT_sold', 0);
1423
+					// now we need to make sure that $new prices are created as well and attached to new ticket.
1424
+					$update_prices = true;
1425
+					$ticket        = $new_ticket;
1426
+				}
1427
+			} else {
1428
+				// no TKT_id so a new ticket
1429
+				$ticket_values['TKT_price'] = $ticket_price;
1430
+				$ticket                     = EE_Ticket::new_instance($ticket_values, $event_timezone, $date_formats);
1431
+				$update_prices              = true;
1432
+			}
1433
+			if (! $ticket instanceof EE_Ticket) {
1434
+				throw new RuntimeException(
1435
+					sprintf(
1436
+						esc_html__(
1437
+							'Something went wrong! A valid Ticket could not be generated or retrieved using the supplied data: %1$s',
1438
+							'event_espresso'
1439
+						),
1440
+						print_r($ticket_values, true)
1441
+					)
1442
+				);
1443
+			}
1444
+			// cap ticket qty by datetime reg limits
1445
+			$ticket->set_qty(min($ticket->qty(), $ticket->qty('reg_limit')));
1446
+			// update ticket.
1447
+			$ticket->save();
1448
+			// before going any further make sure our dates are setup correctly
1449
+			// so that the end date is always equal or greater than the start date.
1450
+			if ($ticket->get_raw('TKT_start_date') > $ticket->get_raw('TKT_end_date')) {
1451
+				$ticket->set('TKT_end_date', $ticket->get('TKT_start_date'));
1452
+				$ticket = EEH_DTT_Helper::date_time_add($ticket, 'TKT_end_date', 'days');
1453
+				$ticket->save();
1454
+			}
1455
+			// initially let's add the ticket to the datetime
1456
+			$datetime->_add_relation_to($ticket, 'Ticket');
1457
+			$saved_tickets[ $ticket->ID() ] = $ticket;
1458
+			// add prices to ticket
1459
+			$prices_data = isset($data['edit_prices'][ $row ]) && is_array($data['edit_prices'][ $row ])
1460
+				? $data['edit_prices'][ $row ]
1461
+				: [];
1462
+			$this->_add_prices_to_ticket($prices_data, $ticket, $update_prices);
1463
+		}
1464
+		// however now we need to handle permanently deleting tickets via the ui.
1465
+		// Keep in mind that the ui does not allow deleting/archiving tickets that have ticket sold.
1466
+		// However, it does allow for deleting tickets that have no tickets sold,
1467
+		// in which case we want to get rid of permanently because there is no need to save in db.
1468
+		$old_tickets     = isset($old_tickets[0]) && $old_tickets[0] === '' ? [] : $old_tickets;
1469
+		$tickets_removed = array_diff($old_tickets, array_keys($saved_tickets));
1470
+		foreach ($tickets_removed as $id) {
1471
+			$id = absint($id);
1472
+			// get the ticket for this id
1473
+			$ticket_to_remove = EEM_Ticket::instance()->get_one_by_ID($id);
1474
+			if (! $ticket_to_remove instanceof EE_Ticket) {
1475
+				continue;
1476
+			}
1477
+			// need to get all the related datetimes on this ticket and remove from every single one of them
1478
+			// (remember this process can ONLY kick off if there are NO tickets sold)
1479
+			$related_datetimes = $ticket_to_remove->get_many_related('Datetime');
1480
+			foreach ($related_datetimes as $related_datetime) {
1481
+				$ticket_to_remove->_remove_relation_to($related_datetime, 'Datetime');
1482
+			}
1483
+			// need to do the same for prices (except these prices can also be deleted because again,
1484
+			// tickets can only be trashed if they don't have any TKTs sold (otherwise they are just archived))
1485
+			$ticket_to_remove->delete_related_permanently('Price');
1486
+			// finally let's delete this ticket
1487
+			// (which should not be blocked at this point b/c we've removed all our relationships)
1488
+			$ticket_to_remove->delete_permanently();
1489
+		}
1490
+		return [$datetime, $saved_tickets];
1491
+	}
1492
+
1493
+
1494
+	/**
1495
+	 * This attaches a list of given prices to a ticket.
1496
+	 * Note we dont' have to worry about ever removing relationships (or archiving prices)
1497
+	 * because if there is a change in price information on a ticket, a new ticket is created anyways
1498
+	 * so the archived ticket will retain the old price info and prices are automatically "archived" via the ticket.
1499
+	 *
1500
+	 * @access  private
1501
+	 * @param array     $prices_data Array of prices from the form.
1502
+	 * @param EE_Ticket $ticket      EE_Ticket object that prices are being attached to.
1503
+	 * @param bool      $new_prices  Whether attach existing incoming prices or create new ones.
1504
+	 * @return  void
1505
+	 * @throws EE_Error
1506
+	 * @throws ReflectionException
1507
+	 */
1508
+	private function _add_prices_to_ticket(array $prices_data, EE_Ticket $ticket, bool $new_prices = false)
1509
+	{
1510
+		$timezone = $ticket->get_timezone();
1511
+		foreach ($prices_data as $row => $price_data) {
1512
+			$price_values = [
1513
+				'PRC_ID'         => ! empty($price_data['PRC_ID']) ? $price_data['PRC_ID'] : null,
1514
+				'PRT_ID'         => ! empty($price_data['PRT_ID']) ? $price_data['PRT_ID'] : null,
1515
+				'PRC_amount'     => ! empty($price_data['PRC_amount']) ? $price_data['PRC_amount'] : 0,
1516
+				'PRC_name'       => ! empty($price_data['PRC_name']) ? $price_data['PRC_name'] : '',
1517
+				'PRC_desc'       => ! empty($price_data['PRC_desc']) ? $price_data['PRC_desc'] : '',
1518
+				'PRC_is_default' => 0, // make sure prices are NOT set as default from this context
1519
+				'PRC_order'      => $row,
1520
+			];
1521
+			if ($new_prices || empty($price_values['PRC_ID'])) {
1522
+				$price_values['PRC_ID'] = 0;
1523
+				$price                  = EE_Price::new_instance($price_values, $timezone);
1524
+			} else {
1525
+				$price = EEM_Price::instance($timezone)->get_one_by_ID($price_data['PRC_ID']);
1526
+				// update this price with new values
1527
+				foreach ($price_values as $field => $new_price) {
1528
+					$price->set($field, $new_price);
1529
+				}
1530
+			}
1531
+			if (! $price instanceof EE_Price) {
1532
+				throw new RuntimeException(
1533
+					sprintf(
1534
+						esc_html__(
1535
+							'Something went wrong! A valid Price could not be generated or retrieved using the supplied data: %1$s',
1536
+							'event_espresso'
1537
+						),
1538
+						print_r($price_values, true)
1539
+					)
1540
+				);
1541
+			}
1542
+			$price->save();
1543
+			$ticket->_add_relation_to($price, 'Price');
1544
+		}
1545
+	}
1546
+
1547
+
1548
+	/**
1549
+	 * Add in our autosave ajax handlers
1550
+	 *
1551
+	 */
1552
+	protected function _ee_autosave_create_new()
1553
+	{
1554
+	}
1555
+
1556
+
1557
+	/**
1558
+	 * More autosave handlers.
1559
+	 */
1560
+	protected function _ee_autosave_edit()
1561
+	{
1562
+	}
1563
+
1564
+
1565
+	/**
1566
+	 * @throws EE_Error
1567
+	 * @throws ReflectionException
1568
+	 */
1569
+	private function _generate_publish_box_extra_content()
1570
+	{
1571
+		// load formatter helper
1572
+		// args for getting related registrations
1573
+		$approved_query_args        = [
1574
+			[
1575
+				'REG_deleted' => 0,
1576
+				'STS_ID'      => EEM_Registration::status_id_approved,
1577
+			],
1578
+		];
1579
+		$not_approved_query_args    = [
1580
+			[
1581
+				'REG_deleted' => 0,
1582
+				'STS_ID'      => EEM_Registration::status_id_not_approved,
1583
+			],
1584
+		];
1585
+		$pending_payment_query_args = [
1586
+			[
1587
+				'REG_deleted' => 0,
1588
+				'STS_ID'      => EEM_Registration::status_id_pending_payment,
1589
+			],
1590
+		];
1591
+		// publish box
1592
+		$publish_box_extra_args = [
1593
+			'view_approved_reg_url'        => add_query_arg(
1594
+				[
1595
+					'action'      => 'default',
1596
+					'event_id'    => $this->_cpt_model_obj->ID(),
1597
+					'_reg_status' => EEM_Registration::status_id_approved,
1598
+					'use_filters' => true,
1599
+				],
1600
+				REG_ADMIN_URL
1601
+			),
1602
+			'view_not_approved_reg_url'    => add_query_arg(
1603
+				[
1604
+					'action'      => 'default',
1605
+					'event_id'    => $this->_cpt_model_obj->ID(),
1606
+					'_reg_status' => EEM_Registration::status_id_not_approved,
1607
+					'use_filters' => true,
1608
+				],
1609
+				REG_ADMIN_URL
1610
+			),
1611
+			'view_pending_payment_reg_url' => add_query_arg(
1612
+				[
1613
+					'action'      => 'default',
1614
+					'event_id'    => $this->_cpt_model_obj->ID(),
1615
+					'_reg_status' => EEM_Registration::status_id_pending_payment,
1616
+					'use_filters' => true,
1617
+				],
1618
+				REG_ADMIN_URL
1619
+			),
1620
+			'approved_regs'                => $this->_cpt_model_obj->count_related(
1621
+				'Registration',
1622
+				$approved_query_args
1623
+			),
1624
+			'not_approved_regs'            => $this->_cpt_model_obj->count_related(
1625
+				'Registration',
1626
+				$not_approved_query_args
1627
+			),
1628
+			'pending_payment_regs'         => $this->_cpt_model_obj->count_related(
1629
+				'Registration',
1630
+				$pending_payment_query_args
1631
+			),
1632
+			'misc_pub_section_class'       => apply_filters(
1633
+				'FHEE_Events_Admin_Page___generate_publish_box_extra_content__misc_pub_section_class',
1634
+				'misc-pub-section'
1635
+			),
1636
+		];
1637
+		ob_start();
1638
+		do_action(
1639
+			'AHEE__Events_Admin_Page___generate_publish_box_extra_content__event_editor_overview_add',
1640
+			$this->_cpt_model_obj
1641
+		);
1642
+		$publish_box_extra_args['event_editor_overview_add'] = ob_get_clean();
1643
+		// load template
1644
+		EEH_Template::display_template(
1645
+			EVENTS_TEMPLATE_PATH . 'event_publish_box_extras.template.php',
1646
+			$publish_box_extra_args
1647
+		);
1648
+	}
1649
+
1650
+
1651
+	/**
1652
+	 * @return EE_Event
1653
+	 */
1654
+	public function get_event_object()
1655
+	{
1656
+		return $this->_cpt_model_obj;
1657
+	}
1658
+
1659
+
1660
+
1661
+
1662
+	/** METABOXES * */
1663
+	/**
1664
+	 * _register_event_editor_meta_boxes
1665
+	 * add all metaboxes related to the event_editor
1666
+	 *
1667
+	 * @return void
1668
+	 * @throws EE_Error
1669
+	 * @throws ReflectionException
1670
+	 */
1671
+	protected function _register_event_editor_meta_boxes()
1672
+	{
1673
+		$this->verify_cpt_object();
1674
+		$use_advanced_editor = $this->admin_config->useAdvancedEditor();
1675
+		// check if the new EDTR reg options meta box is being used, and if so, don't load the legacy version
1676
+		if (! $use_advanced_editor || ! $this->feature->allowed('use_reg_options_meta_box')) {
1677
+			$this->addMetaBox(
1678
+				'espresso_event_editor_event_options',
1679
+				esc_html__('Event Registration Options', 'event_espresso'),
1680
+				[$this, 'registration_options_meta_box'],
1681
+				$this->page_slug,
1682
+				'side'
1683
+			);
1684
+		}
1685
+		if (! $use_advanced_editor) {
1686
+			$this->addMetaBox(
1687
+				'espresso_event_editor_tickets',
1688
+				esc_html__('Event Datetime & Ticket', 'event_espresso'),
1689
+				[$this, 'ticket_metabox'],
1690
+				$this->page_slug,
1691
+				'normal',
1692
+				'high'
1693
+			);
1694
+		} elseif ($this->feature->allowed('use_reg_options_meta_box')) {
1695
+			add_action(
1696
+				'add_meta_boxes_espresso_events',
1697
+				function () {
1698
+					global $current_screen;
1699
+					remove_meta_box('authordiv', $current_screen, 'normal');
1700
+				},
1701
+				99
1702
+			);
1703
+		}
1704
+		// NOTE: if you're looking for other metaboxes in here,
1705
+		// where a metabox has a related management page in the admin
1706
+		// you will find it setup in the related management page's "_Hooks" file.
1707
+		// i.e. messages metabox is found in "espresso_events_Messages_Hooks.class.php".
1708
+	}
1709
+
1710
+
1711
+	/**
1712
+	 * @throws DomainException
1713
+	 * @throws EE_Error
1714
+	 * @throws ReflectionException
1715
+	 */
1716
+	public function ticket_metabox()
1717
+	{
1718
+		$existing_datetime_ids = $existing_ticket_ids = [];
1719
+		// defaults for template args
1720
+		$template_args = [
1721
+			'ticket_rows'       => '',
1722
+			'total_ticket_rows' => 1,
1723
+			'trash_icon'        => 'dashicons dashicons-lock',
1724
+			'disabled'          => '',
1725
+		];
1726
+		$event_id      = is_object($this->_cpt_model_obj) ? $this->_cpt_model_obj->ID() : null;
1727
+		/**
1728
+		 * 1. Start with retrieving Datetimes
1729
+		 * 2. Fore each datetime get related tickets
1730
+		 * 3. For each ticket get related prices
1731
+		 */
1732
+		/** @var EEM_Datetime $datetime_model */
1733
+		$datetime_model = EE_Registry::instance()->load_model('Datetime');
1734
+		/** @var EEM_Ticket $datetime_model */
1735
+		$ticket_model = EE_Registry::instance()->load_model('Ticket');
1736
+		$times        = $datetime_model->get_all_event_dates($event_id);
1737
+		/** @type EE_Datetime $first_datetime */
1738
+		$first_datetime = reset($times);
1739
+		// do we get related tickets?
1740
+		if (
1741
+			$first_datetime instanceof EE_Datetime
1742
+			&& $first_datetime->ID() !== 0
1743
+		) {
1744
+			$existing_datetime_ids[] = $first_datetime->get('DTT_ID');
1745
+			$template_args['time']   = $first_datetime;
1746
+			$related_tickets         = $first_datetime->tickets(
1747
+				[
1748
+					['OR' => ['TKT_deleted' => 1, 'TKT_deleted*' => 0]],
1749
+					'default_where_conditions' => 'none',
1750
+				]
1751
+			);
1752
+			if (! empty($related_tickets)) {
1753
+				$template_args['total_ticket_rows'] = count($related_tickets);
1754
+				$row                                = 0;
1755
+				foreach ($related_tickets as $ticket) {
1756
+					$existing_ticket_ids[]        = $ticket->get('TKT_ID');
1757
+					$template_args['ticket_rows'] .= $this->_get_ticket_row($ticket, false, $row);
1758
+					$row++;
1759
+				}
1760
+			} else {
1761
+				$template_args['total_ticket_rows'] = 1;
1762
+				/** @type EE_Ticket $ticket */
1763
+				$ticket                       = $ticket_model->create_default_object();
1764
+				$template_args['ticket_rows'] .= $this->_get_ticket_row($ticket);
1765
+			}
1766
+		} else {
1767
+			$template_args['time'] = $times[0];
1768
+			/** @type EE_Ticket[] $tickets */
1769
+			$tickets                      = $ticket_model->get_all_default_tickets();
1770
+			$template_args['ticket_rows'] .= $this->_get_ticket_row($tickets[1]);
1771
+			// NOTE: we're just sending the first default row
1772
+			// (decaf can't manage default tickets so this should be sufficient);
1773
+		}
1774
+		$template_args['event_datetime_help_link'] = $this->_get_help_tab_link(
1775
+			'event_editor_event_datetimes_help_tab'
1776
+		);
1777
+		$template_args['ticket_options_help_link'] = $this->_get_help_tab_link('ticket_options_info');
1778
+		$template_args['existing_datetime_ids']    = implode(',', $existing_datetime_ids);
1779
+		$template_args['existing_ticket_ids']      = implode(',', $existing_ticket_ids);
1780
+		$template_args['ticket_js_structure']      = $this->_get_ticket_row(
1781
+			$ticket_model->create_default_object(),
1782
+			true
1783
+		);
1784
+		$template                                  = apply_filters(
1785
+			'FHEE__Events_Admin_Page__ticket_metabox__template',
1786
+			EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_main.template.php'
1787
+		);
1788
+		EEH_Template::display_template($template, $template_args);
1789
+	}
1790
+
1791
+
1792
+	/**
1793
+	 * Setup an individual ticket form for the decaf event editor page
1794
+	 *
1795
+	 * @access private
1796
+	 * @param EE_Ticket $ticket   the ticket object
1797
+	 * @param boolean   $skeleton whether we're generating a skeleton for js manipulation
1798
+	 * @param int       $row
1799
+	 * @return string generated html for the ticket row.
1800
+	 * @throws EE_Error
1801
+	 * @throws ReflectionException
1802
+	 */
1803
+	private function _get_ticket_row(EE_Ticket $ticket, bool $skeleton = false, int $row = 0): string
1804
+	{
1805
+		$template_args = [
1806
+			'tkt_status_class'    => ' tkt-status-' . $ticket->ticket_status(),
1807
+			'tkt_archive_class'   => $ticket->ticket_status() === EE_Ticket::archived && ! $skeleton ? ' tkt-archived'
1808
+				: '',
1809
+			'ticketrow'           => $skeleton ? 'TICKETNUM' : $row,
1810
+			'TKT_ID'              => $ticket->get('TKT_ID'),
1811
+			'TKT_name'            => $ticket->get('TKT_name'),
1812
+			'TKT_start_date'      => $skeleton ? '' : $ticket->get_date('TKT_start_date', 'Y-m-d h:i a'),
1813
+			'TKT_end_date'        => $skeleton ? '' : $ticket->get_date('TKT_end_date', 'Y-m-d h:i a'),
1814
+			'TKT_is_default'      => $ticket->get('TKT_is_default'),
1815
+			'TKT_qty'             => $ticket->get_pretty('TKT_qty', 'input'),
1816
+			'edit_ticketrow_name' => $skeleton ? 'TICKETNAMEATTR' : 'edit_tickets',
1817
+			'TKT_sold'            => $skeleton ? 0 : $ticket->get('TKT_sold'),
1818
+			'trash_icon'          => ($skeleton || (! empty($ticket) && ! $ticket->get('TKT_deleted')))
1819
+									 && (! empty($ticket) && $ticket->get('TKT_sold') === 0)
1820
+				? 'trash-icon dashicons dashicons-post-trash clickable' : 'dashicons dashicons-lock',
1821
+			'disabled'            => $skeleton || (! empty($ticket) && ! $ticket->get('TKT_deleted')) ? ''
1822
+				: ' disabled=disabled',
1823
+		];
1824
+		$price         = $ticket->ID() !== 0
1825
+			? $ticket->get_first_related('Price', ['default_where_conditions' => 'none'])
1826
+			: null;
1827
+		$price         = $price instanceof EE_Price
1828
+			? $price
1829
+			: EEM_Price::instance()->create_default_object();
1830
+		$price_args    = [
1831
+			'price_currency_symbol' => EE_Registry::instance()->CFG->currency->sign,
1832
+			'PRC_amount'            => $price->get('PRC_amount'),
1833
+			'PRT_ID'                => $price->get('PRT_ID'),
1834
+			'PRC_ID'                => $price->get('PRC_ID'),
1835
+			'PRC_is_default'        => $price->get('PRC_is_default'),
1836
+		];
1837
+		// make sure we have default start and end dates if skeleton
1838
+		// handle rows that should NOT be empty
1839
+		if (empty($template_args['TKT_start_date'])) {
1840
+			// if empty then the start date will be now.
1841
+			$template_args['TKT_start_date'] = date('Y-m-d h:i a', current_time('timestamp'));
1842
+		}
1843
+		if (empty($template_args['TKT_end_date'])) {
1844
+			// get the earliest datetime (if present);
1845
+			$earliest_datetime             = $this->_cpt_model_obj->ID() > 0
1846
+				? $this->_cpt_model_obj->get_first_related(
1847
+					'Datetime',
1848
+					['order_by' => ['DTT_EVT_start' => 'ASC']]
1849
+				)
1850
+				: null;
1851
+			$template_args['TKT_end_date'] = $earliest_datetime instanceof EE_Datetime
1852
+				? $earliest_datetime->get_datetime('DTT_EVT_start', 'Y-m-d', 'h:i a')
1853
+				: date('Y-m-d h:i a', mktime(0, 0, 0, date('m'), date('d') + 7, date('Y')));
1854
+		}
1855
+		$template_args = array_merge($template_args, $price_args);
1856
+		$template      = apply_filters(
1857
+			'FHEE__Events_Admin_Page__get_ticket_row__template',
1858
+			EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_ticket_row.template.php',
1859
+			$ticket
1860
+		);
1861
+		return EEH_Template::display_template($template, $template_args, true);
1862
+	}
1863
+
1864
+
1865
+	/**
1866
+	 * @throws EE_Error
1867
+	 * @throws ReflectionException
1868
+	 */
1869
+	public function registration_options_meta_box()
1870
+	{
1871
+		$yes_no_values             = [
1872
+			['id' => true, 'text' => esc_html__('Yes', 'event_espresso')],
1873
+			['id' => false, 'text' => esc_html__('No', 'event_espresso')],
1874
+		];
1875
+		$default_reg_status_values = EEM_Registration::reg_status_array(
1876
+			[
1877
+				EEM_Registration::status_id_cancelled,
1878
+				EEM_Registration::status_id_declined,
1879
+				EEM_Registration::status_id_incomplete,
1880
+			],
1881
+			true
1882
+		);
1883
+		// $template_args['is_active_select'] = EEH_Form_Fields::select_input('is_active', $yes_no_values, $this->_cpt_model_obj->is_active());
1884
+		$template_args['_event']                          = $this->_cpt_model_obj;
1885
+		$template_args['event']                           = $this->_cpt_model_obj;
1886
+		$template_args['active_status']                   = $this->_cpt_model_obj->pretty_active_status(false);
1887
+		$template_args['additional_limit']                = $this->_cpt_model_obj->additional_limit();
1888
+		$template_args['default_registration_status']     = EEH_Form_Fields::select_input(
1889
+			'default_reg_status',
1890
+			$default_reg_status_values,
1891
+			$this->_cpt_model_obj->default_registration_status()
1892
+		);
1893
+		$template_args['display_description']             = EEH_Form_Fields::select_input(
1894
+			'display_desc',
1895
+			$yes_no_values,
1896
+			$this->_cpt_model_obj->display_description()
1897
+		);
1898
+		$template_args['display_ticket_selector']         = EEH_Form_Fields::select_input(
1899
+			'display_ticket_selector',
1900
+			$yes_no_values,
1901
+			$this->_cpt_model_obj->display_ticket_selector(),
1902
+			'',
1903
+			'',
1904
+			false
1905
+		);
1906
+		$template_args['additional_registration_options'] = apply_filters(
1907
+			'FHEE__Events_Admin_Page__registration_options_meta_box__additional_registration_options',
1908
+			'',
1909
+			$template_args,
1910
+			$yes_no_values,
1911
+			$default_reg_status_values
1912
+		);
1913
+		EEH_Template::display_template(
1914
+			EVENTS_TEMPLATE_PATH . 'event_registration_options.template.php',
1915
+			$template_args
1916
+		);
1917
+	}
1918
+
1919
+
1920
+	/**
1921
+	 * _get_events()
1922
+	 * This method simply returns all the events (for the given _view and paging)
1923
+	 *
1924
+	 * @access public
1925
+	 * @param int  $per_page     count of items per page (20 default);
1926
+	 * @param int  $current_page what is the current page being viewed.
1927
+	 * @param bool $count        if TRUE then we just return a count of ALL events matching the given _view.
1928
+	 *                           If FALSE then we return an array of event objects
1929
+	 *                           that match the given _view and paging parameters.
1930
+	 * @return array|int         an array of event objects or a count of them.
1931
+	 * @throws Exception
1932
+	 */
1933
+	public function get_events(int $per_page = 10, int $current_page = 1, bool $count = false)
1934
+	{
1935
+		$EEM_Event   = $this->_event_model();
1936
+		$offset      = ($current_page - 1) * $per_page;
1937
+		$limit       = $count ? null : $offset . ',' . $per_page;
1938
+		$orderby     = $this->request->getRequestParam('orderby', 'EVT_ID');
1939
+		$order       = $this->request->getRequestParam('order', 'DESC');
1940
+		$month_range = $this->request->getRequestParam('month_range');
1941
+		if ($month_range) {
1942
+			$pieces = explode(' ', $month_range, 3);
1943
+			// simulate the FIRST day of the month, that fixes issues for months like February
1944
+			// where PHP doesn't know what to assume for date.
1945
+			// @see https://events.codebasehq.com/projects/event-espresso/tickets/10437
1946
+			$month_r = ! empty($pieces[0]) ? date('m', EEH_DTT_Helper::first_of_month_timestamp($pieces[0])) : '';
1947
+			$year_r  = ! empty($pieces[1]) ? $pieces[1] : '';
1948
+		}
1949
+		$where  = [];
1950
+		$status = $this->request->getRequestParam('status');
1951
+		// determine what post_status our condition will have for the query.
1952
+		switch ($status) {
1953
+			case 'month':
1954
+			case 'today':
1955
+			case null:
1956
+			case 'all':
1957
+				break;
1958
+			case 'draft':
1959
+				$where['status'] = ['IN', ['draft', 'auto-draft']];
1960
+				break;
1961
+			default:
1962
+				$where['status'] = $status;
1963
+		}
1964
+		// categories? The default for all categories is -1
1965
+		$category = $this->request->getRequestParam('EVT_CAT', -1, DataType::INT);
1966
+		if ($category !== -1) {
1967
+			$where['Term_Taxonomy.taxonomy'] = EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY;
1968
+			$where['Term_Taxonomy.term_id']  = $category;
1969
+		}
1970
+		// date where conditions
1971
+		$start_formats = EEM_Datetime::instance()->get_formats_for('DTT_EVT_start');
1972
+		if ($month_range) {
1973
+			$DateTime = new DateTime(
1974
+				$year_r . '-' . $month_r . '-01 00:00:00',
1975
+				new DateTimeZone('UTC')
1976
+			);
1977
+			$start    = $DateTime->getTimestamp();
1978
+			// set the datetime to be the end of the month
1979
+			$DateTime->setDate(
1980
+				$year_r,
1981
+				$month_r,
1982
+				$DateTime->format('t')
1983
+			)->setTime(23, 59, 59);
1984
+			$end                             = $DateTime->getTimestamp();
1985
+			$where['Datetime.DTT_EVT_start'] = ['BETWEEN', [$start, $end]];
1986
+		} elseif ($status === 'today') {
1987
+			$DateTime                        =
1988
+				new DateTime('now', new DateTimeZone(EEM_Event::instance()->get_timezone()));
1989
+			$start                           = $DateTime->setTime(0, 0)->format(implode(' ', $start_formats));
1990
+			$end                             = $DateTime->setTime(23, 59, 59)->format(implode(' ', $start_formats));
1991
+			$where['Datetime.DTT_EVT_start'] = ['BETWEEN', [$start, $end]];
1992
+		} elseif ($status === 'month') {
1993
+			$now                             = date('Y-m-01');
1994
+			$DateTime                        =
1995
+				new DateTime($now, new DateTimeZone(EEM_Event::instance()->get_timezone()));
1996
+			$start                           = $DateTime->setTime(0, 0)->format(implode(' ', $start_formats));
1997
+			$end                             = $DateTime->setDate(date('Y'), date('m'), $DateTime->format('t'))
1998
+														->setTime(23, 59, 59)
1999
+														->format(implode(' ', $start_formats));
2000
+			$where['Datetime.DTT_EVT_start'] = ['BETWEEN', [$start, $end]];
2001
+		}
2002
+		if (! EE_Registry::instance()->CAP->current_user_can('ee_read_others_events', 'get_events')) {
2003
+			$where['EVT_wp_user'] = get_current_user_id();
2004
+		} else {
2005
+			if (! isset($where['status'])) {
2006
+				if (! EE_Registry::instance()->CAP->current_user_can('ee_read_private_events', 'get_events')) {
2007
+					$where['OR'] = [
2008
+						'status*restrict_private' => ['!=', 'private'],
2009
+						'AND'                     => [
2010
+							'status*inclusive' => ['=', 'private'],
2011
+							'EVT_wp_user'      => get_current_user_id(),
2012
+						],
2013
+					];
2014
+				}
2015
+			}
2016
+		}
2017
+		$wp_user = $this->request->getRequestParam('EVT_wp_user', 0, DataType::INT);
2018
+		if (
2019
+			$wp_user
2020
+			&& $wp_user !== get_current_user_id()
2021
+			&& EE_Registry::instance()->CAP->current_user_can('ee_read_others_events', 'get_events')
2022
+		) {
2023
+			$where['EVT_wp_user'] = $wp_user;
2024
+		}
2025
+		// search query handling
2026
+		$search_term = $this->request->getRequestParam('s');
2027
+		if ($search_term) {
2028
+			$search_term = '%' . $search_term . '%';
2029
+			$where['OR'] = [
2030
+				'EVT_name'       => ['LIKE', $search_term],
2031
+				'EVT_desc'       => ['LIKE', $search_term],
2032
+				'EVT_short_desc' => ['LIKE', $search_term],
2033
+			];
2034
+		}
2035
+		// filter events by venue.
2036
+		$venue = $this->request->getRequestParam('venue', 0, DataType::INT);
2037
+		if ($venue) {
2038
+			$where['Venue.VNU_ID'] = $venue;
2039
+		}
2040
+		$request_params = $this->request->requestParams();
2041
+		$where          = apply_filters('FHEE__Events_Admin_Page__get_events__where', $where, $request_params);
2042
+		$query_params   = apply_filters(
2043
+			'FHEE__Events_Admin_Page__get_events__query_params',
2044
+			[
2045
+				$where,
2046
+				'limit'    => $limit,
2047
+				'order_by' => $orderby,
2048
+				'order'    => $order,
2049
+				'group_by' => 'EVT_ID',
2050
+			],
2051
+			$request_params
2052
+		);
2053
+
2054
+		// let's first check if we have special requests coming in.
2055
+		$active_status = $this->request->getRequestParam('active_status');
2056
+		if ($active_status) {
2057
+			switch ($active_status) {
2058
+				case 'upcoming':
2059
+					return $EEM_Event->get_upcoming_events($query_params, $count);
2060
+				case 'expired':
2061
+					return $EEM_Event->get_expired_events($query_params, $count);
2062
+				case 'active':
2063
+					return $EEM_Event->get_active_events($query_params, $count);
2064
+				case 'inactive':
2065
+					return $EEM_Event->get_inactive_events($query_params, $count);
2066
+			}
2067
+		}
2068
+
2069
+		return $count ? $EEM_Event->count([$where], 'EVT_ID', true) : $EEM_Event->get_all($query_params);
2070
+	}
2071
+
2072
+
2073
+	/**
2074
+	 * handling for WordPress CPT actions (trash, restore, delete)
2075
+	 *
2076
+	 * @param string $post_id
2077
+	 * @throws EE_Error
2078
+	 * @throws ReflectionException
2079
+	 */
2080
+	public function trash_cpt_item($post_id)
2081
+	{
2082
+		$this->request->setRequestParam('EVT_ID', $post_id);
2083
+		$this->_trash_or_restore_event('trash', false);
2084
+	}
2085
+
2086
+
2087
+	/**
2088
+	 * @param string $post_id
2089
+	 * @throws EE_Error
2090
+	 * @throws ReflectionException
2091
+	 */
2092
+	public function restore_cpt_item($post_id)
2093
+	{
2094
+		$this->request->setRequestParam('EVT_ID', $post_id);
2095
+		$this->_trash_or_restore_event('draft', false);
2096
+	}
2097
+
2098
+
2099
+	/**
2100
+	 * @param string $post_id
2101
+	 * @throws EE_Error
2102
+	 * @throws EE_Error
2103
+	 */
2104
+	public function delete_cpt_item($post_id)
2105
+	{
2106
+		throw new EE_Error(
2107
+			esc_html__(
2108
+				'Please contact Event Espresso support with the details of the steps taken to produce this error.',
2109
+				'event_espresso'
2110
+			)
2111
+		);
2112
+		// $this->request->setRequestParam('EVT_ID', $post_id);
2113
+		// $this->_delete_event();
2114
+	}
2115
+
2116
+
2117
+	/**
2118
+	 * _trash_or_restore_event
2119
+	 *
2120
+	 * @access protected
2121
+	 * @param string $event_status
2122
+	 * @param bool   $redirect_after
2123
+	 * @throws EE_Error
2124
+	 * @throws EE_Error
2125
+	 * @throws ReflectionException
2126
+	 */
2127
+	protected function _trash_or_restore_event(string $event_status = 'trash', bool $redirect_after = true)
2128
+	{
2129
+		// determine the event id and set to array.
2130
+		$EVT_ID = $this->request->getRequestParam('EVT_ID', 0, DataType::INT);
2131
+		// loop thru events
2132
+		if ($EVT_ID) {
2133
+			// clean status
2134
+			$event_status = sanitize_key($event_status);
2135
+			// grab status
2136
+			if (! empty($event_status)) {
2137
+				$success = $this->_change_event_status($EVT_ID, $event_status);
2138
+			} else {
2139
+				$success = false;
2140
+				$msg     = esc_html__(
2141
+					'An error occurred. The event could not be moved to the trash because a valid event status was not not supplied.',
2142
+					'event_espresso'
2143
+				);
2144
+				EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2145
+			}
2146
+		} else {
2147
+			$success = false;
2148
+			$msg     = esc_html__(
2149
+				'An error occurred. The event could not be moved to the trash because a valid event ID was not not supplied.',
2150
+				'event_espresso'
2151
+			);
2152
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2153
+		}
2154
+		$action = $event_status === 'trash' ? 'moved to the trash' : 'restored from the trash';
2155
+		if ($redirect_after) {
2156
+			$this->_redirect_after_action($success, 'Event', $action, ['action' => 'default']);
2157
+		}
2158
+	}
2159
+
2160
+
2161
+	/**
2162
+	 * _trash_or_restore_events
2163
+	 *
2164
+	 * @access protected
2165
+	 * @param string $event_status
2166
+	 * @return void
2167
+	 * @throws EE_Error
2168
+	 * @throws EE_Error
2169
+	 * @throws ReflectionException
2170
+	 */
2171
+	protected function _trash_or_restore_events(string $event_status = 'trash')
2172
+	{
2173
+		// clean status
2174
+		$event_status = sanitize_key($event_status);
2175
+		// grab status
2176
+		if (! empty($event_status)) {
2177
+			$success = true;
2178
+			// determine the event id and set to array.
2179
+			$EVT_IDs = $this->request->getRequestParam('EVT_IDs', [], 'int', true);
2180
+			// loop thru events
2181
+			foreach ($EVT_IDs as $EVT_ID) {
2182
+				if ($EVT_ID = absint($EVT_ID)) {
2183
+					$results = $this->_change_event_status($EVT_ID, $event_status);
2184
+					$success = $results !== false ? $success : false;
2185
+				} else {
2186
+					$msg = sprintf(
2187
+						esc_html__(
2188
+							'An error occurred. Event #%d could not be moved to the trash because a valid event ID was not not supplied.',
2189
+							'event_espresso'
2190
+						),
2191
+						$EVT_ID
2192
+					);
2193
+					EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2194
+					$success = false;
2195
+				}
2196
+			}
2197
+		} else {
2198
+			$success = false;
2199
+			$msg     = esc_html__(
2200
+				'An error occurred. The event could not be moved to the trash because a valid event status was not not supplied.',
2201
+				'event_espresso'
2202
+			);
2203
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2204
+		}
2205
+		// in order to force a pluralized result message we need to send back a success status greater than 1
2206
+		$success = $success ? 2 : false;
2207
+		$action  = $event_status === 'trash' ? 'moved to the trash' : 'restored from the trash';
2208
+		$this->_redirect_after_action($success, 'Events', $action, ['action' => 'default']);
2209
+	}
2210
+
2211
+
2212
+	/**
2213
+	 * @param int    $EVT_ID
2214
+	 * @param string $event_status
2215
+	 * @return bool
2216
+	 * @throws EE_Error
2217
+	 * @throws ReflectionException
2218
+	 */
2219
+	private function _change_event_status(int $EVT_ID = 0, string $event_status = ''): bool
2220
+	{
2221
+		// grab event id
2222
+		if (! $EVT_ID) {
2223
+			$msg = esc_html__(
2224
+				'An error occurred. No Event ID or an invalid Event ID was received.',
2225
+				'event_espresso'
2226
+			);
2227
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2228
+			return false;
2229
+		}
2230
+		$this->_cpt_model_obj = EEM_Event::instance()->get_one_by_ID($EVT_ID);
2231
+		// clean status
2232
+		$event_status = sanitize_key($event_status);
2233
+		// grab status
2234
+		if (empty($event_status)) {
2235
+			$msg = esc_html__(
2236
+				'An error occurred. No Event Status or an invalid Event Status was received.',
2237
+				'event_espresso'
2238
+			);
2239
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2240
+			return false;
2241
+		}
2242
+		// was event trashed or restored ?
2243
+		switch ($event_status) {
2244
+			case 'draft':
2245
+				$action = 'restored from the trash';
2246
+				$hook   = 'AHEE_event_restored_from_trash';
2247
+				break;
2248
+			case 'trash':
2249
+				$action = 'moved to the trash';
2250
+				$hook   = 'AHEE_event_moved_to_trash';
2251
+				break;
2252
+			default:
2253
+				$action = 'updated';
2254
+				$hook   = false;
2255
+		}
2256
+		// use class to change status
2257
+		$this->_cpt_model_obj->set_status($event_status);
2258
+		$success = $this->_cpt_model_obj->save();
2259
+		if (! $success) {
2260
+			$msg = sprintf(esc_html__('An error occurred. The event could not be %s.', 'event_espresso'), $action);
2261
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2262
+			return false;
2263
+		}
2264
+		if ($hook) {
2265
+			do_action($hook);
2266
+			// fake the action hook in EE_Soft_Delete_Base_Class::delete_or_restore()
2267
+			// because events side step that and it otherwise won't get called
2268
+			do_action(
2269
+				'AHEE__EE_Soft_Delete_Base_Class__delete_or_restore__after',
2270
+				$this->_cpt_model_obj,
2271
+				$hook === 'AHEE_event_moved_to_trash',
2272
+				$success
2273
+			);
2274
+		}
2275
+		return true;
2276
+	}
2277
+
2278
+
2279
+	/**
2280
+	 * @param array $event_ids
2281
+	 * @return array
2282
+	 * @since   4.10.23.p
2283
+	 */
2284
+	private function cleanEventIds(array $event_ids): array
2285
+	{
2286
+		return array_map('absint', $event_ids);
2287
+	}
2288
+
2289
+
2290
+	/**
2291
+	 * @return array
2292
+	 * @since   4.10.23.p
2293
+	 */
2294
+	private function getEventIdsFromRequest(): array
2295
+	{
2296
+		if ($this->request->requestParamIsSet('EVT_IDs')) {
2297
+			return $this->request->getRequestParam('EVT_IDs', [], 'int', true);
2298
+		} else {
2299
+			return $this->request->getRequestParam('EVT_ID', [], 'int', true);
2300
+		}
2301
+	}
2302
+
2303
+
2304
+	/**
2305
+	 * @param bool $preview_delete
2306
+	 * @throws EE_Error
2307
+	 * @throws ReflectionException
2308
+	 */
2309
+	protected function _delete_event(bool $preview_delete = true)
2310
+	{
2311
+		$this->_delete_events($preview_delete);
2312
+	}
2313
+
2314
+
2315
+	/**
2316
+	 * Gets the tree traversal batch persister.
2317
+	 *
2318
+	 * @return NodeGroupDao
2319
+	 * @throws InvalidArgumentException
2320
+	 * @throws InvalidDataTypeException
2321
+	 * @throws InvalidInterfaceException
2322
+	 * @since 4.10.12.p
2323
+	 */
2324
+	protected function getModelObjNodeGroupPersister(): NodeGroupDao
2325
+	{
2326
+		if (! $this->model_obj_node_group_persister instanceof NodeGroupDao) {
2327
+			$this->model_obj_node_group_persister =
2328
+				$this->getLoader()->load('\EventEspresso\core\services\orm\tree_traversal\NodeGroupDao');
2329
+		}
2330
+		return $this->model_obj_node_group_persister;
2331
+	}
2332
+
2333
+
2334
+	/**
2335
+	 * @param bool $preview_delete
2336
+	 * @return void
2337
+	 * @throws EE_Error
2338
+	 * @throws ReflectionException
2339
+	 */
2340
+	protected function _delete_events(bool $preview_delete = true)
2341
+	{
2342
+		$event_ids = $this->getEventIdsFromRequest();
2343
+		if ($preview_delete) {
2344
+			$this->generateDeletionPreview($event_ids);
2345
+		} else {
2346
+			foreach ($event_ids as $event_id) {
2347
+				$event = EEM_Event::instance()->get_one_by_ID($event_id);
2348
+				if ($event instanceof EE_Event) {
2349
+					$event->delete_permanently();
2350
+				}
2351
+			}
2352
+		}
2353
+	}
2354
+
2355
+
2356
+	/**
2357
+	 * @param array $event_ids
2358
+	 */
2359
+	protected function generateDeletionPreview(array $event_ids)
2360
+	{
2361
+		$event_ids = $this->cleanEventIds($event_ids);
2362
+		// Set a code we can use to reference this deletion task in the batch jobs and preview page.
2363
+		$deletion_job_code = $this->getModelObjNodeGroupPersister()->generateGroupCode();
2364
+		$return_url        = EE_Admin_Page::add_query_args_and_nonce(
2365
+			[
2366
+				'action'            => 'preview_deletion',
2367
+				'deletion_job_code' => $deletion_job_code,
2368
+			],
2369
+			$this->_admin_base_url
2370
+		);
2371
+		EEH_URL::safeRedirectAndExit(
2372
+			EE_Admin_Page::add_query_args_and_nonce(
2373
+				[
2374
+					'page'              => EED_Batch::PAGE_SLUG,
2375
+					'batch'             => EED_Batch::batch_job,
2376
+					'EVT_IDs'           => $event_ids,
2377
+					'deletion_job_code' => $deletion_job_code,
2378
+					'job_handler'       => urlencode('EventEspressoBatchRequest\JobHandlers\PreviewEventDeletion'),
2379
+					'return_url'        => urlencode($return_url),
2380
+				],
2381
+				admin_url()
2382
+			)
2383
+		);
2384
+	}
2385
+
2386
+
2387
+	/**
2388
+	 * Checks for a POST submission
2389
+	 *
2390
+	 * @since 4.10.12.p
2391
+	 */
2392
+	protected function confirmDeletion()
2393
+	{
2394
+		$deletion_redirect_logic = $this->getLoader()->getShared(
2395
+			'EventEspresso\core\domain\services\admin\events\data\ConfirmDeletion'
2396
+		);
2397
+		$deletion_redirect_logic->handle($this->get_request_data(), $this->admin_base_url());
2398
+	}
2399
+
2400
+
2401
+	/**
2402
+	 * A page for users to preview what exactly will be deleted, and confirm they want to delete it.
2403
+	 *
2404
+	 * @throws EE_Error
2405
+	 * @since 4.10.12.p
2406
+	 */
2407
+	protected function previewDeletion()
2408
+	{
2409
+		$preview_deletion_logic = $this->getLoader()->getShared(
2410
+			'EventEspresso\core\domain\services\admin\events\data\PreviewDeletion'
2411
+		);
2412
+		$this->set_template_args($preview_deletion_logic->handle($this->get_request_data(), $this->admin_base_url()));
2413
+		$this->display_admin_page_with_no_sidebar();
2414
+	}
2415
+
2416
+
2417
+	/**
2418
+	 * get total number of events
2419
+	 *
2420
+	 * @access public
2421
+	 * @return int
2422
+	 * @throws EE_Error
2423
+	 * @throws EE_Error
2424
+	 * @throws ReflectionException
2425
+	 */
2426
+	public function total_events(): int
2427
+	{
2428
+		return EEM_Event::instance()->count(
2429
+			['caps' => 'read_admin'],
2430
+			'EVT_ID',
2431
+			true
2432
+		);
2433
+	}
2434
+
2435
+
2436
+	/**
2437
+	 * get total number of draft events
2438
+	 *
2439
+	 * @access public
2440
+	 * @return int
2441
+	 * @throws EE_Error
2442
+	 * @throws EE_Error
2443
+	 * @throws ReflectionException
2444
+	 */
2445
+	public function total_events_draft(): int
2446
+	{
2447
+		return EEM_Event::instance()->count(
2448
+			[
2449
+				['status' => ['IN', ['draft', 'auto-draft']]],
2450
+				'caps' => 'read_admin',
2451
+			],
2452
+			'EVT_ID',
2453
+			true
2454
+		);
2455
+	}
2456
+
2457
+
2458
+	/**
2459
+	 * get total number of trashed events
2460
+	 *
2461
+	 * @access public
2462
+	 * @return int
2463
+	 * @throws EE_Error
2464
+	 * @throws EE_Error
2465
+	 * @throws ReflectionException
2466
+	 */
2467
+	public function total_trashed_events(): int
2468
+	{
2469
+		return EEM_Event::instance()->count(
2470
+			[
2471
+				['status' => 'trash'],
2472
+				'caps' => 'read_admin',
2473
+			],
2474
+			'EVT_ID',
2475
+			true
2476
+		);
2477
+	}
2478
+
2479
+
2480
+	/**
2481
+	 *    _default_event_settings
2482
+	 *    This generates the Default Settings Tab
2483
+	 *
2484
+	 * @return void
2485
+	 * @throws DomainException
2486
+	 * @throws EE_Error
2487
+	 * @throws InvalidArgumentException
2488
+	 * @throws InvalidDataTypeException
2489
+	 * @throws InvalidInterfaceException
2490
+	 */
2491
+	protected function _default_event_settings()
2492
+	{
2493
+		$this->_set_add_edit_form_tags('update_default_event_settings');
2494
+		$this->_set_publish_post_box_vars();
2495
+		$this->_template_args['admin_page_content'] = EEH_HTML::div(
2496
+			$this->_default_event_settings_form()->get_html(),
2497
+			'',
2498
+			'padding'
2499
+		);
2500
+		$this->display_admin_page_with_sidebar();
2501
+	}
2502
+
2503
+
2504
+	/**
2505
+	 * Return the form for event settings.
2506
+	 *
2507
+	 * @return EE_Form_Section_Proper
2508
+	 * @throws EE_Error
2509
+	 */
2510
+	protected function _default_event_settings_form(): EE_Form_Section_Proper
2511
+	{
2512
+		$registration_config              = EE_Registry::instance()->CFG->registration;
2513
+		$registration_stati_for_selection = EEM_Registration::reg_status_array(
2514
+		// exclude
2515
+			[
2516
+				EEM_Registration::status_id_cancelled,
2517
+				EEM_Registration::status_id_declined,
2518
+				EEM_Registration::status_id_incomplete,
2519
+				EEM_Registration::status_id_wait_list,
2520
+			],
2521
+			true
2522
+		);
2523
+		// setup Advanced Editor ???
2524
+		if (
2525
+			$this->raw_req_action === 'default_event_settings'
2526
+			|| $this->raw_req_action === 'update_default_event_settings'
2527
+		) {
2528
+			$this->advanced_editor_admin_form = $this->loader->getShared(AdvancedEditorAdminFormSection::class);
2529
+		}
2530
+		return new EE_Form_Section_Proper(
2531
+			[
2532
+				'name'            => 'update_default_event_settings',
2533
+				'html_id'         => 'update_default_event_settings',
2534
+				'html_class'      => 'form-table',
2535
+				'layout_strategy' => new EE_Admin_Two_Column_Layout(),
2536
+				'subsections'     => apply_filters(
2537
+					'FHEE__Events_Admin_Page___default_event_settings_form__form_subsections',
2538
+					[
2539
+						'defaults_section_header' => new EE_Form_Section_HTML(
2540
+							EEH_HTML::h2(
2541
+								esc_html__('Default Settings', 'event_espresso'),
2542
+								'',
2543
+								'ee-admin-settings-hdr'
2544
+							)
2545
+						),
2546
+						'default_reg_status'      => new EE_Select_Input(
2547
+							$registration_stati_for_selection,
2548
+							[
2549
+								'default'         => isset($registration_config->default_STS_ID)
2550
+													 && array_key_exists(
2551
+														 $registration_config->default_STS_ID,
2552
+														 $registration_stati_for_selection
2553
+													 )
2554
+									? sanitize_text_field($registration_config->default_STS_ID)
2555
+									: EEM_Registration::status_id_pending_payment,
2556
+								'html_label_text' => esc_html__('Default Registration Status', 'event_espresso')
2557
+													 . EEH_Template::get_help_tab_link(
2558
+														 'default_settings_status_help_tab'
2559
+													 ),
2560
+								'html_help_text'  => esc_html__(
2561
+									'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.',
2562
+									'event_espresso'
2563
+								),
2564
+							]
2565
+						),
2566
+						'default_max_tickets'     => new EE_Integer_Input(
2567
+							[
2568
+								'default'         => $registration_config->default_maximum_number_of_tickets
2569
+													 ?? EEM_Event::get_default_additional_limit(),
2570
+								'html_label_text' => esc_html__(
2571
+									'Default Maximum Tickets Allowed Per Order:',
2572
+									'event_espresso'
2573
+								)
2574
+													 . EEH_Template::get_help_tab_link(
2575
+														 'default_maximum_tickets_help_tab"'
2576
+													 ),
2577
+								'html_help_text'  => esc_html__(
2578
+									'This setting allows you to indicate what will be the default for the maximum number of tickets per order when creating new events.',
2579
+									'event_espresso'
2580
+								),
2581
+							]
2582
+						),
2583
+					]
2584
+				),
2585
+			]
2586
+		);
2587
+	}
2588
+
2589
+
2590
+	/**
2591
+	 * @return void
2592
+	 * @throws EE_Error
2593
+	 * @throws InvalidArgumentException
2594
+	 * @throws InvalidDataTypeException
2595
+	 * @throws InvalidInterfaceException
2596
+	 */
2597
+	protected function _update_default_event_settings()
2598
+	{
2599
+		$form = $this->_default_event_settings_form();
2600
+		if ($form->was_submitted()) {
2601
+			$form->receive_form_submission();
2602
+			if ($form->is_valid()) {
2603
+				$registration_config = EE_Registry::instance()->CFG->registration;
2604
+				$valid_data          = $form->valid_data();
2605
+				if (isset($valid_data['default_reg_status'])) {
2606
+					$registration_config->default_STS_ID = $valid_data['default_reg_status'];
2607
+				}
2608
+				if (isset($valid_data['default_max_tickets'])) {
2609
+					$registration_config->default_maximum_number_of_tickets = $valid_data['default_max_tickets'];
2610
+				}
2611
+				do_action(
2612
+					'AHEE__Events_Admin_Page___update_default_event_settings',
2613
+					$valid_data,
2614
+					EE_Registry::instance()->CFG,
2615
+					$this
2616
+				);
2617
+				// update because data was valid!
2618
+				EE_Registry::instance()->CFG->update_espresso_config();
2619
+				EE_Error::overwrite_success();
2620
+				EE_Error::add_success(
2621
+					esc_html__('Default Event Settings were updated', 'event_espresso')
2622
+				);
2623
+			}
2624
+		}
2625
+		$this->_redirect_after_action(0, '', '', ['action' => 'default_event_settings'], true);
2626
+	}
2627
+
2628
+
2629
+	/*************        Templates        *************
23 2630
      *
24
-     * @var EE_Event $_event
25
-     */
26
-    protected $_event;
27
-
28
-
29
-    /**
30
-     * This will hold the category object for category_details screen.
31
-     *
32
-     * @var stdClass $_category
33
-     */
34
-    protected $_category;
35
-
36
-
37
-    /**
38
-     * This will hold the event model instance
39
-     *
40
-     * @var EEM_Event $_event_model
41
-     */
42
-    protected $_event_model;
43
-
44
-
45
-    /**
46
-     * @var EE_Event
47
-     */
48
-    protected $_cpt_model_obj = false;
49
-
50
-
51
-    /**
52
-     * @var NodeGroupDao
53
-     */
54
-    protected $model_obj_node_group_persister;
55
-
56
-    /**
57
-     * @var AdvancedEditorAdminFormSection
58
-     */
59
-    protected $advanced_editor_admin_form;
60
-
61
-
62
-    /**
63
-     * Initialize page props for this admin page group.
64
-     */
65
-    protected function _init_page_props()
66
-    {
67
-        $this->page_slug        = EVENTS_PG_SLUG;
68
-        $this->page_label       = EVENTS_LABEL;
69
-        $this->_admin_base_url  = EVENTS_ADMIN_URL;
70
-        $this->_admin_base_path = EVENTS_ADMIN;
71
-        $this->_cpt_model_names = [
72
-            'create_new' => 'EEM_Event',
73
-            'edit'       => 'EEM_Event',
74
-        ];
75
-        $this->_cpt_edit_routes = [
76
-            'espresso_events' => 'edit',
77
-        ];
78
-        add_action(
79
-            'AHEE__EE_Admin_Page_CPT__set_model_object__after_set_object',
80
-            [$this, 'verify_event_edit'],
81
-            10,
82
-            2
83
-        );
84
-    }
85
-
86
-
87
-    /**
88
-     * Sets the ajax hooks used for this admin page group.
89
-     */
90
-    protected function _ajax_hooks()
91
-    {
92
-        add_action('wp_ajax_ee_save_timezone_setting', [$this, 'saveTimezoneString']);
93
-    }
94
-
95
-
96
-    /**
97
-     * Sets the page properties for this admin page group.
98
-     */
99
-    protected function _define_page_props()
100
-    {
101
-        $event_id = $this->request->getRequestParam('post', 0, DataType::INT);
102
-        if ($event_id) {
103
-            $event_post = get_post($event_id);
104
-        }
105
-
106
-        $this->_admin_page_title = EVENTS_LABEL;
107
-        $this->_labels           = [
108
-            'buttons'      => [
109
-                'add'             => esc_html__('Add New Event', 'event_espresso'),
110
-                'edit'            => esc_html__('Edit Event', 'event_espresso'),
111
-                'delete'          => esc_html__('Delete Event', 'event_espresso'),
112
-                'add_category'    => esc_html__('Add New Category', 'event_espresso'),
113
-                'edit_category'   => esc_html__('Edit Category', 'event_espresso'),
114
-                'delete_category' => esc_html__('Delete Category', 'event_espresso'),
115
-            ],
116
-            'editor_title' => [
117
-                'espresso_events' => isset($event_post) && $event_post instanceof WP_Post
118
-                    ? $event_post->post_title
119
-                    : esc_html__('Edit Event', 'event_espresso'),
120
-            ],
121
-            'publishbox'   => [
122
-                'create_new'        => esc_html__('Save New Event', 'event_espresso'),
123
-                'edit'              => esc_html__('Update Event', 'event_espresso'),
124
-                'add_category'      => esc_html__('Save New Category', 'event_espresso'),
125
-                'edit_category'     => esc_html__('Update Category', 'event_espresso'),
126
-                'template_settings' => esc_html__('Update Settings', 'event_espresso'),
127
-            ],
128
-        ];
129
-    }
130
-
131
-
132
-    /**
133
-     * Sets the page routes property for this admin page group.
134
-     */
135
-    protected function _set_page_routes()
136
-    {
137
-        // load formatter helper
138
-        // load field generator helper
139
-        // is there a evt_id in the request?
140
-        $EVT_ID = $this->request->getRequestParam('EVT_ID', 0, DataType::INT);
141
-        $EVT_ID = $this->request->getRequestParam('post', $EVT_ID, DataType::INT);
142
-
143
-        $this->_page_routes = [
144
-            'default'                       => [
145
-                'func'       => [$this, '_events_overview_list_table'],
146
-                'capability' => 'ee_read_events',
147
-            ],
148
-            'create_new'                    => [
149
-                'func'       => [$this, '_create_new_cpt_item'],
150
-                'capability' => 'ee_edit_events',
151
-            ],
152
-            'edit'                          => [
153
-                'func'       => [$this, '_edit_cpt_item'],
154
-                'capability' => 'ee_edit_event',
155
-                'obj_id'     => $EVT_ID,
156
-            ],
157
-            'copy_event'                    => [
158
-                'func'       => [$this, '_copy_events'],
159
-                'capability' => 'ee_edit_event',
160
-                'obj_id'     => $EVT_ID,
161
-                'noheader'   => true,
162
-            ],
163
-            'trash_event'                   => [
164
-                'func'       => [$this, '_trash_or_restore_event'],
165
-                'args'       => ['event_status' => 'trash'],
166
-                'capability' => 'ee_delete_event',
167
-                'obj_id'     => $EVT_ID,
168
-                'noheader'   => true,
169
-            ],
170
-            'trash_events'                  => [
171
-                'func'       => [$this, '_trash_or_restore_events'],
172
-                'args'       => ['event_status' => 'trash'],
173
-                'capability' => 'ee_delete_events',
174
-                'noheader'   => true,
175
-            ],
176
-            'restore_event'                 => [
177
-                'func'       => [$this, '_trash_or_restore_event'],
178
-                'args'       => ['event_status' => 'draft'],
179
-                'capability' => 'ee_delete_event',
180
-                'obj_id'     => $EVT_ID,
181
-                'noheader'   => true,
182
-            ],
183
-            'restore_events'                => [
184
-                'func'       => [$this, '_trash_or_restore_events'],
185
-                'args'       => ['event_status' => 'draft'],
186
-                'capability' => 'ee_delete_events',
187
-                'noheader'   => true,
188
-            ],
189
-            'delete_event'                  => [
190
-                'func'       => [$this, '_delete_event'],
191
-                'capability' => 'ee_delete_event',
192
-                'obj_id'     => $EVT_ID,
193
-                'noheader'   => true,
194
-            ],
195
-            'delete_events'                 => [
196
-                'func'       => [$this, '_delete_events'],
197
-                'capability' => 'ee_delete_events',
198
-                'noheader'   => true,
199
-            ],
200
-            'view_report'                   => [
201
-                'func'       => [$this, '_view_report'],
202
-                'capability' => 'ee_edit_events',
203
-            ],
204
-            'default_event_settings'        => [
205
-                'func'       => [$this, '_default_event_settings'],
206
-                'capability' => 'manage_options',
207
-            ],
208
-            'update_default_event_settings' => [
209
-                'func'       => [$this, '_update_default_event_settings'],
210
-                'capability' => 'manage_options',
211
-                'noheader'   => true,
212
-            ],
213
-            'template_settings'             => [
214
-                'func'       => [$this, '_template_settings'],
215
-                'capability' => 'manage_options',
216
-            ],
217
-            // event category tab related
218
-            'add_category'                  => [
219
-                'func'       => [$this, '_category_details'],
220
-                'capability' => 'ee_edit_event_category',
221
-                'args'       => ['view' => 'add'],
222
-            ],
223
-            'edit_category'                 => [
224
-                'func'       => [$this, '_category_details'],
225
-                'capability' => 'ee_edit_event_category',
226
-                'args'       => ['view' => 'edit'],
227
-            ],
228
-            'delete_categories'             => [
229
-                'func'       => [$this, '_delete_categories'],
230
-                'capability' => 'ee_delete_event_category',
231
-                'noheader'   => true,
232
-            ],
233
-            'delete_category'               => [
234
-                'func'       => [$this, '_delete_categories'],
235
-                'capability' => 'ee_delete_event_category',
236
-                'noheader'   => true,
237
-            ],
238
-            'insert_category'               => [
239
-                'func'       => [$this, '_insert_or_update_category'],
240
-                'args'       => ['new_category' => true],
241
-                'capability' => 'ee_edit_event_category',
242
-                'noheader'   => true,
243
-            ],
244
-            'update_category'               => [
245
-                'func'       => [$this, '_insert_or_update_category'],
246
-                'args'       => ['new_category' => false],
247
-                'capability' => 'ee_edit_event_category',
248
-                'noheader'   => true,
249
-            ],
250
-            'category_list'                 => [
251
-                'func'       => [$this, '_category_list_table'],
252
-                'capability' => 'ee_manage_event_categories',
253
-            ],
254
-            'preview_deletion'              => [
255
-                'func'       => [$this, 'previewDeletion'],
256
-                'capability' => 'ee_delete_events',
257
-            ],
258
-            'confirm_deletion'              => [
259
-                'func'       => [$this, 'confirmDeletion'],
260
-                'capability' => 'ee_delete_events',
261
-                'noheader'   => true,
262
-            ],
263
-        ];
264
-    }
265
-
266
-
267
-    /**
268
-     * Set the _page_config property for this admin page group.
269
-     */
270
-    protected function _set_page_config()
271
-    {
272
-        $post_id            = $this->request->getRequestParam('post', 0, DataType::INT);
273
-        $EVT_CAT_ID         = $this->request->getRequestParam('EVT_CAT_ID', 0, DataType::INT);
274
-        $this->_page_config = [
275
-            'default'                => [
276
-                'nav'           => [
277
-                    'label' => esc_html__('Overview', 'event_espresso'),
278
-                    'icon'  => 'dashicons-list-view',
279
-                    'order' => 10,
280
-                ],
281
-                'list_table'    => 'Events_Admin_List_Table',
282
-                'help_tabs'     => [
283
-                    'events_overview_help_tab'                       => [
284
-                        'title'    => esc_html__('Events Overview', 'event_espresso'),
285
-                        'filename' => 'events_overview',
286
-                    ],
287
-                    'events_overview_table_column_headings_help_tab' => [
288
-                        'title'    => esc_html__('Events Overview Table Column Headings', 'event_espresso'),
289
-                        'filename' => 'events_overview_table_column_headings',
290
-                    ],
291
-                    'events_overview_filters_help_tab'               => [
292
-                        'title'    => esc_html__('Events Overview Filters', 'event_espresso'),
293
-                        'filename' => 'events_overview_filters',
294
-                    ],
295
-                    'events_overview_view_help_tab'                  => [
296
-                        'title'    => esc_html__('Events Overview Views', 'event_espresso'),
297
-                        'filename' => 'events_overview_views',
298
-                    ],
299
-                    'events_overview_other_help_tab'                 => [
300
-                        'title'    => esc_html__('Events Overview Other', 'event_espresso'),
301
-                        'filename' => 'events_overview_other',
302
-                    ],
303
-                ],
304
-                'require_nonce' => false,
305
-            ],
306
-            'create_new'             => [
307
-                'nav'           => [
308
-                    'label'      => esc_html__('Add New Event', 'event_espresso'),
309
-                    'icon'       => 'dashicons-plus-alt',
310
-                    'order'      => 15,
311
-                    'persistent' => false,
312
-                ],
313
-                'metaboxes'     => ['_register_event_editor_meta_boxes'],
314
-                'help_tabs'     => [
315
-                    'event_editor_help_tab'                            => [
316
-                        'title'    => esc_html__('Event Editor', 'event_espresso'),
317
-                        'filename' => 'event_editor',
318
-                    ],
319
-                    'event_editor_title_richtexteditor_help_tab'       => [
320
-                        'title'    => esc_html__('Event Title & Rich Text Editor', 'event_espresso'),
321
-                        'filename' => 'event_editor_title_richtexteditor',
322
-                    ],
323
-                    'event_editor_venue_details_help_tab'              => [
324
-                        'title'    => esc_html__('Event Venue Details', 'event_espresso'),
325
-                        'filename' => 'event_editor_venue_details',
326
-                    ],
327
-                    'event_editor_event_datetimes_help_tab'            => [
328
-                        'title'    => esc_html__('Event Datetimes', 'event_espresso'),
329
-                        'filename' => 'event_editor_event_datetimes',
330
-                    ],
331
-                    'event_editor_event_tickets_help_tab'              => [
332
-                        'title'    => esc_html__('Event Tickets', 'event_espresso'),
333
-                        'filename' => 'event_editor_event_tickets',
334
-                    ],
335
-                    'event_editor_event_registration_options_help_tab' => [
336
-                        'title'    => esc_html__('Event Registration Options', 'event_espresso'),
337
-                        'filename' => 'event_editor_event_registration_options',
338
-                    ],
339
-                    'event_editor_tags_categories_help_tab'            => [
340
-                        'title'    => esc_html__('Event Tags & Categories', 'event_espresso'),
341
-                        'filename' => 'event_editor_tags_categories',
342
-                    ],
343
-                    'event_editor_questions_registrants_help_tab'      => [
344
-                        'title'    => esc_html__('Questions for Registrants', 'event_espresso'),
345
-                        'filename' => 'event_editor_questions_registrants',
346
-                    ],
347
-                    'event_editor_save_new_event_help_tab'             => [
348
-                        'title'    => esc_html__('Save New Event', 'event_espresso'),
349
-                        'filename' => 'event_editor_save_new_event',
350
-                    ],
351
-                    'event_editor_other_help_tab'                      => [
352
-                        'title'    => esc_html__('Event Other', 'event_espresso'),
353
-                        'filename' => 'event_editor_other',
354
-                    ],
355
-                ],
356
-                'qtips'         => ['EE_Event_Editor_Decaf_Tips'],
357
-                'require_nonce' => false,
358
-            ],
359
-            'edit'                   => [
360
-                'nav'           => [
361
-                    'label'      => esc_html__('Edit Event', 'event_espresso'),
362
-                    'icon'       => 'dashicons-edit',
363
-                    'order'      => 15,
364
-                    'persistent' => false,
365
-                    'url'        => $post_id
366
-                        ? EE_Admin_Page::add_query_args_and_nonce(
367
-                            ['post' => $post_id, 'action' => 'edit'],
368
-                            $this->_current_page_view_url
369
-                        )
370
-                        : $this->_admin_base_url,
371
-                ],
372
-                'metaboxes'     => ['_register_event_editor_meta_boxes'],
373
-                'help_tabs'     => [
374
-                    'event_editor_help_tab'                            => [
375
-                        'title'    => esc_html__('Event Editor', 'event_espresso'),
376
-                        'filename' => 'event_editor',
377
-                    ],
378
-                    'event_editor_title_richtexteditor_help_tab'       => [
379
-                        'title'    => esc_html__('Event Title & Rich Text Editor', 'event_espresso'),
380
-                        'filename' => 'event_editor_title_richtexteditor',
381
-                    ],
382
-                    'event_editor_venue_details_help_tab'              => [
383
-                        'title'    => esc_html__('Event Venue Details', 'event_espresso'),
384
-                        'filename' => 'event_editor_venue_details',
385
-                    ],
386
-                    'event_editor_event_datetimes_help_tab'            => [
387
-                        'title'    => esc_html__('Event Datetimes', 'event_espresso'),
388
-                        'filename' => 'event_editor_event_datetimes',
389
-                    ],
390
-                    'event_editor_event_tickets_help_tab'              => [
391
-                        'title'    => esc_html__('Event Tickets', 'event_espresso'),
392
-                        'filename' => 'event_editor_event_tickets',
393
-                    ],
394
-                    'event_editor_event_registration_options_help_tab' => [
395
-                        'title'    => esc_html__('Event Registration Options', 'event_espresso'),
396
-                        'filename' => 'event_editor_event_registration_options',
397
-                    ],
398
-                    'event_editor_tags_categories_help_tab'            => [
399
-                        'title'    => esc_html__('Event Tags & Categories', 'event_espresso'),
400
-                        'filename' => 'event_editor_tags_categories',
401
-                    ],
402
-                    'event_editor_questions_registrants_help_tab'      => [
403
-                        'title'    => esc_html__('Questions for Registrants', 'event_espresso'),
404
-                        'filename' => 'event_editor_questions_registrants',
405
-                    ],
406
-                    'event_editor_save_new_event_help_tab'             => [
407
-                        'title'    => esc_html__('Save New Event', 'event_espresso'),
408
-                        'filename' => 'event_editor_save_new_event',
409
-                    ],
410
-                    'event_editor_other_help_tab'                      => [
411
-                        'title'    => esc_html__('Event Other', 'event_espresso'),
412
-                        'filename' => 'event_editor_other',
413
-                    ],
414
-                ],
415
-                'require_nonce' => false,
416
-            ],
417
-            'default_event_settings' => [
418
-                'nav'           => [
419
-                    'label' => esc_html__('Default Settings', 'event_espresso'),
420
-                    'icon'  => 'dashicons-admin-generic',
421
-                    'order' => 40,
422
-                ],
423
-                'metaboxes'     => array_merge(['_publish_post_box'], $this->_default_espresso_metaboxes),
424
-                'labels'        => [
425
-                    'publishbox' => esc_html__('Update Settings', 'event_espresso'),
426
-                ],
427
-                'help_tabs'     => [
428
-                    'default_settings_help_tab'        => [
429
-                        'title'    => esc_html__('Default Event Settings', 'event_espresso'),
430
-                        'filename' => 'events_default_settings',
431
-                    ],
432
-                    'default_settings_status_help_tab' => [
433
-                        'title'    => esc_html__('Default Registration Status', 'event_espresso'),
434
-                        'filename' => 'events_default_settings_status',
435
-                    ],
436
-                    'default_maximum_tickets_help_tab' => [
437
-                        'title'    => esc_html__('Default Maximum Tickets Per Order', 'event_espresso'),
438
-                        'filename' => 'events_default_settings_max_tickets',
439
-                    ],
440
-                ],
441
-                'require_nonce' => false,
442
-            ],
443
-            // template settings
444
-            'template_settings'      => [
445
-                'nav'           => [
446
-                    'label' => esc_html__('Templates', 'event_espresso'),
447
-                    'icon'  => 'dashicons-layout',
448
-                    'order' => 30,
449
-                ],
450
-                'metaboxes'     => $this->_default_espresso_metaboxes,
451
-                'help_tabs'     => [
452
-                    'general_settings_templates_help_tab' => [
453
-                        'title'    => esc_html__('Templates', 'event_espresso'),
454
-                        'filename' => 'general_settings_templates',
455
-                    ],
456
-                ],
457
-                'require_nonce' => false,
458
-            ],
459
-            // event category stuff
460
-            'add_category'           => [
461
-                'nav'           => [
462
-                    'label'      => esc_html__('Add Category', 'event_espresso'),
463
-                    'icon'       => 'dashicons-plus-alt',
464
-                    'order'      => 25,
465
-                    'persistent' => false,
466
-                ],
467
-                'help_tabs'     => [
468
-                    'add_category_help_tab' => [
469
-                        'title'    => esc_html__('Add New Event Category', 'event_espresso'),
470
-                        'filename' => 'events_add_category',
471
-                    ],
472
-                ],
473
-                'metaboxes'     => ['_publish_post_box'],
474
-                'require_nonce' => false,
475
-            ],
476
-            'edit_category'          => [
477
-                'nav'           => [
478
-                    'label'      => esc_html__('Edit Category', 'event_espresso'),
479
-                    'icon'       => 'dashicons-edit',
480
-                    'order'      => 25,
481
-                    'persistent' => false,
482
-                    'url'        => $EVT_CAT_ID
483
-                        ? add_query_arg(
484
-                            ['EVT_CAT_ID' => $EVT_CAT_ID],
485
-                            $this->_current_page_view_url
486
-                        )
487
-                        : $this->_admin_base_url,
488
-                ],
489
-                'help_tabs'     => [
490
-                    'edit_category_help_tab' => [
491
-                        'title'    => esc_html__('Edit Event Category', 'event_espresso'),
492
-                        'filename' => 'events_edit_category',
493
-                    ],
494
-                ],
495
-                'metaboxes'     => ['_publish_post_box'],
496
-                'require_nonce' => false,
497
-            ],
498
-            'category_list'          => [
499
-                'nav'           => [
500
-                    'label' => esc_html__('Categories', 'event_espresso'),
501
-                    'icon'  => 'dashicons-networking',
502
-                    'order' => 20,
503
-                ],
504
-                'list_table'    => 'Event_Categories_Admin_List_Table',
505
-                'help_tabs'     => [
506
-                    'events_categories_help_tab'                       => [
507
-                        'title'    => esc_html__('Event Categories', 'event_espresso'),
508
-                        'filename' => 'events_categories',
509
-                    ],
510
-                    'events_categories_table_column_headings_help_tab' => [
511
-                        'title'    => esc_html__('Event Categories Table Column Headings', 'event_espresso'),
512
-                        'filename' => 'events_categories_table_column_headings',
513
-                    ],
514
-                    'events_categories_view_help_tab'                  => [
515
-                        'title'    => esc_html__('Event Categories Views', 'event_espresso'),
516
-                        'filename' => 'events_categories_views',
517
-                    ],
518
-                    'events_categories_other_help_tab'                 => [
519
-                        'title'    => esc_html__('Event Categories Other', 'event_espresso'),
520
-                        'filename' => 'events_categories_other',
521
-                    ],
522
-                ],
523
-                'metaboxes'     => $this->_default_espresso_metaboxes,
524
-                'require_nonce' => false,
525
-            ],
526
-            'preview_deletion'       => [
527
-                'nav'           => [
528
-                    'label'      => esc_html__('Preview Deletion', 'event_espresso'),
529
-                    'icon'       => 'dashicons-remove',
530
-                    'order'      => 15,
531
-                    'persistent' => false,
532
-                    'url'        => '',
533
-                ],
534
-                'require_nonce' => false,
535
-            ],
536
-        ];
537
-    }
538
-
539
-
540
-    /**
541
-     * Used to register any global screen options if necessary for every route in this admin page group.
542
-     */
543
-    protected function _add_screen_options()
544
-    {
545
-    }
546
-
547
-
548
-    /**
549
-     * Implementing the screen options for the 'default' route.
550
-     *
551
-     * @throws InvalidArgumentException
552
-     * @throws InvalidDataTypeException
553
-     * @throws InvalidInterfaceException
554
-     */
555
-    protected function _add_screen_options_default()
556
-    {
557
-        $this->_per_page_screen_option();
558
-    }
559
-
560
-
561
-    /**
562
-     * Implementing screen options for the category list route.
563
-     *
564
-     * @throws InvalidArgumentException
565
-     * @throws InvalidDataTypeException
566
-     * @throws InvalidInterfaceException
567
-     */
568
-    protected function _add_screen_options_category_list()
569
-    {
570
-        $page_title              = $this->_admin_page_title;
571
-        $this->_admin_page_title = esc_html__('Categories', 'event_espresso');
572
-        $this->_per_page_screen_option();
573
-        $this->_admin_page_title = $page_title;
574
-    }
575
-
576
-
577
-    /**
578
-     * Used to register any global feature pointers for the admin page group.
579
-     */
580
-    protected function _add_feature_pointers()
581
-    {
582
-    }
583
-
584
-
585
-    /**
586
-     * Registers and enqueues any global scripts and styles for the entire admin page group.
587
-     */
588
-    public function load_scripts_styles()
589
-    {
590
-        wp_register_style(
591
-            'events-admin-css',
592
-            EVENTS_ASSETS_URL . 'events-admin-page.css',
593
-            [],
594
-            EVENT_ESPRESSO_VERSION
595
-        );
596
-        wp_register_style(
597
-            'ee-cat-admin',
598
-            EVENTS_ASSETS_URL . 'ee-cat-admin.css',
599
-            [],
600
-            EVENT_ESPRESSO_VERSION
601
-        );
602
-        wp_enqueue_style('events-admin-css');
603
-        wp_enqueue_style('ee-cat-admin');
604
-        // scripts
605
-        wp_register_script(
606
-            'event_editor_js',
607
-            EVENTS_ASSETS_URL . 'event_editor.js',
608
-            ['ee_admin_js', 'jquery-ui-slider', 'jquery-ui-timepicker-addon'],
609
-            EVENT_ESPRESSO_VERSION,
610
-            true
611
-        );
612
-    }
613
-
614
-
615
-    /**
616
-     * Enqueuing scripts and styles specific to this view
617
-     */
618
-    public function load_scripts_styles_create_new()
619
-    {
620
-        $this->load_scripts_styles_edit();
621
-    }
622
-
623
-
624
-    /**
625
-     * Enqueuing scripts and styles specific to this view
626
-     */
627
-    public function load_scripts_styles_edit()
628
-    {
629
-        // styles
630
-        wp_enqueue_style('espresso-ui-theme');
631
-        wp_register_style(
632
-            'event-editor-css',
633
-            EVENTS_ASSETS_URL . 'event-editor.css',
634
-            ['ee-admin-css'],
635
-            EVENT_ESPRESSO_VERSION
636
-        );
637
-        wp_enqueue_style('event-editor-css');
638
-        // scripts
639
-        if (! $this->admin_config->useAdvancedEditor()) {
640
-            wp_register_script(
641
-                'event-datetime-metabox',
642
-                EVENTS_ASSETS_URL . 'event-datetime-metabox.js',
643
-                ['event_editor_js', 'ee-datepicker'],
644
-                EVENT_ESPRESSO_VERSION
645
-            );
646
-            wp_enqueue_script('event-datetime-metabox');
647
-        }
648
-    }
649
-
650
-
651
-    /**
652
-     * Populating the _views property for the category list table view.
653
-     */
654
-    protected function _set_list_table_views_category_list()
655
-    {
656
-        $this->_views = [
657
-            'all' => [
658
-                'slug'        => 'all',
659
-                'label'       => esc_html__('All', 'event_espresso'),
660
-                'count'       => 0,
661
-                'bulk_action' => [
662
-                    'delete_categories' => esc_html__('Delete Permanently', 'event_espresso'),
663
-                ],
664
-            ],
665
-        ];
666
-    }
667
-
668
-
669
-    /**
670
-     * For adding anything that fires on the admin_init hook for any route within this admin page group.
671
-     */
672
-    public function admin_init()
673
-    {
674
-        EE_Registry::$i18n_js_strings['image_confirm'] = esc_html__(
675
-            'Do you really want to delete this image? Please remember to update your event to complete the removal.',
676
-            'event_espresso'
677
-        );
678
-    }
679
-
680
-
681
-    /**
682
-     * For adding anything that should be triggered on the admin_notices hook for any route within this admin page
683
-     * group.
684
-     */
685
-    public function admin_notices()
686
-    {
687
-    }
688
-
689
-
690
-    /**
691
-     * For adding anything that should be triggered on the `admin_print_footer_scripts` hook for any route within
692
-     * this admin page group.
693
-     */
694
-    public function admin_footer_scripts()
695
-    {
696
-    }
697
-
698
-
699
-    /**
700
-     * Call this function to verify if an event is public and has tickets for sale.  If it does, then we need to show a
701
-     * warning (via EE_Error::add_error());
702
-     *
703
-     * @param EE_Event|null $event Event object
704
-     * @param string        $req_type
705
-     * @return void
706
-     * @throws EE_Error
707
-     * @throws ReflectionException
708
-     */
709
-    public function verify_event_edit(?EE_Base_Class $event = null, string $req_type = '')
710
-    {
711
-        // don't need to do this when processing
712
-        if (! empty($req_type)) {
713
-            return;
714
-        }
715
-        // no event?
716
-        if (! $event instanceof EE_Event) {
717
-            $event = $this->_cpt_model_obj;
718
-        }
719
-        // STILL no event?
720
-        if (! $event instanceof EE_Event) {
721
-            return;
722
-        }
723
-        // don't need to keep calling this
724
-        remove_action(
725
-            'AHEE__EE_Admin_Page_CPT__set_model_object__after_set_object',
726
-            [$this, 'verify_event_edit']
727
-        );
728
-        $orig_status = $event->status();
729
-        // first check if event is active.
730
-        if (
731
-            $orig_status === EEM_Event::cancelled
732
-            || $orig_status === EEM_Event::postponed
733
-            || $event->is_expired()
734
-            || $event->is_inactive()
735
-        ) {
736
-            return;
737
-        }
738
-        // made it here so it IS active... next check that any of the tickets are sold.
739
-        if ($event->is_sold_out(true)) {
740
-            if ($orig_status !== EEM_Event::sold_out && $event->status() !== $orig_status) {
741
-                EE_Error::add_attention(
742
-                    sprintf(
743
-                        esc_html__(
744
-                            '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.',
745
-                            'event_espresso'
746
-                        ),
747
-                        EEH_Template::pretty_status(EEM_Event::sold_out, false, 'sentence')
748
-                    )
749
-                );
750
-            }
751
-            return;
752
-        }
753
-        if ($orig_status === EEM_Event::sold_out) {
754
-            EE_Error::add_attention(
755
-                sprintf(
756
-                    esc_html__(
757
-                        '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.',
758
-                        'event_espresso'
759
-                    ),
760
-                    EEH_Template::pretty_status($event->status(), false, 'sentence')
761
-                )
762
-            );
763
-        }
764
-        // now we need to determine if the event has any tickets on sale.  If not then we dont' show the error
765
-        if (! $event->tickets_on_sale()) {
766
-            return;
767
-        }
768
-        // made it here so show warning
769
-        $this->_edit_event_warning();
770
-    }
771
-
772
-
773
-    /**
774
-     * This is the text used for when an event is being edited that is public and has tickets for sale.
775
-     * When needed, hook this into a EE_Error::add_error() notice.
776
-     *
777
-     * @access protected
778
-     * @return void
779
-     */
780
-    protected function _edit_event_warning()
781
-    {
782
-        // we don't want to add warnings during these requests
783
-        if ($this->request->getRequestParam('action') === 'editpost') {
784
-            return;
785
-        }
786
-        EE_Error::add_attention(
787
-            sprintf(
788
-                esc_html__(
789
-                    'Your event is open for registration. Making changes may disrupt any transactions in progress. %sLearn more%s',
790
-                    'event_espresso'
791
-                ),
792
-                '<a class="espresso-help-tab-lnk ee-help-tab-link">',
793
-                '</a>'
794
-            )
795
-        );
796
-    }
797
-
798
-
799
-    /**
800
-     * When a user is creating a new event, notify them if they haven't set their timezone.
801
-     * Otherwise, do the normal logic
802
-     *
803
-     * @return void
804
-     * @throws EE_Error
805
-     * @throws InvalidArgumentException
806
-     * @throws InvalidDataTypeException
807
-     * @throws InvalidInterfaceException
808
-     * @throws ReflectionException
809
-     */
810
-    protected function _create_new_cpt_item()
811
-    {
812
-        $has_timezone_string = get_option('timezone_string');
813
-        // only nag them about setting their timezone if it's their first event, and they haven't already done it
814
-        if (! $has_timezone_string && ! EEM_Event::instance()->exists([])) {
815
-            EE_Error::add_attention(
816
-                sprintf(
817
-                    esc_html__(
818
-                        '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',
819
-                        'event_espresso'
820
-                    ),
821
-                    '<br>',
822
-                    '<select id="timezone_string" name="timezone_string" aria-describedby="timezone-description">'
823
-                    . EEH_DTT_Helper::wp_timezone_choice('', EEH_DTT_Helper::get_user_locale())
824
-                    . '</select>',
825
-                    '<button class="button button--secondary timezone-submit">',
826
-                    '</button><span class="spinner"></span>'
827
-                ),
828
-                __FILE__,
829
-                __FUNCTION__,
830
-                __LINE__
831
-            );
832
-        }
833
-        parent::_create_new_cpt_item();
834
-    }
835
-
836
-
837
-    /**
838
-     * Sets the _views property for the default route in this admin page group.
839
-     */
840
-    protected function _set_list_table_views_default()
841
-    {
842
-        $this->_views = [
843
-            'all'   => [
844
-                'slug'        => 'all',
845
-                'label'       => esc_html__('View All Events', 'event_espresso'),
846
-                'count'       => 0,
847
-                'bulk_action' => [
848
-                    'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
849
-                ],
850
-            ],
851
-            'draft' => [
852
-                'slug'        => 'draft',
853
-                'label'       => esc_html__('Draft', 'event_espresso'),
854
-                'count'       => 0,
855
-                'bulk_action' => [
856
-                    'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
857
-                ],
858
-            ],
859
-        ];
860
-        if (EE_Registry::instance()->CAP->current_user_can('ee_delete_events', 'espresso_events_trash_events')) {
861
-            $this->_views['trash'] = [
862
-                'slug'        => 'trash',
863
-                'label'       => esc_html__('Trash', 'event_espresso'),
864
-                'count'       => 0,
865
-                'bulk_action' => [
866
-                    'restore_events' => esc_html__('Restore From Trash', 'event_espresso'),
867
-                    'delete_events'  => esc_html__('Delete Permanently', 'event_espresso'),
868
-                ],
869
-            ];
870
-        }
871
-    }
872
-
873
-
874
-    /**
875
-     * Provides the legend item array for the default list table view.
876
-     *
877
-     * @return array
878
-     * @throws EE_Error
879
-     * @throws EE_Error
880
-     */
881
-    protected function _event_legend_items(): array
882
-    {
883
-        $items    = [
884
-            'view_details'   => [
885
-                'class' => 'dashicons dashicons-visibility',
886
-                'desc'  => esc_html__('View Event', 'event_espresso'),
887
-            ],
888
-            'edit_event'     => [
889
-                'class' => 'dashicons dashicons-calendar-alt',
890
-                'desc'  => esc_html__('Edit Event Details', 'event_espresso'),
891
-            ],
892
-            'view_attendees' => [
893
-                'class' => 'dashicons dashicons-groups',
894
-                'desc'  => esc_html__('View Registrations for Event', 'event_espresso'),
895
-            ],
896
-        ];
897
-        $items    = apply_filters('FHEE__Events_Admin_Page___event_legend_items__items', $items);
898
-        $statuses = [
899
-            'sold_out_status'  => [
900
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::sold_out,
901
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::sold_out, false, 'sentence'),
902
-            ],
903
-            'active_status'    => [
904
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::active,
905
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::active, false, 'sentence'),
906
-            ],
907
-            'upcoming_status'  => [
908
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::upcoming,
909
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::upcoming, false, 'sentence'),
910
-            ],
911
-            'postponed_status' => [
912
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::postponed,
913
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::postponed, false, 'sentence'),
914
-            ],
915
-            'cancelled_status' => [
916
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::cancelled,
917
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::cancelled, false, 'sentence'),
918
-            ],
919
-            'expired_status'   => [
920
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::expired,
921
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::expired, false, 'sentence'),
922
-            ],
923
-            'inactive_status'  => [
924
-                'class' => 'ee-status-legend ee-status-bg--' . EE_Datetime::inactive,
925
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::inactive, false, 'sentence'),
926
-            ],
927
-        ];
928
-        $statuses = apply_filters('FHEE__Events_Admin_Page__event_legend_items__statuses', $statuses);
929
-        return array_merge($items, $statuses);
930
-    }
931
-
932
-
933
-    /**
934
-     * @return EEM_Event
935
-     * @throws EE_Error
936
-     * @throws InvalidArgumentException
937
-     * @throws InvalidDataTypeException
938
-     * @throws InvalidInterfaceException
939
-     * @throws ReflectionException
940
-     */
941
-    private function _event_model(): EEM_Event
942
-    {
943
-        if (! $this->_event_model instanceof EEM_Event) {
944
-            $this->_event_model = EE_Registry::instance()->load_model('Event');
945
-        }
946
-        return $this->_event_model;
947
-    }
948
-
949
-
950
-    /**
951
-     * Adds extra buttons to the WP CPT permalink field row.
952
-     * Method is called from parent and is hooked into the wp 'get_sample_permalink_html' filter.
953
-     *
954
-     * @param string      $return    the current html
955
-     * @param int         $id        the post id for the page
956
-     * @param string|null $new_title What the title is
957
-     * @param string|null $new_slug  what the slug is
958
-     * @return string            The new html string for the permalink area
959
-     * @deprecated 5.0.0.p
960
-     * @see TicketSelectorShortcodeButton::addButton
961
-     */
962
-    public function extra_permalink_field_buttons(
963
-        string $return,
964
-        int $id,
965
-        ?string $new_title,
966
-        ?string $new_slug
967
-    ): string {
968
-        return TicketSelectorShortcodeButton::addButton($return, $id, $new_title, $new_slug);
969
-    }
970
-
971
-
972
-    /**
973
-     * _events_overview_list_table
974
-     * This contains the logic for showing the events_overview list
975
-     *
976
-     * @access protected
977
-     * @return void
978
-     * @throws DomainException
979
-     * @throws EE_Error
980
-     * @throws InvalidArgumentException
981
-     * @throws InvalidDataTypeException
982
-     * @throws InvalidInterfaceException
983
-     */
984
-    protected function _events_overview_list_table()
985
-    {
986
-        $after_list_table = [];
987
-        $links_html       = EEH_HTML::div('', '', 'ee-admin-section ee-layout-stack');
988
-        $links_html       .= EEH_HTML::h3(esc_html__('Links', 'event_espresso'));
989
-        $links_html       .= EEH_HTML::div(
990
-            EEH_Template::get_button_or_link(
991
-                get_post_type_archive_link('espresso_events'),
992
-                esc_html__('View Event Archive Page', 'event_espresso'),
993
-                'button button--small button--secondary'
994
-            ),
995
-            '',
996
-            'ee-admin-button-row ee-admin-button-row--align-start'
997
-        );
998
-        $links_html       .= EEH_HTML::divx();
999
-
1000
-        $after_list_table['view_event_list_button'] = $links_html;
1001
-
1002
-        $after_list_table['legend'] = $this->_display_legend($this->_event_legend_items());
1003
-        $this->_admin_page_title    .= ' ' . $this->get_action_link_or_button(
1004
-            'create_new',
1005
-            'add',
1006
-            [],
1007
-            'add-new-h2'
1008
-        );
1009
-
1010
-        $this->_template_args['after_list_table'] = array_merge(
1011
-            (array) $this->_template_args['after_list_table'],
1012
-            $after_list_table
1013
-        );
1014
-        $this->display_admin_list_table_page_with_no_sidebar();
1015
-    }
1016
-
1017
-
1018
-    /**
1019
-     * this allows for extra misc actions in the default WP publish box
1020
-     *
1021
-     * @return void
1022
-     * @throws DomainException
1023
-     * @throws EE_Error
1024
-     * @throws InvalidArgumentException
1025
-     * @throws InvalidDataTypeException
1026
-     * @throws InvalidInterfaceException
1027
-     * @throws ReflectionException
1028
-     */
1029
-    public function extra_misc_actions_publish_box()
1030
-    {
1031
-        $this->_generate_publish_box_extra_content();
1032
-    }
1033
-
1034
-
1035
-    /**
1036
-     * This is hooked into the WordPress do_action('save_post') hook and runs after the custom post type has been
1037
-     * saved.
1038
-     * Typically you would use this to save any additional data.
1039
-     * Keep in mind also that "save_post" runs on EVERY post update to the database.
1040
-     * ALSO very important.  When a post transitions from scheduled to published,
1041
-     * the save_post action is fired but you will NOT have any _POST data containing any extra info you may have from
1042
-     * other meta saves. So MAKE sure that you handle this accordingly.
1043
-     *
1044
-     * @access protected
1045
-     * @abstract
1046
-     * @param string  $post_id The ID of the cpt that was saved (so you can link relationally)
1047
-     * @param WP_Post $post    The post object of the cpt that was saved.
1048
-     * @return void
1049
-     * @throws EE_Error
1050
-     * @throws InvalidArgumentException
1051
-     * @throws InvalidDataTypeException
1052
-     * @throws InvalidInterfaceException
1053
-     * @throws ReflectionException
1054
-     */
1055
-    protected function _insert_update_cpt_item($post_id, $post)
1056
-    {
1057
-        if ($post instanceof WP_Post && $post->post_type !== 'espresso_events') {
1058
-            // get out we're not processing an event save.
1059
-            return;
1060
-        }
1061
-        $event_values = [
1062
-            'EVT_member_only'     => $this->request->getRequestParam('member_only', false, DataType::BOOL),
1063
-            'EVT_allow_overflow'  => $this->request->getRequestParam('EVT_allow_overflow', false, DataType::BOOL),
1064
-            'EVT_timezone_string' => $this->request->getRequestParam('timezone_string'),
1065
-        ];
1066
-        // check if the new EDTR reg options meta box is being used, and if so, don't run updates for legacy version
1067
-        if (! $this->admin_config->useAdvancedEditor() || ! $this->feature->allowed('use_reg_options_meta_box')) {
1068
-            $event_values['EVT_display_ticket_selector']     = $this->request->getRequestParam(
1069
-                'display_ticket_selector',
1070
-                false,
1071
-                'bool'
1072
-            );
1073
-            $event_values['EVT_additional_limit']            = min(
1074
-                apply_filters('FHEE__EE_Events_Admin__insert_update_cpt_item__EVT_additional_limit_max', 255),
1075
-                $this->request->getRequestParam(
1076
-                    'additional_limit',
1077
-                    EEM_Event::get_default_additional_limit(),
1078
-                    'int'
1079
-                )
1080
-            );
1081
-            $event_values['EVT_default_registration_status'] = $this->request->getRequestParam(
1082
-                'EVT_default_registration_status',
1083
-                EE_Registry::instance()->CFG->registration->default_STS_ID
1084
-            );
1085
-
1086
-            $event_values['EVT_external_URL'] = $this->request->getRequestParam('externalURL');
1087
-            $event_values['EVT_phone']        = $this->request->getRequestParam('event_phone');
1088
-            $event_values['EVT_display_desc'] = $this->request->getRequestParam('display_desc', false, DataType::BOOL);
1089
-        } elseif ($post instanceof WP_Post) {
1090
-            $event_values['EVT_name'] = $post->post_title;
1091
-            $event_values['EVT_desc'] = $post->post_content;
1092
-        }
1093
-        // update event
1094
-        $success = $this->_event_model()->update_by_ID($event_values, $post_id);
1095
-        // get event_object for other metaboxes...
1096
-        // though it would seem to make sense to just use $this->_event_model()->get_one_by_ID( $post_id )..
1097
-        // i have to setup where conditions to override the filters in the model
1098
-        // that filter out auto-draft and inherit statuses so we GET the inherit id!
1099
-        /** @var EE_Event $event */
1100
-        $event = $this->_event_model()->get_one(
1101
-            [
1102
-                [
1103
-                    $this->_event_model()->primary_key_name() => $post_id,
1104
-                    'OR'                                      => [
1105
-                        'status'   => $post->post_status,
1106
-                        // if trying to "Publish" a sold out event, it's status will get switched back to "sold_out" in the db,
1107
-                        // but the returned object here has a status of "publish", so use the original post status as well
1108
-                        'status*1' => $this->request->getRequestParam('original_post_status'),
1109
-                    ],
1110
-                ],
1111
-            ]
1112
-        );
1113
-
1114
-        // the following are default callbacks for event attachment updates
1115
-        // that can be overridden by caffeinated functionality and/or addons.
1116
-        $event_update_callbacks = [];
1117
-        if (! $this->admin_config->useAdvancedEditor()) {
1118
-            $event_update_callbacks['_default_venue_update']   = [$this, '_default_venue_update'];
1119
-            $event_update_callbacks['_default_tickets_update'] = [$this, '_default_tickets_update'];
1120
-        }
1121
-        $event_update_callbacks = apply_filters(
1122
-            'FHEE__Events_Admin_Page___insert_update_cpt_item__event_update_callbacks',
1123
-            $event_update_callbacks
1124
-        );
1125
-
1126
-        $att_success = true;
1127
-        foreach ($event_update_callbacks as $e_callback) {
1128
-            $_success = is_callable($e_callback)
1129
-                ? $e_callback($event, $this->request->requestParams())
1130
-                : false;
1131
-            // if ANY of these updates fail then we want the appropriate global error message
1132
-            $att_success = $_success !== false ? $att_success : false;
1133
-        }
1134
-        // any errors?
1135
-        if ($success && $att_success === false) {
1136
-            EE_Error::add_error(
1137
-                esc_html__(
1138
-                    'Event Details saved successfully but something went wrong with saving attachments.',
1139
-                    'event_espresso'
1140
-                ),
1141
-                __FILE__,
1142
-                __FUNCTION__,
1143
-                __LINE__
1144
-            );
1145
-        } elseif ($success === false) {
1146
-            EE_Error::add_error(
1147
-                esc_html__('Event Details did not save successfully.', 'event_espresso'),
1148
-                __FILE__,
1149
-                __FUNCTION__,
1150
-                __LINE__
1151
-            );
1152
-        }
1153
-    }
1154
-
1155
-
1156
-    /**
1157
-     * @param int $post_id
1158
-     * @param int $revision_id
1159
-     * @throws EE_Error
1160
-     * @throws EE_Error
1161
-     * @throws ReflectionException
1162
-     * @see parent::restore_item()
1163
-     */
1164
-    protected function _restore_cpt_item(int $post_id, int $revision_id)
1165
-    {
1166
-        // copy existing event meta to new post
1167
-        $post_evt = $this->_event_model()->get_one_by_ID($post_id);
1168
-        if ($post_evt instanceof EE_Event) {
1169
-            // meta revision restore
1170
-            $post_evt->restore_revision($revision_id);
1171
-            // related objs restore
1172
-            $post_evt->restore_revision($revision_id, ['Venue', 'Datetime', 'Price']);
1173
-        }
1174
-    }
1175
-
1176
-
1177
-    /**
1178
-     * Attach the venue to the Event
1179
-     *
1180
-     * @param EE_Event $event Event Object to add the venue to
1181
-     * @param array    $data  The request data from the form
1182
-     * @return bool           Success or fail.
1183
-     * @throws EE_Error
1184
-     * @throws ReflectionException
1185
-     */
1186
-    protected function _default_venue_update(EE_Event $event, array $data): bool
1187
-    {
1188
-        require_once(EE_MODELS . 'EEM_Venue.model.php');
1189
-        $venue_model = EE_Registry::instance()->load_model('Venue');
1190
-        $venue_id    = ! empty($data['venue_id']) ? $data['venue_id'] : null;
1191
-        // very important.  If we don't have a venue name...
1192
-        // then we'll get out because not necessary to create empty venue
1193
-        if (empty($data['venue_title'])) {
1194
-            return false;
1195
-        }
1196
-        $venue_array = [
1197
-            'VNU_wp_user'         => $event->get('EVT_wp_user'),
1198
-            'VNU_name'            => $data['venue_title'],
1199
-            'VNU_desc'            => ! empty($data['venue_description']) ? $data['venue_description'] : null,
1200
-            'VNU_identifier'      => ! empty($data['venue_identifier']) ? $data['venue_identifier'] : null,
1201
-            'VNU_short_desc'      => ! empty($data['venue_short_description'])
1202
-                ? $data['venue_short_description']
1203
-                : null,
1204
-            'VNU_address'         => ! empty($data['address']) ? $data['address'] : null,
1205
-            'VNU_address2'        => ! empty($data['address2']) ? $data['address2'] : null,
1206
-            'VNU_city'            => ! empty($data['city']) ? $data['city'] : null,
1207
-            'STA_ID'              => ! empty($data['state']) ? $data['state'] : null,
1208
-            'CNT_ISO'             => ! empty($data['countries']) ? $data['countries'] : null,
1209
-            'VNU_zip'             => ! empty($data['zip']) ? $data['zip'] : null,
1210
-            'VNU_phone'           => ! empty($data['venue_phone']) ? $data['venue_phone'] : null,
1211
-            'VNU_capacity'        => ! empty($data['venue_capacity']) ? $data['venue_capacity'] : null,
1212
-            'VNU_url'             => ! empty($data['venue_url']) ? $data['venue_url'] : null,
1213
-            'VNU_virtual_phone'   => ! empty($data['virtual_phone']) ? $data['virtual_phone'] : null,
1214
-            'VNU_virtual_url'     => ! empty($data['virtual_url']) ? $data['virtual_url'] : null,
1215
-            'VNU_enable_for_gmap' => isset($data['enable_for_gmap']) ? 1 : 0,
1216
-            'status'              => 'publish',
1217
-        ];
1218
-        // if we've got the venue_id then we're just updating the existing venue so let's do that and then get out.
1219
-        if (! empty($venue_id)) {
1220
-            $update_where  = [$venue_model->primary_key_name() => $venue_id];
1221
-            $rows_affected = $venue_model->update($venue_array, [$update_where]);
1222
-            // we've gotta make sure that the venue is always attached to a revision..
1223
-            // add_relation_to should take care of making sure that the relation is already present.
1224
-            $event->_add_relation_to($venue_id, 'Venue');
1225
-            return $rows_affected > 0;
1226
-        }
1227
-        // we insert the venue
1228
-        $venue_id = $venue_model->insert($venue_array);
1229
-        $event->_add_relation_to($venue_id, 'Venue');
1230
-        return ! empty($venue_id);
1231
-        // when we have the ancestor come in it's already been handled by the revision save.
1232
-    }
1233
-
1234
-
1235
-    /**
1236
-     * Handles saving everything related to Tickets (datetimes, tickets, prices)
1237
-     *
1238
-     * @param EE_Event $event The Event object we're attaching data to
1239
-     * @param array    $data  The request data from the form
1240
-     * @return array
1241
-     * @throws EE_Error
1242
-     * @throws ReflectionException
1243
-     * @throws Exception
1244
-     */
1245
-    protected function _default_tickets_update(EE_Event $event, array $data): array
1246
-    {
1247
-        if ($this->admin_config->useAdvancedEditor()) {
1248
-            return [];
1249
-        }
1250
-        $datetime       = null;
1251
-        $saved_tickets  = [];
1252
-        $event_timezone = $event->get_timezone();
1253
-        $date_formats   = ['Y-m-d', 'h:i a'];
1254
-        foreach ($data['edit_event_datetimes'] as $row => $datetime_data) {
1255
-            // trim all values to ensure any excess whitespace is removed.
1256
-            $datetime_data                = array_map('trim', $datetime_data);
1257
-            $datetime_data['DTT_EVT_end'] =
1258
-                isset($datetime_data['DTT_EVT_end']) && ! empty($datetime_data['DTT_EVT_end'])
1259
-                    ? $datetime_data['DTT_EVT_end']
1260
-                    : $datetime_data['DTT_EVT_start'];
1261
-            $datetime_values              = [
1262
-                'DTT_ID'        => ! empty($datetime_data['DTT_ID']) ? $datetime_data['DTT_ID'] : null,
1263
-                'DTT_EVT_start' => $datetime_data['DTT_EVT_start'],
1264
-                'DTT_EVT_end'   => $datetime_data['DTT_EVT_end'],
1265
-                'DTT_reg_limit' => empty($datetime_data['DTT_reg_limit']) ? EE_INF : $datetime_data['DTT_reg_limit'],
1266
-                'DTT_order'     => $row,
1267
-            ];
1268
-            // if we have an id then let's get existing object first and then set the new values.
1269
-            //  Otherwise we instantiate a new object for save.
1270
-            if (! empty($datetime_data['DTT_ID'])) {
1271
-                $datetime = EEM_Datetime::instance($event_timezone)->get_one_by_ID($datetime_data['DTT_ID']);
1272
-                if (! $datetime instanceof EE_Datetime) {
1273
-                    throw new RuntimeException(
1274
-                        sprintf(
1275
-                            esc_html__(
1276
-                                'Something went wrong! A valid Datetime could not be retrieved from the database using the supplied ID: %1$d',
1277
-                                'event_espresso'
1278
-                            ),
1279
-                            $datetime_data['DTT_ID']
1280
-                        )
1281
-                    );
1282
-                }
1283
-                $datetime->set_date_format($date_formats[0]);
1284
-                $datetime->set_time_format($date_formats[1]);
1285
-                foreach ($datetime_values as $field => $value) {
1286
-                    $datetime->set($field, $value);
1287
-                }
1288
-            } else {
1289
-                $datetime = EE_Datetime::new_instance($datetime_values, $event_timezone, $date_formats);
1290
-            }
1291
-            if (! $datetime instanceof EE_Datetime) {
1292
-                throw new RuntimeException(
1293
-                    sprintf(
1294
-                        esc_html__(
1295
-                            'Something went wrong! A valid Datetime could not be generated or retrieved using the supplied data: %1$s',
1296
-                            'event_espresso'
1297
-                        ),
1298
-                        print_r($datetime_values, true)
1299
-                    )
1300
-                );
1301
-            }
1302
-            // before going any further make sure our dates are setup correctly
1303
-            // so that the end date is always equal or greater than the start date.
1304
-            if ($datetime->get_raw('DTT_EVT_start') > $datetime->get_raw('DTT_EVT_end')) {
1305
-                $datetime->set('DTT_EVT_end', $datetime->get('DTT_EVT_start'));
1306
-                $datetime = EEH_DTT_Helper::date_time_add($datetime, 'DTT_EVT_end', 'days');
1307
-            }
1308
-            $datetime->save();
1309
-            $event->_add_relation_to($datetime, 'Datetime');
1310
-        }
1311
-        // no datetimes get deleted so we don't do any of that logic here.
1312
-        // update tickets next
1313
-        $old_tickets = isset($data['ticket_IDs']) ? explode(',', $data['ticket_IDs']) : [];
1314
-
1315
-        // set up some default start and end dates in case those are not present in the incoming data
1316
-        $default_start_date = new DateTime('now', new DateTimeZone($event->get_timezone()));
1317
-        $default_start_date = $default_start_date->format($date_formats[0] . ' ' . $date_formats[1]);
1318
-        // use the start date of the first datetime for the end date
1319
-        $first_datetime   = $event->first_datetime();
1320
-        $default_end_date = $first_datetime->start_date_and_time($date_formats[0], $date_formats[1]);
1321
-
1322
-        // now process the incoming data
1323
-        foreach ($data['edit_tickets'] as $row => $ticket_data) {
1324
-            $update_prices = false;
1325
-            $ticket_price  = $data['edit_prices'][ $row ][1]['PRC_amount'] ?? 0;
1326
-            // trim inputs to ensure any excess whitespace is removed.
1327
-            $ticket_data   = array_map('trim', $ticket_data);
1328
-            $ticket_values = [
1329
-                'TKT_ID'          => ! empty($ticket_data['TKT_ID']) ? $ticket_data['TKT_ID'] : null,
1330
-                'TTM_ID'          => ! empty($ticket_data['TTM_ID']) ? $ticket_data['TTM_ID'] : 0,
1331
-                'TKT_name'        => ! empty($ticket_data['TKT_name']) ? $ticket_data['TKT_name'] : '',
1332
-                'TKT_description' => ! empty($ticket_data['TKT_description']) ? $ticket_data['TKT_description'] : '',
1333
-                'TKT_start_date'  => ! empty($ticket_data['TKT_start_date'])
1334
-                    ? $ticket_data['TKT_start_date']
1335
-                    : $default_start_date,
1336
-                'TKT_end_date'    => ! empty($ticket_data['TKT_end_date'])
1337
-                    ? $ticket_data['TKT_end_date']
1338
-                    : $default_end_date,
1339
-                'TKT_qty'         => ! empty($ticket_data['TKT_qty'])
1340
-                                     || (isset($ticket_data['TKT_qty']) && (int) $ticket_data['TKT_qty'] === 0)
1341
-                    ? $ticket_data['TKT_qty']
1342
-                    : EE_INF,
1343
-                'TKT_uses'        => ! empty($ticket_data['TKT_uses'])
1344
-                                     || (isset($ticket_data['TKT_uses']) && (int) $ticket_data['TKT_uses'] === 0)
1345
-                    ? $ticket_data['TKT_uses']
1346
-                    : EE_INF,
1347
-                'TKT_min'         => ! empty($ticket_data['TKT_min']) ? $ticket_data['TKT_min'] : 0,
1348
-                'TKT_max'         => ! empty($ticket_data['TKT_max']) ? $ticket_data['TKT_max'] : EE_INF,
1349
-                'TKT_order'       => $ticket_data['TKT_order'] ?? $row,
1350
-                'TKT_price'       => $ticket_price,
1351
-                'TKT_row'         => $row,
1352
-            ];
1353
-            // if this is a default ticket, then we need to set the TKT_ID to 0 and update accordingly,
1354
-            // which means in turn that the prices will become new prices as well.
1355
-            if (isset($ticket_data['TKT_is_default']) && $ticket_data['TKT_is_default']) {
1356
-                $ticket_values['TKT_ID']         = 0;
1357
-                $ticket_values['TKT_is_default'] = 0;
1358
-                $update_prices                   = true;
1359
-            }
1360
-            // if we have a TKT_ID then we need to get that existing TKT_obj and update it
1361
-            // we actually do our saves ahead of adding any relations because its entirely possible that this
1362
-            // ticket didn't get removed or added to any datetime in the session but DID have it's items modified.
1363
-            // keep in mind that if the ticket has been sold (and we have changed pricing information),
1364
-            // then we won't be updating the tkt but instead a new tkt will be created and the old one archived.
1365
-            if (! empty($ticket_data['TKT_ID'])) {
1366
-                $existing_ticket = EEM_Ticket::instance($event_timezone)->get_one_by_ID($ticket_data['TKT_ID']);
1367
-                if (! $existing_ticket instanceof EE_Ticket) {
1368
-                    throw new RuntimeException(
1369
-                        sprintf(
1370
-                            esc_html__(
1371
-                                'Something went wrong! A valid Ticket could not be retrieved from the database using the supplied ID: %1$d',
1372
-                                'event_espresso'
1373
-                            ),
1374
-                            $ticket_data['TKT_ID']
1375
-                        )
1376
-                    );
1377
-                }
1378
-                $ticket_sold = $existing_ticket->count_related(
1379
-                    'Registration',
1380
-                    [
1381
-                            [
1382
-                                'STS_ID' => [
1383
-                                    'NOT IN',
1384
-                                    [EEM_Registration::status_id_incomplete],
1385
-                                ],
1386
-                            ],
1387
-                        ]
1388
-                ) > 0;
1389
-                // let's just check the total price for the existing ticket and determine if it matches the new total price.
1390
-                // if they are different then we create a new ticket (if $ticket_sold)
1391
-                // if they aren't different then we go ahead and modify existing ticket.
1392
-                $create_new_ticket = $ticket_sold
1393
-                                     && $ticket_price !== $existing_ticket->price()
1394
-                                     && ! $existing_ticket->deleted();
1395
-                $existing_ticket->set_date_format($date_formats[0]);
1396
-                $existing_ticket->set_time_format($date_formats[1]);
1397
-                // set new values
1398
-                foreach ($ticket_values as $field => $value) {
1399
-                    if ($field == 'TKT_qty') {
1400
-                        $existing_ticket->set_qty($value);
1401
-                    } elseif ($field == 'TKT_price') {
1402
-                        $existing_ticket->set('TKT_price', $ticket_price);
1403
-                    } else {
1404
-                        $existing_ticket->set($field, $value);
1405
-                    }
1406
-                }
1407
-                $ticket = $existing_ticket;
1408
-                // if $create_new_ticket is false then we can safely update the existing ticket.
1409
-                //  Otherwise we have to create a new ticket.
1410
-                if ($create_new_ticket) {
1411
-                    // archive the old ticket first
1412
-                    $existing_ticket->set('TKT_deleted', 1);
1413
-                    $existing_ticket->save();
1414
-                    // make sure this ticket is still recorded in our $saved_tickets
1415
-                    // so we don't run it through the regular trash routine.
1416
-                    $saved_tickets[ $existing_ticket->ID() ] = $existing_ticket;
1417
-                    // create new ticket that's a copy of the existing except,
1418
-                    // (a new id of course and not archived) AND has the new TKT_price associated with it.
1419
-                    $new_ticket = clone $existing_ticket;
1420
-                    $new_ticket->set('TKT_ID', 0);
1421
-                    $new_ticket->set('TKT_deleted', 0);
1422
-                    $new_ticket->set('TKT_sold', 0);
1423
-                    // now we need to make sure that $new prices are created as well and attached to new ticket.
1424
-                    $update_prices = true;
1425
-                    $ticket        = $new_ticket;
1426
-                }
1427
-            } else {
1428
-                // no TKT_id so a new ticket
1429
-                $ticket_values['TKT_price'] = $ticket_price;
1430
-                $ticket                     = EE_Ticket::new_instance($ticket_values, $event_timezone, $date_formats);
1431
-                $update_prices              = true;
1432
-            }
1433
-            if (! $ticket instanceof EE_Ticket) {
1434
-                throw new RuntimeException(
1435
-                    sprintf(
1436
-                        esc_html__(
1437
-                            'Something went wrong! A valid Ticket could not be generated or retrieved using the supplied data: %1$s',
1438
-                            'event_espresso'
1439
-                        ),
1440
-                        print_r($ticket_values, true)
1441
-                    )
1442
-                );
1443
-            }
1444
-            // cap ticket qty by datetime reg limits
1445
-            $ticket->set_qty(min($ticket->qty(), $ticket->qty('reg_limit')));
1446
-            // update ticket.
1447
-            $ticket->save();
1448
-            // before going any further make sure our dates are setup correctly
1449
-            // so that the end date is always equal or greater than the start date.
1450
-            if ($ticket->get_raw('TKT_start_date') > $ticket->get_raw('TKT_end_date')) {
1451
-                $ticket->set('TKT_end_date', $ticket->get('TKT_start_date'));
1452
-                $ticket = EEH_DTT_Helper::date_time_add($ticket, 'TKT_end_date', 'days');
1453
-                $ticket->save();
1454
-            }
1455
-            // initially let's add the ticket to the datetime
1456
-            $datetime->_add_relation_to($ticket, 'Ticket');
1457
-            $saved_tickets[ $ticket->ID() ] = $ticket;
1458
-            // add prices to ticket
1459
-            $prices_data = isset($data['edit_prices'][ $row ]) && is_array($data['edit_prices'][ $row ])
1460
-                ? $data['edit_prices'][ $row ]
1461
-                : [];
1462
-            $this->_add_prices_to_ticket($prices_data, $ticket, $update_prices);
1463
-        }
1464
-        // however now we need to handle permanently deleting tickets via the ui.
1465
-        // Keep in mind that the ui does not allow deleting/archiving tickets that have ticket sold.
1466
-        // However, it does allow for deleting tickets that have no tickets sold,
1467
-        // in which case we want to get rid of permanently because there is no need to save in db.
1468
-        $old_tickets     = isset($old_tickets[0]) && $old_tickets[0] === '' ? [] : $old_tickets;
1469
-        $tickets_removed = array_diff($old_tickets, array_keys($saved_tickets));
1470
-        foreach ($tickets_removed as $id) {
1471
-            $id = absint($id);
1472
-            // get the ticket for this id
1473
-            $ticket_to_remove = EEM_Ticket::instance()->get_one_by_ID($id);
1474
-            if (! $ticket_to_remove instanceof EE_Ticket) {
1475
-                continue;
1476
-            }
1477
-            // need to get all the related datetimes on this ticket and remove from every single one of them
1478
-            // (remember this process can ONLY kick off if there are NO tickets sold)
1479
-            $related_datetimes = $ticket_to_remove->get_many_related('Datetime');
1480
-            foreach ($related_datetimes as $related_datetime) {
1481
-                $ticket_to_remove->_remove_relation_to($related_datetime, 'Datetime');
1482
-            }
1483
-            // need to do the same for prices (except these prices can also be deleted because again,
1484
-            // tickets can only be trashed if they don't have any TKTs sold (otherwise they are just archived))
1485
-            $ticket_to_remove->delete_related_permanently('Price');
1486
-            // finally let's delete this ticket
1487
-            // (which should not be blocked at this point b/c we've removed all our relationships)
1488
-            $ticket_to_remove->delete_permanently();
1489
-        }
1490
-        return [$datetime, $saved_tickets];
1491
-    }
1492
-
1493
-
1494
-    /**
1495
-     * This attaches a list of given prices to a ticket.
1496
-     * Note we dont' have to worry about ever removing relationships (or archiving prices)
1497
-     * because if there is a change in price information on a ticket, a new ticket is created anyways
1498
-     * so the archived ticket will retain the old price info and prices are automatically "archived" via the ticket.
1499
-     *
1500
-     * @access  private
1501
-     * @param array     $prices_data Array of prices from the form.
1502
-     * @param EE_Ticket $ticket      EE_Ticket object that prices are being attached to.
1503
-     * @param bool      $new_prices  Whether attach existing incoming prices or create new ones.
1504
-     * @return  void
1505
-     * @throws EE_Error
1506
-     * @throws ReflectionException
1507
-     */
1508
-    private function _add_prices_to_ticket(array $prices_data, EE_Ticket $ticket, bool $new_prices = false)
1509
-    {
1510
-        $timezone = $ticket->get_timezone();
1511
-        foreach ($prices_data as $row => $price_data) {
1512
-            $price_values = [
1513
-                'PRC_ID'         => ! empty($price_data['PRC_ID']) ? $price_data['PRC_ID'] : null,
1514
-                'PRT_ID'         => ! empty($price_data['PRT_ID']) ? $price_data['PRT_ID'] : null,
1515
-                'PRC_amount'     => ! empty($price_data['PRC_amount']) ? $price_data['PRC_amount'] : 0,
1516
-                'PRC_name'       => ! empty($price_data['PRC_name']) ? $price_data['PRC_name'] : '',
1517
-                'PRC_desc'       => ! empty($price_data['PRC_desc']) ? $price_data['PRC_desc'] : '',
1518
-                'PRC_is_default' => 0, // make sure prices are NOT set as default from this context
1519
-                'PRC_order'      => $row,
1520
-            ];
1521
-            if ($new_prices || empty($price_values['PRC_ID'])) {
1522
-                $price_values['PRC_ID'] = 0;
1523
-                $price                  = EE_Price::new_instance($price_values, $timezone);
1524
-            } else {
1525
-                $price = EEM_Price::instance($timezone)->get_one_by_ID($price_data['PRC_ID']);
1526
-                // update this price with new values
1527
-                foreach ($price_values as $field => $new_price) {
1528
-                    $price->set($field, $new_price);
1529
-                }
1530
-            }
1531
-            if (! $price instanceof EE_Price) {
1532
-                throw new RuntimeException(
1533
-                    sprintf(
1534
-                        esc_html__(
1535
-                            'Something went wrong! A valid Price could not be generated or retrieved using the supplied data: %1$s',
1536
-                            'event_espresso'
1537
-                        ),
1538
-                        print_r($price_values, true)
1539
-                    )
1540
-                );
1541
-            }
1542
-            $price->save();
1543
-            $ticket->_add_relation_to($price, 'Price');
1544
-        }
1545
-    }
1546
-
1547
-
1548
-    /**
1549
-     * Add in our autosave ajax handlers
1550
-     *
1551
-     */
1552
-    protected function _ee_autosave_create_new()
1553
-    {
1554
-    }
1555
-
1556
-
1557
-    /**
1558
-     * More autosave handlers.
1559
-     */
1560
-    protected function _ee_autosave_edit()
1561
-    {
1562
-    }
1563
-
1564
-
1565
-    /**
1566
-     * @throws EE_Error
1567
-     * @throws ReflectionException
1568
-     */
1569
-    private function _generate_publish_box_extra_content()
1570
-    {
1571
-        // load formatter helper
1572
-        // args for getting related registrations
1573
-        $approved_query_args        = [
1574
-            [
1575
-                'REG_deleted' => 0,
1576
-                'STS_ID'      => EEM_Registration::status_id_approved,
1577
-            ],
1578
-        ];
1579
-        $not_approved_query_args    = [
1580
-            [
1581
-                'REG_deleted' => 0,
1582
-                'STS_ID'      => EEM_Registration::status_id_not_approved,
1583
-            ],
1584
-        ];
1585
-        $pending_payment_query_args = [
1586
-            [
1587
-                'REG_deleted' => 0,
1588
-                'STS_ID'      => EEM_Registration::status_id_pending_payment,
1589
-            ],
1590
-        ];
1591
-        // publish box
1592
-        $publish_box_extra_args = [
1593
-            'view_approved_reg_url'        => add_query_arg(
1594
-                [
1595
-                    'action'      => 'default',
1596
-                    'event_id'    => $this->_cpt_model_obj->ID(),
1597
-                    '_reg_status' => EEM_Registration::status_id_approved,
1598
-                    'use_filters' => true,
1599
-                ],
1600
-                REG_ADMIN_URL
1601
-            ),
1602
-            'view_not_approved_reg_url'    => add_query_arg(
1603
-                [
1604
-                    'action'      => 'default',
1605
-                    'event_id'    => $this->_cpt_model_obj->ID(),
1606
-                    '_reg_status' => EEM_Registration::status_id_not_approved,
1607
-                    'use_filters' => true,
1608
-                ],
1609
-                REG_ADMIN_URL
1610
-            ),
1611
-            'view_pending_payment_reg_url' => add_query_arg(
1612
-                [
1613
-                    'action'      => 'default',
1614
-                    'event_id'    => $this->_cpt_model_obj->ID(),
1615
-                    '_reg_status' => EEM_Registration::status_id_pending_payment,
1616
-                    'use_filters' => true,
1617
-                ],
1618
-                REG_ADMIN_URL
1619
-            ),
1620
-            'approved_regs'                => $this->_cpt_model_obj->count_related(
1621
-                'Registration',
1622
-                $approved_query_args
1623
-            ),
1624
-            'not_approved_regs'            => $this->_cpt_model_obj->count_related(
1625
-                'Registration',
1626
-                $not_approved_query_args
1627
-            ),
1628
-            'pending_payment_regs'         => $this->_cpt_model_obj->count_related(
1629
-                'Registration',
1630
-                $pending_payment_query_args
1631
-            ),
1632
-            'misc_pub_section_class'       => apply_filters(
1633
-                'FHEE_Events_Admin_Page___generate_publish_box_extra_content__misc_pub_section_class',
1634
-                'misc-pub-section'
1635
-            ),
1636
-        ];
1637
-        ob_start();
1638
-        do_action(
1639
-            'AHEE__Events_Admin_Page___generate_publish_box_extra_content__event_editor_overview_add',
1640
-            $this->_cpt_model_obj
1641
-        );
1642
-        $publish_box_extra_args['event_editor_overview_add'] = ob_get_clean();
1643
-        // load template
1644
-        EEH_Template::display_template(
1645
-            EVENTS_TEMPLATE_PATH . 'event_publish_box_extras.template.php',
1646
-            $publish_box_extra_args
1647
-        );
1648
-    }
1649
-
1650
-
1651
-    /**
1652
-     * @return EE_Event
1653
-     */
1654
-    public function get_event_object()
1655
-    {
1656
-        return $this->_cpt_model_obj;
1657
-    }
1658
-
1659
-
1660
-
1661
-
1662
-    /** METABOXES * */
1663
-    /**
1664
-     * _register_event_editor_meta_boxes
1665
-     * add all metaboxes related to the event_editor
1666
-     *
1667
-     * @return void
1668
-     * @throws EE_Error
1669
-     * @throws ReflectionException
1670
-     */
1671
-    protected function _register_event_editor_meta_boxes()
1672
-    {
1673
-        $this->verify_cpt_object();
1674
-        $use_advanced_editor = $this->admin_config->useAdvancedEditor();
1675
-        // check if the new EDTR reg options meta box is being used, and if so, don't load the legacy version
1676
-        if (! $use_advanced_editor || ! $this->feature->allowed('use_reg_options_meta_box')) {
1677
-            $this->addMetaBox(
1678
-                'espresso_event_editor_event_options',
1679
-                esc_html__('Event Registration Options', 'event_espresso'),
1680
-                [$this, 'registration_options_meta_box'],
1681
-                $this->page_slug,
1682
-                'side'
1683
-            );
1684
-        }
1685
-        if (! $use_advanced_editor) {
1686
-            $this->addMetaBox(
1687
-                'espresso_event_editor_tickets',
1688
-                esc_html__('Event Datetime & Ticket', 'event_espresso'),
1689
-                [$this, 'ticket_metabox'],
1690
-                $this->page_slug,
1691
-                'normal',
1692
-                'high'
1693
-            );
1694
-        } elseif ($this->feature->allowed('use_reg_options_meta_box')) {
1695
-            add_action(
1696
-                'add_meta_boxes_espresso_events',
1697
-                function () {
1698
-                    global $current_screen;
1699
-                    remove_meta_box('authordiv', $current_screen, 'normal');
1700
-                },
1701
-                99
1702
-            );
1703
-        }
1704
-        // NOTE: if you're looking for other metaboxes in here,
1705
-        // where a metabox has a related management page in the admin
1706
-        // you will find it setup in the related management page's "_Hooks" file.
1707
-        // i.e. messages metabox is found in "espresso_events_Messages_Hooks.class.php".
1708
-    }
1709
-
1710
-
1711
-    /**
1712
-     * @throws DomainException
1713
-     * @throws EE_Error
1714
-     * @throws ReflectionException
1715
-     */
1716
-    public function ticket_metabox()
1717
-    {
1718
-        $existing_datetime_ids = $existing_ticket_ids = [];
1719
-        // defaults for template args
1720
-        $template_args = [
1721
-            'ticket_rows'       => '',
1722
-            'total_ticket_rows' => 1,
1723
-            'trash_icon'        => 'dashicons dashicons-lock',
1724
-            'disabled'          => '',
1725
-        ];
1726
-        $event_id      = is_object($this->_cpt_model_obj) ? $this->_cpt_model_obj->ID() : null;
1727
-        /**
1728
-         * 1. Start with retrieving Datetimes
1729
-         * 2. Fore each datetime get related tickets
1730
-         * 3. For each ticket get related prices
1731
-         */
1732
-        /** @var EEM_Datetime $datetime_model */
1733
-        $datetime_model = EE_Registry::instance()->load_model('Datetime');
1734
-        /** @var EEM_Ticket $datetime_model */
1735
-        $ticket_model = EE_Registry::instance()->load_model('Ticket');
1736
-        $times        = $datetime_model->get_all_event_dates($event_id);
1737
-        /** @type EE_Datetime $first_datetime */
1738
-        $first_datetime = reset($times);
1739
-        // do we get related tickets?
1740
-        if (
1741
-            $first_datetime instanceof EE_Datetime
1742
-            && $first_datetime->ID() !== 0
1743
-        ) {
1744
-            $existing_datetime_ids[] = $first_datetime->get('DTT_ID');
1745
-            $template_args['time']   = $first_datetime;
1746
-            $related_tickets         = $first_datetime->tickets(
1747
-                [
1748
-                    ['OR' => ['TKT_deleted' => 1, 'TKT_deleted*' => 0]],
1749
-                    'default_where_conditions' => 'none',
1750
-                ]
1751
-            );
1752
-            if (! empty($related_tickets)) {
1753
-                $template_args['total_ticket_rows'] = count($related_tickets);
1754
-                $row                                = 0;
1755
-                foreach ($related_tickets as $ticket) {
1756
-                    $existing_ticket_ids[]        = $ticket->get('TKT_ID');
1757
-                    $template_args['ticket_rows'] .= $this->_get_ticket_row($ticket, false, $row);
1758
-                    $row++;
1759
-                }
1760
-            } else {
1761
-                $template_args['total_ticket_rows'] = 1;
1762
-                /** @type EE_Ticket $ticket */
1763
-                $ticket                       = $ticket_model->create_default_object();
1764
-                $template_args['ticket_rows'] .= $this->_get_ticket_row($ticket);
1765
-            }
1766
-        } else {
1767
-            $template_args['time'] = $times[0];
1768
-            /** @type EE_Ticket[] $tickets */
1769
-            $tickets                      = $ticket_model->get_all_default_tickets();
1770
-            $template_args['ticket_rows'] .= $this->_get_ticket_row($tickets[1]);
1771
-            // NOTE: we're just sending the first default row
1772
-            // (decaf can't manage default tickets so this should be sufficient);
1773
-        }
1774
-        $template_args['event_datetime_help_link'] = $this->_get_help_tab_link(
1775
-            'event_editor_event_datetimes_help_tab'
1776
-        );
1777
-        $template_args['ticket_options_help_link'] = $this->_get_help_tab_link('ticket_options_info');
1778
-        $template_args['existing_datetime_ids']    = implode(',', $existing_datetime_ids);
1779
-        $template_args['existing_ticket_ids']      = implode(',', $existing_ticket_ids);
1780
-        $template_args['ticket_js_structure']      = $this->_get_ticket_row(
1781
-            $ticket_model->create_default_object(),
1782
-            true
1783
-        );
1784
-        $template                                  = apply_filters(
1785
-            'FHEE__Events_Admin_Page__ticket_metabox__template',
1786
-            EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_main.template.php'
1787
-        );
1788
-        EEH_Template::display_template($template, $template_args);
1789
-    }
1790
-
1791
-
1792
-    /**
1793
-     * Setup an individual ticket form for the decaf event editor page
1794
-     *
1795
-     * @access private
1796
-     * @param EE_Ticket $ticket   the ticket object
1797
-     * @param boolean   $skeleton whether we're generating a skeleton for js manipulation
1798
-     * @param int       $row
1799
-     * @return string generated html for the ticket row.
1800
-     * @throws EE_Error
1801
-     * @throws ReflectionException
1802
-     */
1803
-    private function _get_ticket_row(EE_Ticket $ticket, bool $skeleton = false, int $row = 0): string
1804
-    {
1805
-        $template_args = [
1806
-            'tkt_status_class'    => ' tkt-status-' . $ticket->ticket_status(),
1807
-            'tkt_archive_class'   => $ticket->ticket_status() === EE_Ticket::archived && ! $skeleton ? ' tkt-archived'
1808
-                : '',
1809
-            'ticketrow'           => $skeleton ? 'TICKETNUM' : $row,
1810
-            'TKT_ID'              => $ticket->get('TKT_ID'),
1811
-            'TKT_name'            => $ticket->get('TKT_name'),
1812
-            'TKT_start_date'      => $skeleton ? '' : $ticket->get_date('TKT_start_date', 'Y-m-d h:i a'),
1813
-            'TKT_end_date'        => $skeleton ? '' : $ticket->get_date('TKT_end_date', 'Y-m-d h:i a'),
1814
-            'TKT_is_default'      => $ticket->get('TKT_is_default'),
1815
-            'TKT_qty'             => $ticket->get_pretty('TKT_qty', 'input'),
1816
-            'edit_ticketrow_name' => $skeleton ? 'TICKETNAMEATTR' : 'edit_tickets',
1817
-            'TKT_sold'            => $skeleton ? 0 : $ticket->get('TKT_sold'),
1818
-            'trash_icon'          => ($skeleton || (! empty($ticket) && ! $ticket->get('TKT_deleted')))
1819
-                                     && (! empty($ticket) && $ticket->get('TKT_sold') === 0)
1820
-                ? 'trash-icon dashicons dashicons-post-trash clickable' : 'dashicons dashicons-lock',
1821
-            'disabled'            => $skeleton || (! empty($ticket) && ! $ticket->get('TKT_deleted')) ? ''
1822
-                : ' disabled=disabled',
1823
-        ];
1824
-        $price         = $ticket->ID() !== 0
1825
-            ? $ticket->get_first_related('Price', ['default_where_conditions' => 'none'])
1826
-            : null;
1827
-        $price         = $price instanceof EE_Price
1828
-            ? $price
1829
-            : EEM_Price::instance()->create_default_object();
1830
-        $price_args    = [
1831
-            'price_currency_symbol' => EE_Registry::instance()->CFG->currency->sign,
1832
-            'PRC_amount'            => $price->get('PRC_amount'),
1833
-            'PRT_ID'                => $price->get('PRT_ID'),
1834
-            'PRC_ID'                => $price->get('PRC_ID'),
1835
-            'PRC_is_default'        => $price->get('PRC_is_default'),
1836
-        ];
1837
-        // make sure we have default start and end dates if skeleton
1838
-        // handle rows that should NOT be empty
1839
-        if (empty($template_args['TKT_start_date'])) {
1840
-            // if empty then the start date will be now.
1841
-            $template_args['TKT_start_date'] = date('Y-m-d h:i a', current_time('timestamp'));
1842
-        }
1843
-        if (empty($template_args['TKT_end_date'])) {
1844
-            // get the earliest datetime (if present);
1845
-            $earliest_datetime             = $this->_cpt_model_obj->ID() > 0
1846
-                ? $this->_cpt_model_obj->get_first_related(
1847
-                    'Datetime',
1848
-                    ['order_by' => ['DTT_EVT_start' => 'ASC']]
1849
-                )
1850
-                : null;
1851
-            $template_args['TKT_end_date'] = $earliest_datetime instanceof EE_Datetime
1852
-                ? $earliest_datetime->get_datetime('DTT_EVT_start', 'Y-m-d', 'h:i a')
1853
-                : date('Y-m-d h:i a', mktime(0, 0, 0, date('m'), date('d') + 7, date('Y')));
1854
-        }
1855
-        $template_args = array_merge($template_args, $price_args);
1856
-        $template      = apply_filters(
1857
-            'FHEE__Events_Admin_Page__get_ticket_row__template',
1858
-            EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_ticket_row.template.php',
1859
-            $ticket
1860
-        );
1861
-        return EEH_Template::display_template($template, $template_args, true);
1862
-    }
1863
-
1864
-
1865
-    /**
1866
-     * @throws EE_Error
1867
-     * @throws ReflectionException
1868
-     */
1869
-    public function registration_options_meta_box()
1870
-    {
1871
-        $yes_no_values             = [
1872
-            ['id' => true, 'text' => esc_html__('Yes', 'event_espresso')],
1873
-            ['id' => false, 'text' => esc_html__('No', 'event_espresso')],
1874
-        ];
1875
-        $default_reg_status_values = EEM_Registration::reg_status_array(
1876
-            [
1877
-                EEM_Registration::status_id_cancelled,
1878
-                EEM_Registration::status_id_declined,
1879
-                EEM_Registration::status_id_incomplete,
1880
-            ],
1881
-            true
1882
-        );
1883
-        // $template_args['is_active_select'] = EEH_Form_Fields::select_input('is_active', $yes_no_values, $this->_cpt_model_obj->is_active());
1884
-        $template_args['_event']                          = $this->_cpt_model_obj;
1885
-        $template_args['event']                           = $this->_cpt_model_obj;
1886
-        $template_args['active_status']                   = $this->_cpt_model_obj->pretty_active_status(false);
1887
-        $template_args['additional_limit']                = $this->_cpt_model_obj->additional_limit();
1888
-        $template_args['default_registration_status']     = EEH_Form_Fields::select_input(
1889
-            'default_reg_status',
1890
-            $default_reg_status_values,
1891
-            $this->_cpt_model_obj->default_registration_status()
1892
-        );
1893
-        $template_args['display_description']             = EEH_Form_Fields::select_input(
1894
-            'display_desc',
1895
-            $yes_no_values,
1896
-            $this->_cpt_model_obj->display_description()
1897
-        );
1898
-        $template_args['display_ticket_selector']         = EEH_Form_Fields::select_input(
1899
-            'display_ticket_selector',
1900
-            $yes_no_values,
1901
-            $this->_cpt_model_obj->display_ticket_selector(),
1902
-            '',
1903
-            '',
1904
-            false
1905
-        );
1906
-        $template_args['additional_registration_options'] = apply_filters(
1907
-            'FHEE__Events_Admin_Page__registration_options_meta_box__additional_registration_options',
1908
-            '',
1909
-            $template_args,
1910
-            $yes_no_values,
1911
-            $default_reg_status_values
1912
-        );
1913
-        EEH_Template::display_template(
1914
-            EVENTS_TEMPLATE_PATH . 'event_registration_options.template.php',
1915
-            $template_args
1916
-        );
1917
-    }
1918
-
1919
-
1920
-    /**
1921
-     * _get_events()
1922
-     * This method simply returns all the events (for the given _view and paging)
1923
-     *
1924
-     * @access public
1925
-     * @param int  $per_page     count of items per page (20 default);
1926
-     * @param int  $current_page what is the current page being viewed.
1927
-     * @param bool $count        if TRUE then we just return a count of ALL events matching the given _view.
1928
-     *                           If FALSE then we return an array of event objects
1929
-     *                           that match the given _view and paging parameters.
1930
-     * @return array|int         an array of event objects or a count of them.
1931
-     * @throws Exception
1932
-     */
1933
-    public function get_events(int $per_page = 10, int $current_page = 1, bool $count = false)
1934
-    {
1935
-        $EEM_Event   = $this->_event_model();
1936
-        $offset      = ($current_page - 1) * $per_page;
1937
-        $limit       = $count ? null : $offset . ',' . $per_page;
1938
-        $orderby     = $this->request->getRequestParam('orderby', 'EVT_ID');
1939
-        $order       = $this->request->getRequestParam('order', 'DESC');
1940
-        $month_range = $this->request->getRequestParam('month_range');
1941
-        if ($month_range) {
1942
-            $pieces = explode(' ', $month_range, 3);
1943
-            // simulate the FIRST day of the month, that fixes issues for months like February
1944
-            // where PHP doesn't know what to assume for date.
1945
-            // @see https://events.codebasehq.com/projects/event-espresso/tickets/10437
1946
-            $month_r = ! empty($pieces[0]) ? date('m', EEH_DTT_Helper::first_of_month_timestamp($pieces[0])) : '';
1947
-            $year_r  = ! empty($pieces[1]) ? $pieces[1] : '';
1948
-        }
1949
-        $where  = [];
1950
-        $status = $this->request->getRequestParam('status');
1951
-        // determine what post_status our condition will have for the query.
1952
-        switch ($status) {
1953
-            case 'month':
1954
-            case 'today':
1955
-            case null:
1956
-            case 'all':
1957
-                break;
1958
-            case 'draft':
1959
-                $where['status'] = ['IN', ['draft', 'auto-draft']];
1960
-                break;
1961
-            default:
1962
-                $where['status'] = $status;
1963
-        }
1964
-        // categories? The default for all categories is -1
1965
-        $category = $this->request->getRequestParam('EVT_CAT', -1, DataType::INT);
1966
-        if ($category !== -1) {
1967
-            $where['Term_Taxonomy.taxonomy'] = EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY;
1968
-            $where['Term_Taxonomy.term_id']  = $category;
1969
-        }
1970
-        // date where conditions
1971
-        $start_formats = EEM_Datetime::instance()->get_formats_for('DTT_EVT_start');
1972
-        if ($month_range) {
1973
-            $DateTime = new DateTime(
1974
-                $year_r . '-' . $month_r . '-01 00:00:00',
1975
-                new DateTimeZone('UTC')
1976
-            );
1977
-            $start    = $DateTime->getTimestamp();
1978
-            // set the datetime to be the end of the month
1979
-            $DateTime->setDate(
1980
-                $year_r,
1981
-                $month_r,
1982
-                $DateTime->format('t')
1983
-            )->setTime(23, 59, 59);
1984
-            $end                             = $DateTime->getTimestamp();
1985
-            $where['Datetime.DTT_EVT_start'] = ['BETWEEN', [$start, $end]];
1986
-        } elseif ($status === 'today') {
1987
-            $DateTime                        =
1988
-                new DateTime('now', new DateTimeZone(EEM_Event::instance()->get_timezone()));
1989
-            $start                           = $DateTime->setTime(0, 0)->format(implode(' ', $start_formats));
1990
-            $end                             = $DateTime->setTime(23, 59, 59)->format(implode(' ', $start_formats));
1991
-            $where['Datetime.DTT_EVT_start'] = ['BETWEEN', [$start, $end]];
1992
-        } elseif ($status === 'month') {
1993
-            $now                             = date('Y-m-01');
1994
-            $DateTime                        =
1995
-                new DateTime($now, new DateTimeZone(EEM_Event::instance()->get_timezone()));
1996
-            $start                           = $DateTime->setTime(0, 0)->format(implode(' ', $start_formats));
1997
-            $end                             = $DateTime->setDate(date('Y'), date('m'), $DateTime->format('t'))
1998
-                                                        ->setTime(23, 59, 59)
1999
-                                                        ->format(implode(' ', $start_formats));
2000
-            $where['Datetime.DTT_EVT_start'] = ['BETWEEN', [$start, $end]];
2001
-        }
2002
-        if (! EE_Registry::instance()->CAP->current_user_can('ee_read_others_events', 'get_events')) {
2003
-            $where['EVT_wp_user'] = get_current_user_id();
2004
-        } else {
2005
-            if (! isset($where['status'])) {
2006
-                if (! EE_Registry::instance()->CAP->current_user_can('ee_read_private_events', 'get_events')) {
2007
-                    $where['OR'] = [
2008
-                        'status*restrict_private' => ['!=', 'private'],
2009
-                        'AND'                     => [
2010
-                            'status*inclusive' => ['=', 'private'],
2011
-                            'EVT_wp_user'      => get_current_user_id(),
2012
-                        ],
2013
-                    ];
2014
-                }
2015
-            }
2016
-        }
2017
-        $wp_user = $this->request->getRequestParam('EVT_wp_user', 0, DataType::INT);
2018
-        if (
2019
-            $wp_user
2020
-            && $wp_user !== get_current_user_id()
2021
-            && EE_Registry::instance()->CAP->current_user_can('ee_read_others_events', 'get_events')
2022
-        ) {
2023
-            $where['EVT_wp_user'] = $wp_user;
2024
-        }
2025
-        // search query handling
2026
-        $search_term = $this->request->getRequestParam('s');
2027
-        if ($search_term) {
2028
-            $search_term = '%' . $search_term . '%';
2029
-            $where['OR'] = [
2030
-                'EVT_name'       => ['LIKE', $search_term],
2031
-                'EVT_desc'       => ['LIKE', $search_term],
2032
-                'EVT_short_desc' => ['LIKE', $search_term],
2033
-            ];
2034
-        }
2035
-        // filter events by venue.
2036
-        $venue = $this->request->getRequestParam('venue', 0, DataType::INT);
2037
-        if ($venue) {
2038
-            $where['Venue.VNU_ID'] = $venue;
2039
-        }
2040
-        $request_params = $this->request->requestParams();
2041
-        $where          = apply_filters('FHEE__Events_Admin_Page__get_events__where', $where, $request_params);
2042
-        $query_params   = apply_filters(
2043
-            'FHEE__Events_Admin_Page__get_events__query_params',
2044
-            [
2045
-                $where,
2046
-                'limit'    => $limit,
2047
-                'order_by' => $orderby,
2048
-                'order'    => $order,
2049
-                'group_by' => 'EVT_ID',
2050
-            ],
2051
-            $request_params
2052
-        );
2053
-
2054
-        // let's first check if we have special requests coming in.
2055
-        $active_status = $this->request->getRequestParam('active_status');
2056
-        if ($active_status) {
2057
-            switch ($active_status) {
2058
-                case 'upcoming':
2059
-                    return $EEM_Event->get_upcoming_events($query_params, $count);
2060
-                case 'expired':
2061
-                    return $EEM_Event->get_expired_events($query_params, $count);
2062
-                case 'active':
2063
-                    return $EEM_Event->get_active_events($query_params, $count);
2064
-                case 'inactive':
2065
-                    return $EEM_Event->get_inactive_events($query_params, $count);
2066
-            }
2067
-        }
2068
-
2069
-        return $count ? $EEM_Event->count([$where], 'EVT_ID', true) : $EEM_Event->get_all($query_params);
2070
-    }
2071
-
2072
-
2073
-    /**
2074
-     * handling for WordPress CPT actions (trash, restore, delete)
2075
-     *
2076
-     * @param string $post_id
2077
-     * @throws EE_Error
2078
-     * @throws ReflectionException
2079
-     */
2080
-    public function trash_cpt_item($post_id)
2081
-    {
2082
-        $this->request->setRequestParam('EVT_ID', $post_id);
2083
-        $this->_trash_or_restore_event('trash', false);
2084
-    }
2085
-
2086
-
2087
-    /**
2088
-     * @param string $post_id
2089
-     * @throws EE_Error
2090
-     * @throws ReflectionException
2091
-     */
2092
-    public function restore_cpt_item($post_id)
2093
-    {
2094
-        $this->request->setRequestParam('EVT_ID', $post_id);
2095
-        $this->_trash_or_restore_event('draft', false);
2096
-    }
2097
-
2098
-
2099
-    /**
2100
-     * @param string $post_id
2101
-     * @throws EE_Error
2102
-     * @throws EE_Error
2103
-     */
2104
-    public function delete_cpt_item($post_id)
2105
-    {
2106
-        throw new EE_Error(
2107
-            esc_html__(
2108
-                'Please contact Event Espresso support with the details of the steps taken to produce this error.',
2109
-                'event_espresso'
2110
-            )
2111
-        );
2112
-        // $this->request->setRequestParam('EVT_ID', $post_id);
2113
-        // $this->_delete_event();
2114
-    }
2115
-
2116
-
2117
-    /**
2118
-     * _trash_or_restore_event
2119
-     *
2120
-     * @access protected
2121
-     * @param string $event_status
2122
-     * @param bool   $redirect_after
2123
-     * @throws EE_Error
2124
-     * @throws EE_Error
2125
-     * @throws ReflectionException
2126
-     */
2127
-    protected function _trash_or_restore_event(string $event_status = 'trash', bool $redirect_after = true)
2128
-    {
2129
-        // determine the event id and set to array.
2130
-        $EVT_ID = $this->request->getRequestParam('EVT_ID', 0, DataType::INT);
2131
-        // loop thru events
2132
-        if ($EVT_ID) {
2133
-            // clean status
2134
-            $event_status = sanitize_key($event_status);
2135
-            // grab status
2136
-            if (! empty($event_status)) {
2137
-                $success = $this->_change_event_status($EVT_ID, $event_status);
2138
-            } else {
2139
-                $success = false;
2140
-                $msg     = esc_html__(
2141
-                    'An error occurred. The event could not be moved to the trash because a valid event status was not not supplied.',
2142
-                    'event_espresso'
2143
-                );
2144
-                EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2145
-            }
2146
-        } else {
2147
-            $success = false;
2148
-            $msg     = esc_html__(
2149
-                'An error occurred. The event could not be moved to the trash because a valid event ID was not not supplied.',
2150
-                'event_espresso'
2151
-            );
2152
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2153
-        }
2154
-        $action = $event_status === 'trash' ? 'moved to the trash' : 'restored from the trash';
2155
-        if ($redirect_after) {
2156
-            $this->_redirect_after_action($success, 'Event', $action, ['action' => 'default']);
2157
-        }
2158
-    }
2159
-
2160
-
2161
-    /**
2162
-     * _trash_or_restore_events
2163
-     *
2164
-     * @access protected
2165
-     * @param string $event_status
2166
-     * @return void
2167
-     * @throws EE_Error
2168
-     * @throws EE_Error
2169
-     * @throws ReflectionException
2170
-     */
2171
-    protected function _trash_or_restore_events(string $event_status = 'trash')
2172
-    {
2173
-        // clean status
2174
-        $event_status = sanitize_key($event_status);
2175
-        // grab status
2176
-        if (! empty($event_status)) {
2177
-            $success = true;
2178
-            // determine the event id and set to array.
2179
-            $EVT_IDs = $this->request->getRequestParam('EVT_IDs', [], 'int', true);
2180
-            // loop thru events
2181
-            foreach ($EVT_IDs as $EVT_ID) {
2182
-                if ($EVT_ID = absint($EVT_ID)) {
2183
-                    $results = $this->_change_event_status($EVT_ID, $event_status);
2184
-                    $success = $results !== false ? $success : false;
2185
-                } else {
2186
-                    $msg = sprintf(
2187
-                        esc_html__(
2188
-                            'An error occurred. Event #%d could not be moved to the trash because a valid event ID was not not supplied.',
2189
-                            'event_espresso'
2190
-                        ),
2191
-                        $EVT_ID
2192
-                    );
2193
-                    EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2194
-                    $success = false;
2195
-                }
2196
-            }
2197
-        } else {
2198
-            $success = false;
2199
-            $msg     = esc_html__(
2200
-                'An error occurred. The event could not be moved to the trash because a valid event status was not not supplied.',
2201
-                'event_espresso'
2202
-            );
2203
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2204
-        }
2205
-        // in order to force a pluralized result message we need to send back a success status greater than 1
2206
-        $success = $success ? 2 : false;
2207
-        $action  = $event_status === 'trash' ? 'moved to the trash' : 'restored from the trash';
2208
-        $this->_redirect_after_action($success, 'Events', $action, ['action' => 'default']);
2209
-    }
2210
-
2211
-
2212
-    /**
2213
-     * @param int    $EVT_ID
2214
-     * @param string $event_status
2215
-     * @return bool
2216
-     * @throws EE_Error
2217
-     * @throws ReflectionException
2218
-     */
2219
-    private function _change_event_status(int $EVT_ID = 0, string $event_status = ''): bool
2220
-    {
2221
-        // grab event id
2222
-        if (! $EVT_ID) {
2223
-            $msg = esc_html__(
2224
-                'An error occurred. No Event ID or an invalid Event ID was received.',
2225
-                'event_espresso'
2226
-            );
2227
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2228
-            return false;
2229
-        }
2230
-        $this->_cpt_model_obj = EEM_Event::instance()->get_one_by_ID($EVT_ID);
2231
-        // clean status
2232
-        $event_status = sanitize_key($event_status);
2233
-        // grab status
2234
-        if (empty($event_status)) {
2235
-            $msg = esc_html__(
2236
-                'An error occurred. No Event Status or an invalid Event Status was received.',
2237
-                'event_espresso'
2238
-            );
2239
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2240
-            return false;
2241
-        }
2242
-        // was event trashed or restored ?
2243
-        switch ($event_status) {
2244
-            case 'draft':
2245
-                $action = 'restored from the trash';
2246
-                $hook   = 'AHEE_event_restored_from_trash';
2247
-                break;
2248
-            case 'trash':
2249
-                $action = 'moved to the trash';
2250
-                $hook   = 'AHEE_event_moved_to_trash';
2251
-                break;
2252
-            default:
2253
-                $action = 'updated';
2254
-                $hook   = false;
2255
-        }
2256
-        // use class to change status
2257
-        $this->_cpt_model_obj->set_status($event_status);
2258
-        $success = $this->_cpt_model_obj->save();
2259
-        if (! $success) {
2260
-            $msg = sprintf(esc_html__('An error occurred. The event could not be %s.', 'event_espresso'), $action);
2261
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2262
-            return false;
2263
-        }
2264
-        if ($hook) {
2265
-            do_action($hook);
2266
-            // fake the action hook in EE_Soft_Delete_Base_Class::delete_or_restore()
2267
-            // because events side step that and it otherwise won't get called
2268
-            do_action(
2269
-                'AHEE__EE_Soft_Delete_Base_Class__delete_or_restore__after',
2270
-                $this->_cpt_model_obj,
2271
-                $hook === 'AHEE_event_moved_to_trash',
2272
-                $success
2273
-            );
2274
-        }
2275
-        return true;
2276
-    }
2277
-
2278
-
2279
-    /**
2280
-     * @param array $event_ids
2281
-     * @return array
2282
-     * @since   4.10.23.p
2283
-     */
2284
-    private function cleanEventIds(array $event_ids): array
2285
-    {
2286
-        return array_map('absint', $event_ids);
2287
-    }
2288
-
2289
-
2290
-    /**
2291
-     * @return array
2292
-     * @since   4.10.23.p
2293
-     */
2294
-    private function getEventIdsFromRequest(): array
2295
-    {
2296
-        if ($this->request->requestParamIsSet('EVT_IDs')) {
2297
-            return $this->request->getRequestParam('EVT_IDs', [], 'int', true);
2298
-        } else {
2299
-            return $this->request->getRequestParam('EVT_ID', [], 'int', true);
2300
-        }
2301
-    }
2302
-
2303
-
2304
-    /**
2305
-     * @param bool $preview_delete
2306
-     * @throws EE_Error
2307
-     * @throws ReflectionException
2308
-     */
2309
-    protected function _delete_event(bool $preview_delete = true)
2310
-    {
2311
-        $this->_delete_events($preview_delete);
2312
-    }
2313
-
2314
-
2315
-    /**
2316
-     * Gets the tree traversal batch persister.
2317
-     *
2318
-     * @return NodeGroupDao
2319
-     * @throws InvalidArgumentException
2320
-     * @throws InvalidDataTypeException
2321
-     * @throws InvalidInterfaceException
2322
-     * @since 4.10.12.p
2323
-     */
2324
-    protected function getModelObjNodeGroupPersister(): NodeGroupDao
2325
-    {
2326
-        if (! $this->model_obj_node_group_persister instanceof NodeGroupDao) {
2327
-            $this->model_obj_node_group_persister =
2328
-                $this->getLoader()->load('\EventEspresso\core\services\orm\tree_traversal\NodeGroupDao');
2329
-        }
2330
-        return $this->model_obj_node_group_persister;
2331
-    }
2332
-
2333
-
2334
-    /**
2335
-     * @param bool $preview_delete
2336
-     * @return void
2337
-     * @throws EE_Error
2338
-     * @throws ReflectionException
2339
-     */
2340
-    protected function _delete_events(bool $preview_delete = true)
2341
-    {
2342
-        $event_ids = $this->getEventIdsFromRequest();
2343
-        if ($preview_delete) {
2344
-            $this->generateDeletionPreview($event_ids);
2345
-        } else {
2346
-            foreach ($event_ids as $event_id) {
2347
-                $event = EEM_Event::instance()->get_one_by_ID($event_id);
2348
-                if ($event instanceof EE_Event) {
2349
-                    $event->delete_permanently();
2350
-                }
2351
-            }
2352
-        }
2353
-    }
2354
-
2355
-
2356
-    /**
2357
-     * @param array $event_ids
2358
-     */
2359
-    protected function generateDeletionPreview(array $event_ids)
2360
-    {
2361
-        $event_ids = $this->cleanEventIds($event_ids);
2362
-        // Set a code we can use to reference this deletion task in the batch jobs and preview page.
2363
-        $deletion_job_code = $this->getModelObjNodeGroupPersister()->generateGroupCode();
2364
-        $return_url        = EE_Admin_Page::add_query_args_and_nonce(
2365
-            [
2366
-                'action'            => 'preview_deletion',
2367
-                'deletion_job_code' => $deletion_job_code,
2368
-            ],
2369
-            $this->_admin_base_url
2370
-        );
2371
-        EEH_URL::safeRedirectAndExit(
2372
-            EE_Admin_Page::add_query_args_and_nonce(
2373
-                [
2374
-                    'page'              => EED_Batch::PAGE_SLUG,
2375
-                    'batch'             => EED_Batch::batch_job,
2376
-                    'EVT_IDs'           => $event_ids,
2377
-                    'deletion_job_code' => $deletion_job_code,
2378
-                    'job_handler'       => urlencode('EventEspressoBatchRequest\JobHandlers\PreviewEventDeletion'),
2379
-                    'return_url'        => urlencode($return_url),
2380
-                ],
2381
-                admin_url()
2382
-            )
2383
-        );
2384
-    }
2385
-
2386
-
2387
-    /**
2388
-     * Checks for a POST submission
2389
-     *
2390
-     * @since 4.10.12.p
2391
-     */
2392
-    protected function confirmDeletion()
2393
-    {
2394
-        $deletion_redirect_logic = $this->getLoader()->getShared(
2395
-            'EventEspresso\core\domain\services\admin\events\data\ConfirmDeletion'
2396
-        );
2397
-        $deletion_redirect_logic->handle($this->get_request_data(), $this->admin_base_url());
2398
-    }
2399
-
2400
-
2401
-    /**
2402
-     * A page for users to preview what exactly will be deleted, and confirm they want to delete it.
2403
-     *
2404
-     * @throws EE_Error
2405
-     * @since 4.10.12.p
2406
-     */
2407
-    protected function previewDeletion()
2408
-    {
2409
-        $preview_deletion_logic = $this->getLoader()->getShared(
2410
-            'EventEspresso\core\domain\services\admin\events\data\PreviewDeletion'
2411
-        );
2412
-        $this->set_template_args($preview_deletion_logic->handle($this->get_request_data(), $this->admin_base_url()));
2413
-        $this->display_admin_page_with_no_sidebar();
2414
-    }
2415
-
2416
-
2417
-    /**
2418
-     * get total number of events
2419
-     *
2420
-     * @access public
2421
-     * @return int
2422
-     * @throws EE_Error
2423
-     * @throws EE_Error
2424
-     * @throws ReflectionException
2425
-     */
2426
-    public function total_events(): int
2427
-    {
2428
-        return EEM_Event::instance()->count(
2429
-            ['caps' => 'read_admin'],
2430
-            'EVT_ID',
2431
-            true
2432
-        );
2433
-    }
2434
-
2435
-
2436
-    /**
2437
-     * get total number of draft events
2438
-     *
2439
-     * @access public
2440
-     * @return int
2441
-     * @throws EE_Error
2442
-     * @throws EE_Error
2443
-     * @throws ReflectionException
2444
-     */
2445
-    public function total_events_draft(): int
2446
-    {
2447
-        return EEM_Event::instance()->count(
2448
-            [
2449
-                ['status' => ['IN', ['draft', 'auto-draft']]],
2450
-                'caps' => 'read_admin',
2451
-            ],
2452
-            'EVT_ID',
2453
-            true
2454
-        );
2455
-    }
2456
-
2457
-
2458
-    /**
2459
-     * get total number of trashed events
2460
-     *
2461
-     * @access public
2462
-     * @return int
2463
-     * @throws EE_Error
2464
-     * @throws EE_Error
2465
-     * @throws ReflectionException
2466
-     */
2467
-    public function total_trashed_events(): int
2468
-    {
2469
-        return EEM_Event::instance()->count(
2470
-            [
2471
-                ['status' => 'trash'],
2472
-                'caps' => 'read_admin',
2473
-            ],
2474
-            'EVT_ID',
2475
-            true
2476
-        );
2477
-    }
2478
-
2479
-
2480
-    /**
2481
-     *    _default_event_settings
2482
-     *    This generates the Default Settings Tab
2483
-     *
2484
-     * @return void
2485
-     * @throws DomainException
2486
-     * @throws EE_Error
2487
-     * @throws InvalidArgumentException
2488
-     * @throws InvalidDataTypeException
2489
-     * @throws InvalidInterfaceException
2490
-     */
2491
-    protected function _default_event_settings()
2492
-    {
2493
-        $this->_set_add_edit_form_tags('update_default_event_settings');
2494
-        $this->_set_publish_post_box_vars();
2495
-        $this->_template_args['admin_page_content'] = EEH_HTML::div(
2496
-            $this->_default_event_settings_form()->get_html(),
2497
-            '',
2498
-            'padding'
2499
-        );
2500
-        $this->display_admin_page_with_sidebar();
2501
-    }
2502
-
2503
-
2504
-    /**
2505
-     * Return the form for event settings.
2506
-     *
2507
-     * @return EE_Form_Section_Proper
2508
-     * @throws EE_Error
2509
-     */
2510
-    protected function _default_event_settings_form(): EE_Form_Section_Proper
2511
-    {
2512
-        $registration_config              = EE_Registry::instance()->CFG->registration;
2513
-        $registration_stati_for_selection = EEM_Registration::reg_status_array(
2514
-        // exclude
2515
-            [
2516
-                EEM_Registration::status_id_cancelled,
2517
-                EEM_Registration::status_id_declined,
2518
-                EEM_Registration::status_id_incomplete,
2519
-                EEM_Registration::status_id_wait_list,
2520
-            ],
2521
-            true
2522
-        );
2523
-        // setup Advanced Editor ???
2524
-        if (
2525
-            $this->raw_req_action === 'default_event_settings'
2526
-            || $this->raw_req_action === 'update_default_event_settings'
2527
-        ) {
2528
-            $this->advanced_editor_admin_form = $this->loader->getShared(AdvancedEditorAdminFormSection::class);
2529
-        }
2530
-        return new EE_Form_Section_Proper(
2531
-            [
2532
-                'name'            => 'update_default_event_settings',
2533
-                'html_id'         => 'update_default_event_settings',
2534
-                'html_class'      => 'form-table',
2535
-                'layout_strategy' => new EE_Admin_Two_Column_Layout(),
2536
-                'subsections'     => apply_filters(
2537
-                    'FHEE__Events_Admin_Page___default_event_settings_form__form_subsections',
2538
-                    [
2539
-                        'defaults_section_header' => new EE_Form_Section_HTML(
2540
-                            EEH_HTML::h2(
2541
-                                esc_html__('Default Settings', 'event_espresso'),
2542
-                                '',
2543
-                                'ee-admin-settings-hdr'
2544
-                            )
2545
-                        ),
2546
-                        'default_reg_status'      => new EE_Select_Input(
2547
-                            $registration_stati_for_selection,
2548
-                            [
2549
-                                'default'         => isset($registration_config->default_STS_ID)
2550
-                                                     && array_key_exists(
2551
-                                                         $registration_config->default_STS_ID,
2552
-                                                         $registration_stati_for_selection
2553
-                                                     )
2554
-                                    ? sanitize_text_field($registration_config->default_STS_ID)
2555
-                                    : EEM_Registration::status_id_pending_payment,
2556
-                                'html_label_text' => esc_html__('Default Registration Status', 'event_espresso')
2557
-                                                     . EEH_Template::get_help_tab_link(
2558
-                                                         'default_settings_status_help_tab'
2559
-                                                     ),
2560
-                                'html_help_text'  => esc_html__(
2561
-                                    '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.',
2562
-                                    'event_espresso'
2563
-                                ),
2564
-                            ]
2565
-                        ),
2566
-                        'default_max_tickets'     => new EE_Integer_Input(
2567
-                            [
2568
-                                'default'         => $registration_config->default_maximum_number_of_tickets
2569
-                                                     ?? EEM_Event::get_default_additional_limit(),
2570
-                                'html_label_text' => esc_html__(
2571
-                                    'Default Maximum Tickets Allowed Per Order:',
2572
-                                    'event_espresso'
2573
-                                )
2574
-                                                     . EEH_Template::get_help_tab_link(
2575
-                                                         'default_maximum_tickets_help_tab"'
2576
-                                                     ),
2577
-                                'html_help_text'  => esc_html__(
2578
-                                    'This setting allows you to indicate what will be the default for the maximum number of tickets per order when creating new events.',
2579
-                                    'event_espresso'
2580
-                                ),
2581
-                            ]
2582
-                        ),
2583
-                    ]
2584
-                ),
2585
-            ]
2586
-        );
2587
-    }
2588
-
2589
-
2590
-    /**
2591
-     * @return void
2592
-     * @throws EE_Error
2593
-     * @throws InvalidArgumentException
2594
-     * @throws InvalidDataTypeException
2595
-     * @throws InvalidInterfaceException
2596
-     */
2597
-    protected function _update_default_event_settings()
2598
-    {
2599
-        $form = $this->_default_event_settings_form();
2600
-        if ($form->was_submitted()) {
2601
-            $form->receive_form_submission();
2602
-            if ($form->is_valid()) {
2603
-                $registration_config = EE_Registry::instance()->CFG->registration;
2604
-                $valid_data          = $form->valid_data();
2605
-                if (isset($valid_data['default_reg_status'])) {
2606
-                    $registration_config->default_STS_ID = $valid_data['default_reg_status'];
2607
-                }
2608
-                if (isset($valid_data['default_max_tickets'])) {
2609
-                    $registration_config->default_maximum_number_of_tickets = $valid_data['default_max_tickets'];
2610
-                }
2611
-                do_action(
2612
-                    'AHEE__Events_Admin_Page___update_default_event_settings',
2613
-                    $valid_data,
2614
-                    EE_Registry::instance()->CFG,
2615
-                    $this
2616
-                );
2617
-                // update because data was valid!
2618
-                EE_Registry::instance()->CFG->update_espresso_config();
2619
-                EE_Error::overwrite_success();
2620
-                EE_Error::add_success(
2621
-                    esc_html__('Default Event Settings were updated', 'event_espresso')
2622
-                );
2623
-            }
2624
-        }
2625
-        $this->_redirect_after_action(0, '', '', ['action' => 'default_event_settings'], true);
2626
-    }
2627
-
2628
-
2629
-    /*************        Templates        *************
2630
-     *
2631
-     * @throws EE_Error
2632
-     */
2633
-    protected function _template_settings()
2634
-    {
2635
-        $this->_admin_page_title              = esc_html__('Template Settings (Preview)', 'event_espresso');
2636
-        $this->_template_args['preview_img']  = '<img src="'
2637
-                                                . EVENTS_ASSETS_URL
2638
-                                                . '/images/'
2639
-                                                . 'caffeinated_template_features.jpg" alt="'
2640
-                                                . esc_attr__('Template Settings Preview screenshot', 'event_espresso')
2641
-                                                . '" />';
2642
-        $this->_template_args['preview_text'] = '<strong>'
2643
-                                                . esc_html__(
2644
-                                                    '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.',
2645
-                                                    'event_espresso'
2646
-                                                ) . '</strong>';
2647
-        $this->display_admin_caf_preview_page('template_settings_tab');
2648
-    }
2649
-
2650
-
2651
-    /** Event Category Stuff **/
2652
-    /**
2653
-     * set the _category property with the category object for the loaded page.
2654
-     *
2655
-     * @access private
2656
-     * @return void
2657
-     */
2658
-    private function _set_category_object()
2659
-    {
2660
-        if (isset($this->_category->id) && ! empty($this->_category->id)) {
2661
-            return;
2662
-        } //already have the category object so get out.
2663
-        // set default category object
2664
-        $this->_set_empty_category_object();
2665
-        // only set if we've got an id
2666
-        $category_ID = $this->request->getRequestParam('EVT_CAT_ID', 0, DataType::INT);
2667
-        if (! $category_ID) {
2668
-            return;
2669
-        }
2670
-        $term = get_term($category_ID, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY);
2671
-        if (! empty($term)) {
2672
-            $this->_category->category_name       = $term->name;
2673
-            $this->_category->category_identifier = $term->slug;
2674
-            $this->_category->category_desc       = $term->description;
2675
-            $this->_category->id                  = $term->term_id;
2676
-            $this->_category->parent              = $term->parent;
2677
-        }
2678
-    }
2679
-
2680
-
2681
-    /**
2682
-     * Clears out category properties.
2683
-     */
2684
-    private function _set_empty_category_object()
2685
-    {
2686
-        $this->_category                = new stdClass();
2687
-        $this->_category->category_name = $this->_category->category_identifier = $this->_category->category_desc = '';
2688
-        $this->_category->id            = $this->_category->parent = 0;
2689
-    }
2690
-
2691
-
2692
-    /**
2693
-     * @throws DomainException
2694
-     * @throws EE_Error
2695
-     * @throws InvalidArgumentException
2696
-     * @throws InvalidDataTypeException
2697
-     * @throws InvalidInterfaceException
2698
-     */
2699
-    protected function _category_list_table()
2700
-    {
2701
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2702
-        $this->_search_btn_label = esc_html__('Categories', 'event_espresso');
2703
-        $this->_admin_page_title .= ' ';
2704
-        $this->_admin_page_title .= $this->get_action_link_or_button(
2705
-            'add_category',
2706
-            'add_category',
2707
-            [],
2708
-            'add-new-h2'
2709
-        );
2710
-        $this->display_admin_list_table_page_with_sidebar();
2711
-    }
2712
-
2713
-
2714
-    /**
2715
-     * Output category details view.
2716
-     *
2717
-     * @throws EE_Error
2718
-     * @throws EE_Error
2719
-     */
2720
-    protected function _category_details($view)
2721
-    {
2722
-        $route = $view === 'edit' ? 'update_category' : 'insert_category';
2723
-        $this->_set_add_edit_form_tags($route);
2724
-        $this->_set_category_object();
2725
-        $id            = ! empty($this->_category->id) ? $this->_category->id : '';
2726
-        $delete_action = 'delete_category';
2727
-        // custom redirect
2728
-        $redirect = EE_Admin_Page::add_query_args_and_nonce(
2729
-            ['action' => 'category_list'],
2730
-            $this->_admin_base_url
2731
-        );
2732
-        $this->_set_publish_post_box_vars('EVT_CAT_ID', $id, $delete_action, $redirect, true);
2733
-        // take care of contents
2734
-        $this->_template_args['admin_page_content'] = $this->_category_details_content();
2735
-        $this->display_admin_page_with_sidebar();
2736
-    }
2737
-
2738
-
2739
-    /**
2740
-     * Output category details content.
2741
-     *
2742
-     * @throws DomainException
2743
-     */
2744
-    protected function _category_details_content(): string
2745
-    {
2746
-        $editor_args['category_desc'] = [
2747
-            'type'          => 'wp_editor',
2748
-            'value'         => EEH_Formatter::admin_format_content($this->_category->category_desc),
2749
-            'class'         => 'my_editor_custom',
2750
-            'wpeditor_args' => ['media_buttons' => false],
2751
-        ];
2752
-        $_wp_editor                   = $this->_generate_admin_form_fields($editor_args, 'array');
2753
-        $all_terms                    = get_terms(
2754
-            [EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY],
2755
-            ['hide_empty' => 0, 'exclude' => [$this->_category->id]]
2756
-        );
2757
-        // setup category select for term parents.
2758
-        $category_select_values[] = [
2759
-            'text' => esc_html__('No Parent', 'event_espresso'),
2760
-            'id'   => 0,
2761
-        ];
2762
-        foreach ($all_terms as $term) {
2763
-            $category_select_values[] = [
2764
-                'text' => $term->name,
2765
-                'id'   => $term->term_id,
2766
-            ];
2767
-        }
2768
-        $category_select = EEH_Form_Fields::select_input(
2769
-            'category_parent',
2770
-            $category_select_values,
2771
-            $this->_category->parent
2772
-        );
2773
-        $template_args   = [
2774
-            'category'                 => $this->_category,
2775
-            'category_select'          => $category_select,
2776
-            'unique_id_info_help_link' => $this->_get_help_tab_link('unique_id_info'),
2777
-            'category_desc_editor'     => $_wp_editor['category_desc']['field'],
2778
-            'disable'                  => '',
2779
-            'disabled_message'         => false,
2780
-        ];
2781
-        $template        = EVENTS_TEMPLATE_PATH . 'event_category_details.template.php';
2782
-        return EEH_Template::display_template($template, $template_args, true);
2783
-    }
2784
-
2785
-
2786
-    /**
2787
-     * Handles deleting categories.
2788
-     *
2789
-     * @throws EE_Error
2790
-     */
2791
-    protected function _delete_categories()
2792
-    {
2793
-        $category_IDs = $this->request->getRequestParam('EVT_CAT_ID', 0, 'int', true);
2794
-        foreach ($category_IDs as $category_ID) {
2795
-            $this->_delete_category($category_ID);
2796
-        }
2797
-        // doesn't matter what page we're coming from... we're going to the same place after delete.
2798
-        $query_args = [
2799
-            'action' => 'category_list',
2800
-        ];
2801
-        $this->_redirect_after_action(0, '', '', $query_args);
2802
-    }
2803
-
2804
-
2805
-    /**
2806
-     * Handles deleting specific category.
2807
-     *
2808
-     * @param int $cat_id
2809
-     */
2810
-    protected function _delete_category(int $cat_id)
2811
-    {
2812
-        $cat_id = absint($cat_id);
2813
-        wp_delete_term($cat_id, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY);
2814
-    }
2815
-
2816
-
2817
-    /**
2818
-     * Handles triggering the update or insertion of a new category.
2819
-     *
2820
-     * @param bool $new_category true means we're triggering the insert of a new category.
2821
-     * @throws EE_Error
2822
-     * @throws EE_Error
2823
-     */
2824
-    protected function _insert_or_update_category(bool $new_category)
2825
-    {
2826
-        $cat_id  = $this->_insert_category($new_category);
2827
-        $success = 0; // we already have a success message so lets not send another.
2828
-        if ($cat_id) {
2829
-            $query_args = [
2830
-                'action'     => 'edit_category',
2831
-                'EVT_CAT_ID' => $cat_id,
2832
-            ];
2833
-        } else {
2834
-            $query_args = ['action' => 'add_category'];
2835
-        }
2836
-        $this->_redirect_after_action($success, '', '', $query_args, true);
2837
-    }
2838
-
2839
-
2840
-    /**
2841
-     * Inserts or updates category
2842
-     *
2843
-     * @param bool $new_category (true indicates we're updating a category).
2844
-     * @return bool|mixed|string
2845
-     */
2846
-    private function _insert_category(bool $new_category)
2847
-    {
2848
-        $category_ID         = $this->request->getRequestParam('EVT_CAT_ID', 0, DataType::INT);
2849
-        $category_name       = $this->request->getRequestParam('category_name', '');
2850
-        $category_desc       = $this->request->getRequestParam('category_desc', '', DataType::HTML);
2851
-        $category_parent     = $this->request->getRequestParam('category_parent', 0, DataType::INT);
2852
-        $category_identifier = $this->request->getRequestParam('category_identifier', '');
2853
-
2854
-        if (empty($category_name)) {
2855
-            $msg = esc_html__('You must add a name for the category.', 'event_espresso');
2856
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2857
-            return 0;
2858
-        }
2859
-        $term_args = [
2860
-            'name'        => $category_name,
2861
-            'description' => $category_desc,
2862
-            'parent'      => $category_parent,
2863
-        ];
2864
-        // was the category_identifier input disabled?
2865
-        if ($category_identifier) {
2866
-            $term_args['slug'] = $category_identifier;
2867
-        }
2868
-        $insert_ids = $new_category
2869
-            ? wp_insert_term($category_name, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY, $term_args)
2870
-            : wp_update_term($category_ID, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY, $term_args);
2871
-
2872
-        if ($insert_ids instanceof WP_Error) {
2873
-            EE_Error::add_error($insert_ids->get_error_message(), __FILE__, __FUNCTION__, __LINE__);
2874
-            return 0;
2875
-        }
2876
-        $category_ID = $insert_ids['term_id'] ?? 0;
2877
-        if (! $category_ID) {
2878
-            EE_Error::add_error(
2879
-                esc_html__(
2880
-                    'An error occurred and the category has not been saved to the database.',
2881
-                    'event_espresso'
2882
-                ),
2883
-                __FILE__,
2884
-                __FUNCTION__,
2885
-                __LINE__
2886
-            );
2887
-            return 0;
2888
-        }
2889
-        EE_Error::add_success(
2890
-            sprintf(
2891
-                esc_html__('The category %s was successfully saved', 'event_espresso'),
2892
-                $category_name
2893
-            )
2894
-        );
2895
-        return $category_ID;
2896
-    }
2897
-
2898
-
2899
-    /**
2900
-     * Gets categories or count of categories matching the arguments in the request.
2901
-     *
2902
-     * @param int  $per_page
2903
-     * @param int  $current_page
2904
-     * @param bool $count
2905
-     * @return EE_Term_Taxonomy[]|int
2906
-     * @throws EE_Error
2907
-     * @throws ReflectionException
2908
-     */
2909
-    public function get_categories(int $per_page = 10, int $current_page = 1, bool $count = false)
2910
-    {
2911
-        // testing term stuff
2912
-        $orderby     = $this->request->getRequestParam('orderby', 'Term.term_id');
2913
-        $order       = $this->request->getRequestParam('order', 'DESC');
2914
-        $limit       = ($current_page - 1) * $per_page;
2915
-        $where       = ['taxonomy' => EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY];
2916
-        $search_term = $this->request->getRequestParam('s');
2917
-        if ($search_term) {
2918
-            $search_term = '%' . $search_term . '%';
2919
-            $where['OR'] = [
2920
-                'Term.name'   => ['LIKE', $search_term],
2921
-                'description' => ['LIKE', $search_term],
2922
-            ];
2923
-        }
2924
-        $query_params = [
2925
-            $where,
2926
-            'order_by'   => [$orderby => $order],
2927
-            'limit'      => $limit . ',' . $per_page,
2928
-            'force_join' => ['Term'],
2929
-        ];
2930
-        return $count
2931
-            ? EEM_Term_Taxonomy::instance()->count($query_params, 'term_id')
2932
-            : EEM_Term_Taxonomy::instance()->get_all($query_params);
2933
-    }
2934
-
2935
-    /* end category stuff */
2936
-
2937
-
2938
-    /**************/
2939
-
2940
-
2941
-    /**
2942
-     * Callback for the `ee_save_timezone_setting` ajax action.
2943
-     *
2944
-     * @throws EE_Error
2945
-     * @throws InvalidArgumentException
2946
-     * @throws InvalidDataTypeException
2947
-     * @throws InvalidInterfaceException
2948
-     */
2949
-    public function saveTimezoneString()
2950
-    {
2951
-        $timezone_string = $this->request->getRequestParam('timezone_selected');
2952
-        if (empty($timezone_string) || ! EEH_DTT_Helper::validate_timezone($timezone_string, false)) {
2953
-            EE_Error::add_error(
2954
-                esc_html__('An invalid timezone string submitted.', 'event_espresso'),
2955
-                __FILE__,
2956
-                __FUNCTION__,
2957
-                __LINE__
2958
-            );
2959
-            $this->_template_args['error'] = true;
2960
-            $this->_return_json();
2961
-        }
2962
-
2963
-        update_option('timezone_string', $timezone_string);
2964
-        EE_Error::add_success(
2965
-            esc_html__('Your timezone string was updated.', 'event_espresso')
2966
-        );
2967
-        $this->_template_args['success'] = true;
2968
-        $this->_return_json(true, ['action' => 'create_new']);
2969
-    }
2970
-
2971
-
2972
-    /**
2973 2631
      * @throws EE_Error
2974
-     * @deprecated 4.10.25.p
2975 2632
      */
2976
-    public function save_timezonestring_setting()
2977
-    {
2978
-        $this->saveTimezoneString();
2979
-    }
2633
+	protected function _template_settings()
2634
+	{
2635
+		$this->_admin_page_title              = esc_html__('Template Settings (Preview)', 'event_espresso');
2636
+		$this->_template_args['preview_img']  = '<img src="'
2637
+												. EVENTS_ASSETS_URL
2638
+												. '/images/'
2639
+												. 'caffeinated_template_features.jpg" alt="'
2640
+												. esc_attr__('Template Settings Preview screenshot', 'event_espresso')
2641
+												. '" />';
2642
+		$this->_template_args['preview_text'] = '<strong>'
2643
+												. esc_html__(
2644
+													'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.',
2645
+													'event_espresso'
2646
+												) . '</strong>';
2647
+		$this->display_admin_caf_preview_page('template_settings_tab');
2648
+	}
2649
+
2650
+
2651
+	/** Event Category Stuff **/
2652
+	/**
2653
+	 * set the _category property with the category object for the loaded page.
2654
+	 *
2655
+	 * @access private
2656
+	 * @return void
2657
+	 */
2658
+	private function _set_category_object()
2659
+	{
2660
+		if (isset($this->_category->id) && ! empty($this->_category->id)) {
2661
+			return;
2662
+		} //already have the category object so get out.
2663
+		// set default category object
2664
+		$this->_set_empty_category_object();
2665
+		// only set if we've got an id
2666
+		$category_ID = $this->request->getRequestParam('EVT_CAT_ID', 0, DataType::INT);
2667
+		if (! $category_ID) {
2668
+			return;
2669
+		}
2670
+		$term = get_term($category_ID, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY);
2671
+		if (! empty($term)) {
2672
+			$this->_category->category_name       = $term->name;
2673
+			$this->_category->category_identifier = $term->slug;
2674
+			$this->_category->category_desc       = $term->description;
2675
+			$this->_category->id                  = $term->term_id;
2676
+			$this->_category->parent              = $term->parent;
2677
+		}
2678
+	}
2679
+
2680
+
2681
+	/**
2682
+	 * Clears out category properties.
2683
+	 */
2684
+	private function _set_empty_category_object()
2685
+	{
2686
+		$this->_category                = new stdClass();
2687
+		$this->_category->category_name = $this->_category->category_identifier = $this->_category->category_desc = '';
2688
+		$this->_category->id            = $this->_category->parent = 0;
2689
+	}
2690
+
2691
+
2692
+	/**
2693
+	 * @throws DomainException
2694
+	 * @throws EE_Error
2695
+	 * @throws InvalidArgumentException
2696
+	 * @throws InvalidDataTypeException
2697
+	 * @throws InvalidInterfaceException
2698
+	 */
2699
+	protected function _category_list_table()
2700
+	{
2701
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2702
+		$this->_search_btn_label = esc_html__('Categories', 'event_espresso');
2703
+		$this->_admin_page_title .= ' ';
2704
+		$this->_admin_page_title .= $this->get_action_link_or_button(
2705
+			'add_category',
2706
+			'add_category',
2707
+			[],
2708
+			'add-new-h2'
2709
+		);
2710
+		$this->display_admin_list_table_page_with_sidebar();
2711
+	}
2712
+
2713
+
2714
+	/**
2715
+	 * Output category details view.
2716
+	 *
2717
+	 * @throws EE_Error
2718
+	 * @throws EE_Error
2719
+	 */
2720
+	protected function _category_details($view)
2721
+	{
2722
+		$route = $view === 'edit' ? 'update_category' : 'insert_category';
2723
+		$this->_set_add_edit_form_tags($route);
2724
+		$this->_set_category_object();
2725
+		$id            = ! empty($this->_category->id) ? $this->_category->id : '';
2726
+		$delete_action = 'delete_category';
2727
+		// custom redirect
2728
+		$redirect = EE_Admin_Page::add_query_args_and_nonce(
2729
+			['action' => 'category_list'],
2730
+			$this->_admin_base_url
2731
+		);
2732
+		$this->_set_publish_post_box_vars('EVT_CAT_ID', $id, $delete_action, $redirect, true);
2733
+		// take care of contents
2734
+		$this->_template_args['admin_page_content'] = $this->_category_details_content();
2735
+		$this->display_admin_page_with_sidebar();
2736
+	}
2737
+
2738
+
2739
+	/**
2740
+	 * Output category details content.
2741
+	 *
2742
+	 * @throws DomainException
2743
+	 */
2744
+	protected function _category_details_content(): string
2745
+	{
2746
+		$editor_args['category_desc'] = [
2747
+			'type'          => 'wp_editor',
2748
+			'value'         => EEH_Formatter::admin_format_content($this->_category->category_desc),
2749
+			'class'         => 'my_editor_custom',
2750
+			'wpeditor_args' => ['media_buttons' => false],
2751
+		];
2752
+		$_wp_editor                   = $this->_generate_admin_form_fields($editor_args, 'array');
2753
+		$all_terms                    = get_terms(
2754
+			[EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY],
2755
+			['hide_empty' => 0, 'exclude' => [$this->_category->id]]
2756
+		);
2757
+		// setup category select for term parents.
2758
+		$category_select_values[] = [
2759
+			'text' => esc_html__('No Parent', 'event_espresso'),
2760
+			'id'   => 0,
2761
+		];
2762
+		foreach ($all_terms as $term) {
2763
+			$category_select_values[] = [
2764
+				'text' => $term->name,
2765
+				'id'   => $term->term_id,
2766
+			];
2767
+		}
2768
+		$category_select = EEH_Form_Fields::select_input(
2769
+			'category_parent',
2770
+			$category_select_values,
2771
+			$this->_category->parent
2772
+		);
2773
+		$template_args   = [
2774
+			'category'                 => $this->_category,
2775
+			'category_select'          => $category_select,
2776
+			'unique_id_info_help_link' => $this->_get_help_tab_link('unique_id_info'),
2777
+			'category_desc_editor'     => $_wp_editor['category_desc']['field'],
2778
+			'disable'                  => '',
2779
+			'disabled_message'         => false,
2780
+		];
2781
+		$template        = EVENTS_TEMPLATE_PATH . 'event_category_details.template.php';
2782
+		return EEH_Template::display_template($template, $template_args, true);
2783
+	}
2784
+
2785
+
2786
+	/**
2787
+	 * Handles deleting categories.
2788
+	 *
2789
+	 * @throws EE_Error
2790
+	 */
2791
+	protected function _delete_categories()
2792
+	{
2793
+		$category_IDs = $this->request->getRequestParam('EVT_CAT_ID', 0, 'int', true);
2794
+		foreach ($category_IDs as $category_ID) {
2795
+			$this->_delete_category($category_ID);
2796
+		}
2797
+		// doesn't matter what page we're coming from... we're going to the same place after delete.
2798
+		$query_args = [
2799
+			'action' => 'category_list',
2800
+		];
2801
+		$this->_redirect_after_action(0, '', '', $query_args);
2802
+	}
2803
+
2804
+
2805
+	/**
2806
+	 * Handles deleting specific category.
2807
+	 *
2808
+	 * @param int $cat_id
2809
+	 */
2810
+	protected function _delete_category(int $cat_id)
2811
+	{
2812
+		$cat_id = absint($cat_id);
2813
+		wp_delete_term($cat_id, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY);
2814
+	}
2815
+
2816
+
2817
+	/**
2818
+	 * Handles triggering the update or insertion of a new category.
2819
+	 *
2820
+	 * @param bool $new_category true means we're triggering the insert of a new category.
2821
+	 * @throws EE_Error
2822
+	 * @throws EE_Error
2823
+	 */
2824
+	protected function _insert_or_update_category(bool $new_category)
2825
+	{
2826
+		$cat_id  = $this->_insert_category($new_category);
2827
+		$success = 0; // we already have a success message so lets not send another.
2828
+		if ($cat_id) {
2829
+			$query_args = [
2830
+				'action'     => 'edit_category',
2831
+				'EVT_CAT_ID' => $cat_id,
2832
+			];
2833
+		} else {
2834
+			$query_args = ['action' => 'add_category'];
2835
+		}
2836
+		$this->_redirect_after_action($success, '', '', $query_args, true);
2837
+	}
2838
+
2839
+
2840
+	/**
2841
+	 * Inserts or updates category
2842
+	 *
2843
+	 * @param bool $new_category (true indicates we're updating a category).
2844
+	 * @return bool|mixed|string
2845
+	 */
2846
+	private function _insert_category(bool $new_category)
2847
+	{
2848
+		$category_ID         = $this->request->getRequestParam('EVT_CAT_ID', 0, DataType::INT);
2849
+		$category_name       = $this->request->getRequestParam('category_name', '');
2850
+		$category_desc       = $this->request->getRequestParam('category_desc', '', DataType::HTML);
2851
+		$category_parent     = $this->request->getRequestParam('category_parent', 0, DataType::INT);
2852
+		$category_identifier = $this->request->getRequestParam('category_identifier', '');
2853
+
2854
+		if (empty($category_name)) {
2855
+			$msg = esc_html__('You must add a name for the category.', 'event_espresso');
2856
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2857
+			return 0;
2858
+		}
2859
+		$term_args = [
2860
+			'name'        => $category_name,
2861
+			'description' => $category_desc,
2862
+			'parent'      => $category_parent,
2863
+		];
2864
+		// was the category_identifier input disabled?
2865
+		if ($category_identifier) {
2866
+			$term_args['slug'] = $category_identifier;
2867
+		}
2868
+		$insert_ids = $new_category
2869
+			? wp_insert_term($category_name, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY, $term_args)
2870
+			: wp_update_term($category_ID, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY, $term_args);
2871
+
2872
+		if ($insert_ids instanceof WP_Error) {
2873
+			EE_Error::add_error($insert_ids->get_error_message(), __FILE__, __FUNCTION__, __LINE__);
2874
+			return 0;
2875
+		}
2876
+		$category_ID = $insert_ids['term_id'] ?? 0;
2877
+		if (! $category_ID) {
2878
+			EE_Error::add_error(
2879
+				esc_html__(
2880
+					'An error occurred and the category has not been saved to the database.',
2881
+					'event_espresso'
2882
+				),
2883
+				__FILE__,
2884
+				__FUNCTION__,
2885
+				__LINE__
2886
+			);
2887
+			return 0;
2888
+		}
2889
+		EE_Error::add_success(
2890
+			sprintf(
2891
+				esc_html__('The category %s was successfully saved', 'event_espresso'),
2892
+				$category_name
2893
+			)
2894
+		);
2895
+		return $category_ID;
2896
+	}
2897
+
2898
+
2899
+	/**
2900
+	 * Gets categories or count of categories matching the arguments in the request.
2901
+	 *
2902
+	 * @param int  $per_page
2903
+	 * @param int  $current_page
2904
+	 * @param bool $count
2905
+	 * @return EE_Term_Taxonomy[]|int
2906
+	 * @throws EE_Error
2907
+	 * @throws ReflectionException
2908
+	 */
2909
+	public function get_categories(int $per_page = 10, int $current_page = 1, bool $count = false)
2910
+	{
2911
+		// testing term stuff
2912
+		$orderby     = $this->request->getRequestParam('orderby', 'Term.term_id');
2913
+		$order       = $this->request->getRequestParam('order', 'DESC');
2914
+		$limit       = ($current_page - 1) * $per_page;
2915
+		$where       = ['taxonomy' => EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY];
2916
+		$search_term = $this->request->getRequestParam('s');
2917
+		if ($search_term) {
2918
+			$search_term = '%' . $search_term . '%';
2919
+			$where['OR'] = [
2920
+				'Term.name'   => ['LIKE', $search_term],
2921
+				'description' => ['LIKE', $search_term],
2922
+			];
2923
+		}
2924
+		$query_params = [
2925
+			$where,
2926
+			'order_by'   => [$orderby => $order],
2927
+			'limit'      => $limit . ',' . $per_page,
2928
+			'force_join' => ['Term'],
2929
+		];
2930
+		return $count
2931
+			? EEM_Term_Taxonomy::instance()->count($query_params, 'term_id')
2932
+			: EEM_Term_Taxonomy::instance()->get_all($query_params);
2933
+	}
2934
+
2935
+	/* end category stuff */
2936
+
2937
+
2938
+	/**************/
2939
+
2940
+
2941
+	/**
2942
+	 * Callback for the `ee_save_timezone_setting` ajax action.
2943
+	 *
2944
+	 * @throws EE_Error
2945
+	 * @throws InvalidArgumentException
2946
+	 * @throws InvalidDataTypeException
2947
+	 * @throws InvalidInterfaceException
2948
+	 */
2949
+	public function saveTimezoneString()
2950
+	{
2951
+		$timezone_string = $this->request->getRequestParam('timezone_selected');
2952
+		if (empty($timezone_string) || ! EEH_DTT_Helper::validate_timezone($timezone_string, false)) {
2953
+			EE_Error::add_error(
2954
+				esc_html__('An invalid timezone string submitted.', 'event_espresso'),
2955
+				__FILE__,
2956
+				__FUNCTION__,
2957
+				__LINE__
2958
+			);
2959
+			$this->_template_args['error'] = true;
2960
+			$this->_return_json();
2961
+		}
2962
+
2963
+		update_option('timezone_string', $timezone_string);
2964
+		EE_Error::add_success(
2965
+			esc_html__('Your timezone string was updated.', 'event_espresso')
2966
+		);
2967
+		$this->_template_args['success'] = true;
2968
+		$this->_return_json(true, ['action' => 'create_new']);
2969
+	}
2970
+
2971
+
2972
+	/**
2973
+	 * @throws EE_Error
2974
+	 * @deprecated 4.10.25.p
2975
+	 */
2976
+	public function save_timezonestring_setting()
2977
+	{
2978
+		$this->saveTimezoneString();
2979
+	}
2980 2980
 }
Please login to merge, or discard this patch.
admin_pages/registrations/EE_Attendee_Contact_List_Table.class.php 1 patch
Indentation   +386 added lines, -386 removed lines patch added patch discarded remove patch
@@ -12,412 +12,412 @@
 block discarded – undo
12 12
  */
13 13
 class EE_Attendee_Contact_List_Table extends EE_Admin_List_Table
14 14
 {
15
-    /**
16
-     * @var Registrations_Admin_Page
17
-     */
18
-    protected $_admin_page;
19
-
20
-
21
-    /**
22
-     * Initial setup of data (called by parent).
23
-     *
24
-     * @throws EE_Error
25
-     */
26
-    protected function _setup_data()
27
-    {
28
-        $this->_data = $this->_view !== 'trash'
29
-            ? $this->_admin_page->get_attendees($this->_per_page)
30
-            : $this->_admin_page->get_attendees($this->_per_page, false, true);
31
-
32
-        $this->_all_data_count = $this->_view !== 'trash'
33
-            ? $this->_admin_page->get_attendees($this->_per_page, true)
34
-            : $this->_admin_page->get_attendees($this->_per_page, true, true);
35
-    }
36
-
37
-
38
-    /**
39
-     * Initial setup of properties.
40
-     */
41
-    protected function _set_properties()
42
-    {
43
-        $this->_wp_list_args = [
44
-            'singular' => esc_html__('attendee', 'event_espresso'),
45
-            'plural'   => esc_html__('attendees', 'event_espresso'),
46
-            'ajax'     => true,
47
-            'screen'   => $this->_admin_page->get_current_screen()->id,
48
-        ];
49
-
50
-        $this->_columns = [
51
-            'cb'                 => '<input type="checkbox" />', // Render a checkbox instead of text
52
-            'id'                 => esc_html__('ID', 'event_espresso'),
53
-            'ATT_fname'          => esc_html__('First Name', 'event_espresso'),
54
-            'ATT_lname'          => esc_html__('Last Name', 'event_espresso'),
55
-            'ATT_email'          => esc_html__('Email Address', 'event_espresso'),
56
-            'Registration_Count' => esc_html__('# Reg', 'event_espresso'),
57
-            'ATT_phone'          => esc_html__('Phone', 'event_espresso'),
58
-            'ATT_address'        => esc_html__('Address', 'event_espresso'),
59
-            'ATT_city'           => esc_html__('City', 'event_espresso'),
60
-            'STA_ID'             => esc_html__('State/Province', 'event_espresso'),
61
-            'CNT_ISO'            => esc_html__('Country', 'event_espresso'),
62
-        ];
63
-
64
-        $this->_sortable_columns = [
65
-            'id'                 => ['id' => false],
66
-            'ATT_lname'          => ['ATT_lname' => true], // true means its already sorted
67
-            'ATT_fname'          => ['ATT_fname' => false],
68
-            'ATT_email'          => ['ATT_email' => false],
69
-            'Registration_Count' => ['Registration_Count' => false],
70
-            'ATT_city'           => ['ATT_city' => false],
71
-            'STA_ID'             => ['STA_ID' => false],
72
-            'CNT_ISO'            => ['CNT_ISO' => false],
73
-        ];
74
-
75
-        $this->_hidden_columns = [
76
-            'ATT_phone',
77
-            'ATT_address',
78
-            'ATT_city',
79
-            'STA_ID',
80
-            'CNT_ISO',
81
-        ];
82
-    }
83
-
84
-
85
-    /**
86
-     * Initial setup of filters
87
-     *
88
-     * @return array
89
-     */
90
-    protected function _get_table_filters()
91
-    {
92
-        return [];
93
-    }
94
-
95
-
96
-    /**
97
-     * Initial setup of counts for views
98
-     *
99
-     * @throws InvalidArgumentException
100
-     * @throws InvalidDataTypeException
101
-     * @throws InvalidInterfaceException
102
-     * @throws EE_Error
103
-     * @throws EE_Error
104
-     */
105
-    protected function _add_view_counts()
106
-    {
107
-        $this->_views['in_use']['count'] = $this->_admin_page->get_attendees($this->_per_page, true);
108
-        if (
109
-            EE_Registry::instance()->CAP->current_user_can(
110
-                'ee_delete_contacts',
111
-                'espresso_registrations_delete_registration'
112
-            )
113
-        ) {
114
-            $this->_views['trash']['count'] = $this->_admin_page->get_attendees($this->_per_page, true, true);
115
-        }
116
-    }
117
-
118
-
119
-    /**
120
-     * Get count of attendees.
121
-     *
122
-     * @return int
123
-     * @throws EE_Error
124
-     * @throws InvalidArgumentException
125
-     * @throws InvalidDataTypeException
126
-     * @throws InvalidInterfaceException
127
-     * @throws ReflectionException
128
-     */
129
-    protected function _get_attendees_count(): int
130
-    {
131
-        return EEM_Attendee::instance()->count();
132
-    }
133
-
134
-
135
-    /**
136
-     * Checkbox column
137
-     *
138
-     * @param EE_Attendee $item Unable to typehint this method because overrides parent.
139
-     * @return string
140
-     * @throws EE_Error
141
-     * @throws ReflectionException
142
-     */
143
-    public function column_cb($item): string
144
-    {
145
-        if (! $item instanceof EE_Attendee) {
146
-            return '';
147
-        }
148
-        return sprintf(
149
-            '<input type="checkbox" name="checkbox[%1$s]" value="%1$s" />',
150
-            $item->ID()
151
-        );
152
-    }
153
-
154
-
155
-    /**
156
-     * @param EE_Attendee|null $attendee
157
-     * @return string
158
-     * @throws EE_Error
159
-     * @throws ReflectionException
160
-     */
161
-    public function column_id(?EE_Attendee $attendee): string
162
-    {
163
-        $content = '
15
+	/**
16
+	 * @var Registrations_Admin_Page
17
+	 */
18
+	protected $_admin_page;
19
+
20
+
21
+	/**
22
+	 * Initial setup of data (called by parent).
23
+	 *
24
+	 * @throws EE_Error
25
+	 */
26
+	protected function _setup_data()
27
+	{
28
+		$this->_data = $this->_view !== 'trash'
29
+			? $this->_admin_page->get_attendees($this->_per_page)
30
+			: $this->_admin_page->get_attendees($this->_per_page, false, true);
31
+
32
+		$this->_all_data_count = $this->_view !== 'trash'
33
+			? $this->_admin_page->get_attendees($this->_per_page, true)
34
+			: $this->_admin_page->get_attendees($this->_per_page, true, true);
35
+	}
36
+
37
+
38
+	/**
39
+	 * Initial setup of properties.
40
+	 */
41
+	protected function _set_properties()
42
+	{
43
+		$this->_wp_list_args = [
44
+			'singular' => esc_html__('attendee', 'event_espresso'),
45
+			'plural'   => esc_html__('attendees', 'event_espresso'),
46
+			'ajax'     => true,
47
+			'screen'   => $this->_admin_page->get_current_screen()->id,
48
+		];
49
+
50
+		$this->_columns = [
51
+			'cb'                 => '<input type="checkbox" />', // Render a checkbox instead of text
52
+			'id'                 => esc_html__('ID', 'event_espresso'),
53
+			'ATT_fname'          => esc_html__('First Name', 'event_espresso'),
54
+			'ATT_lname'          => esc_html__('Last Name', 'event_espresso'),
55
+			'ATT_email'          => esc_html__('Email Address', 'event_espresso'),
56
+			'Registration_Count' => esc_html__('# Reg', 'event_espresso'),
57
+			'ATT_phone'          => esc_html__('Phone', 'event_espresso'),
58
+			'ATT_address'        => esc_html__('Address', 'event_espresso'),
59
+			'ATT_city'           => esc_html__('City', 'event_espresso'),
60
+			'STA_ID'             => esc_html__('State/Province', 'event_espresso'),
61
+			'CNT_ISO'            => esc_html__('Country', 'event_espresso'),
62
+		];
63
+
64
+		$this->_sortable_columns = [
65
+			'id'                 => ['id' => false],
66
+			'ATT_lname'          => ['ATT_lname' => true], // true means its already sorted
67
+			'ATT_fname'          => ['ATT_fname' => false],
68
+			'ATT_email'          => ['ATT_email' => false],
69
+			'Registration_Count' => ['Registration_Count' => false],
70
+			'ATT_city'           => ['ATT_city' => false],
71
+			'STA_ID'             => ['STA_ID' => false],
72
+			'CNT_ISO'            => ['CNT_ISO' => false],
73
+		];
74
+
75
+		$this->_hidden_columns = [
76
+			'ATT_phone',
77
+			'ATT_address',
78
+			'ATT_city',
79
+			'STA_ID',
80
+			'CNT_ISO',
81
+		];
82
+	}
83
+
84
+
85
+	/**
86
+	 * Initial setup of filters
87
+	 *
88
+	 * @return array
89
+	 */
90
+	protected function _get_table_filters()
91
+	{
92
+		return [];
93
+	}
94
+
95
+
96
+	/**
97
+	 * Initial setup of counts for views
98
+	 *
99
+	 * @throws InvalidArgumentException
100
+	 * @throws InvalidDataTypeException
101
+	 * @throws InvalidInterfaceException
102
+	 * @throws EE_Error
103
+	 * @throws EE_Error
104
+	 */
105
+	protected function _add_view_counts()
106
+	{
107
+		$this->_views['in_use']['count'] = $this->_admin_page->get_attendees($this->_per_page, true);
108
+		if (
109
+			EE_Registry::instance()->CAP->current_user_can(
110
+				'ee_delete_contacts',
111
+				'espresso_registrations_delete_registration'
112
+			)
113
+		) {
114
+			$this->_views['trash']['count'] = $this->_admin_page->get_attendees($this->_per_page, true, true);
115
+		}
116
+	}
117
+
118
+
119
+	/**
120
+	 * Get count of attendees.
121
+	 *
122
+	 * @return int
123
+	 * @throws EE_Error
124
+	 * @throws InvalidArgumentException
125
+	 * @throws InvalidDataTypeException
126
+	 * @throws InvalidInterfaceException
127
+	 * @throws ReflectionException
128
+	 */
129
+	protected function _get_attendees_count(): int
130
+	{
131
+		return EEM_Attendee::instance()->count();
132
+	}
133
+
134
+
135
+	/**
136
+	 * Checkbox column
137
+	 *
138
+	 * @param EE_Attendee $item Unable to typehint this method because overrides parent.
139
+	 * @return string
140
+	 * @throws EE_Error
141
+	 * @throws ReflectionException
142
+	 */
143
+	public function column_cb($item): string
144
+	{
145
+		if (! $item instanceof EE_Attendee) {
146
+			return '';
147
+		}
148
+		return sprintf(
149
+			'<input type="checkbox" name="checkbox[%1$s]" value="%1$s" />',
150
+			$item->ID()
151
+		);
152
+	}
153
+
154
+
155
+	/**
156
+	 * @param EE_Attendee|null $attendee
157
+	 * @return string
158
+	 * @throws EE_Error
159
+	 * @throws ReflectionException
160
+	 */
161
+	public function column_id(?EE_Attendee $attendee): string
162
+	{
163
+		$content = '
164 164
             <span class="ee-entity-id">' . $attendee->ID() . '</span>
165 165
             <span class="show-on-mobile-view-only">
166 166
                 ' . $this->editAttendeeLink($attendee->ID(), $attendee->full_name()) . '
167 167
             </span>';
168
-        return $this->columnContent('id', $content, 'end');
169
-    }
170
-
171
-
172
-    /**
173
-     * ATT_lname column
174
-     *
175
-     * @param EE_Attendee $attendee
176
-     * @return string
177
-     * @throws EE_Error
178
-     * @throws ReflectionException
179
-     */
180
-    public function column_ATT_lname(EE_Attendee $attendee): string
181
-    {
182
-        // edit attendee link
183
-        $content = $this->editAttendeeLink($attendee->ID(), $attendee->lname());
184
-        return $this->columnContent('ATT_lname', $content);
185
-    }
186
-
187
-
188
-    /**
189
-     * @param int    $ID
190
-     * @param string $attendee_name
191
-     * @return string
192
-     * @since   5.0.0.p
193
-     */
194
-    private function editAttendeeLink(int $ID, string $attendee_name): string
195
-    {
196
-        $edit_lnk_url = EE_Admin_Page::add_query_args_and_nonce(
197
-            [
198
-                'action' => 'edit_attendee',
199
-                'post'   => $ID,
200
-            ],
201
-            REG_ADMIN_URL
202
-        );
203
-        return EE_Registry::instance()->CAP->current_user_can(
204
-            'ee_edit_contacts',
205
-            'espresso_registrations_edit_attendee'
206
-        )
207
-            ? '
168
+		return $this->columnContent('id', $content, 'end');
169
+	}
170
+
171
+
172
+	/**
173
+	 * ATT_lname column
174
+	 *
175
+	 * @param EE_Attendee $attendee
176
+	 * @return string
177
+	 * @throws EE_Error
178
+	 * @throws ReflectionException
179
+	 */
180
+	public function column_ATT_lname(EE_Attendee $attendee): string
181
+	{
182
+		// edit attendee link
183
+		$content = $this->editAttendeeLink($attendee->ID(), $attendee->lname());
184
+		return $this->columnContent('ATT_lname', $content);
185
+	}
186
+
187
+
188
+	/**
189
+	 * @param int    $ID
190
+	 * @param string $attendee_name
191
+	 * @return string
192
+	 * @since   5.0.0.p
193
+	 */
194
+	private function editAttendeeLink(int $ID, string $attendee_name): string
195
+	{
196
+		$edit_lnk_url = EE_Admin_Page::add_query_args_and_nonce(
197
+			[
198
+				'action' => 'edit_attendee',
199
+				'post'   => $ID,
200
+			],
201
+			REG_ADMIN_URL
202
+		);
203
+		return EE_Registry::instance()->CAP->current_user_can(
204
+			'ee_edit_contacts',
205
+			'espresso_registrations_edit_attendee'
206
+		)
207
+			? '
208 208
             <a  href="' . $edit_lnk_url . '"
209 209
                 class="ee-aria-tooltip"
210 210
                 aria-label="' . esc_attr__('Edit Contact', 'event_espresso') . '"
211 211
             >
212 212
                 ' . $attendee_name . '
213 213
             </a>'
214
-            : $attendee_name;
215
-    }
216
-
217
-
218
-    /**
219
-     * ATT_fname column
220
-     *
221
-     * @param EE_Attendee $attendee
222
-     * @return string
223
-     * @throws InvalidArgumentException
224
-     * @throws InvalidDataTypeException
225
-     * @throws InvalidInterfaceException
226
-     * @throws EE_Error
227
-     * @throws ReflectionException
228
-     * @throws ReflectionException
229
-     * @throws ReflectionException
230
-     * @throws ReflectionException
231
-     */
232
-    public function column_ATT_fname(EE_Attendee $attendee): string
233
-    {
234
-        // Build row actions
235
-        $actions = [];
236
-        // edit attendee link
237
-        if (
238
-            EE_Registry::instance()->CAP->current_user_can(
239
-                'ee_edit_contacts',
240
-                'espresso_registrations_edit_attendee'
241
-            )
242
-        ) {
243
-            $actions['edit'] = $this->editAttendeeLink(
244
-                $attendee->ID(),
245
-                esc_html__('Edit Contact', 'event_espresso')
246
-            );
247
-        }
248
-
249
-        if ($this->_view === 'in_use') {
250
-            // trash attendee link
251
-            if (
252
-                EE_Registry::instance()->CAP->current_user_can(
253
-                    'ee_delete_contacts',
254
-                    'espresso_registrations_trash_attendees'
255
-                )
256
-            ) {
257
-                $trash_lnk_url    = EE_Admin_Page::add_query_args_and_nonce(
258
-                    [
259
-                        'action' => 'trash_attendee',
260
-                        'ATT_ID' => $attendee->ID(),
261
-                    ],
262
-                    REG_ADMIN_URL
263
-                );
264
-                $actions['trash'] = '
214
+			: $attendee_name;
215
+	}
216
+
217
+
218
+	/**
219
+	 * ATT_fname column
220
+	 *
221
+	 * @param EE_Attendee $attendee
222
+	 * @return string
223
+	 * @throws InvalidArgumentException
224
+	 * @throws InvalidDataTypeException
225
+	 * @throws InvalidInterfaceException
226
+	 * @throws EE_Error
227
+	 * @throws ReflectionException
228
+	 * @throws ReflectionException
229
+	 * @throws ReflectionException
230
+	 * @throws ReflectionException
231
+	 */
232
+	public function column_ATT_fname(EE_Attendee $attendee): string
233
+	{
234
+		// Build row actions
235
+		$actions = [];
236
+		// edit attendee link
237
+		if (
238
+			EE_Registry::instance()->CAP->current_user_can(
239
+				'ee_edit_contacts',
240
+				'espresso_registrations_edit_attendee'
241
+			)
242
+		) {
243
+			$actions['edit'] = $this->editAttendeeLink(
244
+				$attendee->ID(),
245
+				esc_html__('Edit Contact', 'event_espresso')
246
+			);
247
+		}
248
+
249
+		if ($this->_view === 'in_use') {
250
+			// trash attendee link
251
+			if (
252
+				EE_Registry::instance()->CAP->current_user_can(
253
+					'ee_delete_contacts',
254
+					'espresso_registrations_trash_attendees'
255
+				)
256
+			) {
257
+				$trash_lnk_url    = EE_Admin_Page::add_query_args_and_nonce(
258
+					[
259
+						'action' => 'trash_attendee',
260
+						'ATT_ID' => $attendee->ID(),
261
+					],
262
+					REG_ADMIN_URL
263
+				);
264
+				$actions['trash'] = '
265 265
                     <a  href="' . $trash_lnk_url . '"
266 266
                         class="ee-aria-tooltip"
267 267
                         aria-label="' . esc_attr__('Move Contact to Trash', 'event_espresso') . '"
268 268
                     >
269 269
                         ' . esc_html__('Trash', 'event_espresso') . '
270 270
                     </a>';
271
-            }
272
-        } else {
273
-            if (
274
-                EE_Registry::instance()->CAP->current_user_can(
275
-                    'ee_delete_contacts',
276
-                    'espresso_registrations_restore_attendees'
277
-                )
278
-            ) {
279
-                // restore attendee link
280
-                $restore_lnk_url    = EE_Admin_Page::add_query_args_and_nonce(
281
-                    [
282
-                        'action' => 'restore_attendees',
283
-                        'ATT_ID' => $attendee->ID(),
284
-                    ],
285
-                    REG_ADMIN_URL
286
-                );
287
-                $actions['restore'] = '
271
+			}
272
+		} else {
273
+			if (
274
+				EE_Registry::instance()->CAP->current_user_can(
275
+					'ee_delete_contacts',
276
+					'espresso_registrations_restore_attendees'
277
+				)
278
+			) {
279
+				// restore attendee link
280
+				$restore_lnk_url    = EE_Admin_Page::add_query_args_and_nonce(
281
+					[
282
+						'action' => 'restore_attendees',
283
+						'ATT_ID' => $attendee->ID(),
284
+					],
285
+					REG_ADMIN_URL
286
+				);
287
+				$actions['restore'] = '
288 288
                     <a  href="' . $restore_lnk_url . '"
289 289
                         class="ee-aria-tooltip"
290 290
                         aria-label="' . esc_attr__('Restore Contact', 'event_espresso') . '"
291 291
                     >
292 292
                         ' . esc_html__('Restore', 'event_espresso') . '
293 293
                     </a>';
294
-            }
295
-        }
296
-
297
-        $name_link    = $this->editAttendeeLink($attendee->ID(), $attendee->fname());
298
-
299
-        // Return the name contents
300
-        $content = sprintf('%1$s %2$s', $name_link, $this->row_actions($actions));
301
-        return $this->columnContent('ATT_fname', $content);
302
-    }
303
-
304
-
305
-    /**
306
-     * Email Column
307
-     *
308
-     * @param EE_Attendee $attendee
309
-     * @return string
310
-     * @throws EE_Error
311
-     */
312
-    public function column_ATT_email(EE_Attendee $attendee): string
313
-    {
314
-        $content = '<a href="mailto:' . $attendee->email() . '">' . $attendee->email() . '</a>';
315
-        return $this->columnContent('ATT_email', $content);
316
-    }
317
-
318
-
319
-    /**
320
-     * Column displaying count of registrations attached to Attendee.
321
-     *
322
-     * @param EE_Attendee $attendee
323
-     * @return string
324
-     * @throws EE_Error
325
-     * @throws ReflectionException
326
-     */
327
-    public function column_Registration_Count(EE_Attendee $attendee): string
328
-    {
329
-        $link = EEH_URL::add_query_args_and_nonce(
330
-            [
331
-                'action' => 'default',
332
-                'ATT_ID' => $attendee->ID(),
333
-            ],
334
-            REG_ADMIN_URL
335
-        );
336
-        $content = '<a href="' . $link . '">' . $attendee->getCustomSelect('Registration_Count') . '</a>';
337
-        return $this->columnContent('Registration_Count', $content, 'end');
338
-    }
339
-
340
-
341
-    /**
342
-     * ATT_address column
343
-     *
344
-     * @param EE_Attendee $attendee
345
-     * @return string
346
-     * @throws EE_Error
347
-     */
348
-    public function column_ATT_address(EE_Attendee $attendee): string
349
-    {
350
-        return $this->columnContent('ATT_address', $attendee->address());
351
-    }
352
-
353
-
354
-    /**
355
-     * ATT_city column
356
-     *
357
-     * @param EE_Attendee $attendee
358
-     * @return string
359
-     * @throws EE_Error
360
-     */
361
-    public function column_ATT_city(EE_Attendee $attendee): string
362
-    {
363
-        return $this->columnContent('ATT_city', $attendee->city());
364
-    }
365
-
366
-
367
-    /**
368
-     * State Column
369
-     *
370
-     * @param EE_Attendee $attendee
371
-     * @return string
372
-     * @throws EE_Error
373
-     * @throws InvalidArgumentException
374
-     * @throws InvalidDataTypeException
375
-     * @throws InvalidInterfaceException
376
-     * @throws ReflectionException
377
-     */
378
-    public function column_STA_ID(EE_Attendee $attendee): string
379
-    {
380
-        $states = EEM_State::instance()->get_all_states();
381
-        $state  = isset($states[ $attendee->state_ID() ])
382
-            ? $states[ $attendee->state_ID() ]->get('STA_name')
383
-            : $attendee->state_ID();
384
-        $content = ! is_numeric($state) ? $state : '';
385
-        return $this->columnContent('STA_ID', $content);
386
-    }
387
-
388
-
389
-    /**
390
-     * Country Column
391
-     *
392
-     * @param EE_Attendee $attendee
393
-     * @return string
394
-     * @throws EE_Error
395
-     * @throws InvalidArgumentException
396
-     * @throws InvalidDataTypeException
397
-     * @throws InvalidInterfaceException
398
-     * @throws ReflectionException
399
-     * @throws ReflectionException
400
-     */
401
-    public function column_CNT_ISO(EE_Attendee $attendee): string
402
-    {
403
-        $countries = EEM_Country::instance()->get_all_countries();
404
-        $country   = isset($countries[ $attendee->country_ID() ])
405
-            ? $countries[ $attendee->country_ID() ]->get('CNT_name')
406
-            : $attendee->country_ID();
407
-        $content = ! is_numeric($country) ? $country : '';
408
-        return $this->columnContent('CNT_ISO', $content);
409
-    }
410
-
411
-
412
-    /**
413
-     * Phone Number column
414
-     *
415
-     * @param EE_Attendee $attendee
416
-     * @return string
417
-     * @throws EE_Error
418
-     */
419
-    public function column_ATT_phone(EE_Attendee $attendee): string
420
-    {
421
-        return $this->columnContent('ATT_phone', $attendee->phone());
422
-    }
294
+			}
295
+		}
296
+
297
+		$name_link    = $this->editAttendeeLink($attendee->ID(), $attendee->fname());
298
+
299
+		// Return the name contents
300
+		$content = sprintf('%1$s %2$s', $name_link, $this->row_actions($actions));
301
+		return $this->columnContent('ATT_fname', $content);
302
+	}
303
+
304
+
305
+	/**
306
+	 * Email Column
307
+	 *
308
+	 * @param EE_Attendee $attendee
309
+	 * @return string
310
+	 * @throws EE_Error
311
+	 */
312
+	public function column_ATT_email(EE_Attendee $attendee): string
313
+	{
314
+		$content = '<a href="mailto:' . $attendee->email() . '">' . $attendee->email() . '</a>';
315
+		return $this->columnContent('ATT_email', $content);
316
+	}
317
+
318
+
319
+	/**
320
+	 * Column displaying count of registrations attached to Attendee.
321
+	 *
322
+	 * @param EE_Attendee $attendee
323
+	 * @return string
324
+	 * @throws EE_Error
325
+	 * @throws ReflectionException
326
+	 */
327
+	public function column_Registration_Count(EE_Attendee $attendee): string
328
+	{
329
+		$link = EEH_URL::add_query_args_and_nonce(
330
+			[
331
+				'action' => 'default',
332
+				'ATT_ID' => $attendee->ID(),
333
+			],
334
+			REG_ADMIN_URL
335
+		);
336
+		$content = '<a href="' . $link . '">' . $attendee->getCustomSelect('Registration_Count') . '</a>';
337
+		return $this->columnContent('Registration_Count', $content, 'end');
338
+	}
339
+
340
+
341
+	/**
342
+	 * ATT_address column
343
+	 *
344
+	 * @param EE_Attendee $attendee
345
+	 * @return string
346
+	 * @throws EE_Error
347
+	 */
348
+	public function column_ATT_address(EE_Attendee $attendee): string
349
+	{
350
+		return $this->columnContent('ATT_address', $attendee->address());
351
+	}
352
+
353
+
354
+	/**
355
+	 * ATT_city column
356
+	 *
357
+	 * @param EE_Attendee $attendee
358
+	 * @return string
359
+	 * @throws EE_Error
360
+	 */
361
+	public function column_ATT_city(EE_Attendee $attendee): string
362
+	{
363
+		return $this->columnContent('ATT_city', $attendee->city());
364
+	}
365
+
366
+
367
+	/**
368
+	 * State Column
369
+	 *
370
+	 * @param EE_Attendee $attendee
371
+	 * @return string
372
+	 * @throws EE_Error
373
+	 * @throws InvalidArgumentException
374
+	 * @throws InvalidDataTypeException
375
+	 * @throws InvalidInterfaceException
376
+	 * @throws ReflectionException
377
+	 */
378
+	public function column_STA_ID(EE_Attendee $attendee): string
379
+	{
380
+		$states = EEM_State::instance()->get_all_states();
381
+		$state  = isset($states[ $attendee->state_ID() ])
382
+			? $states[ $attendee->state_ID() ]->get('STA_name')
383
+			: $attendee->state_ID();
384
+		$content = ! is_numeric($state) ? $state : '';
385
+		return $this->columnContent('STA_ID', $content);
386
+	}
387
+
388
+
389
+	/**
390
+	 * Country Column
391
+	 *
392
+	 * @param EE_Attendee $attendee
393
+	 * @return string
394
+	 * @throws EE_Error
395
+	 * @throws InvalidArgumentException
396
+	 * @throws InvalidDataTypeException
397
+	 * @throws InvalidInterfaceException
398
+	 * @throws ReflectionException
399
+	 * @throws ReflectionException
400
+	 */
401
+	public function column_CNT_ISO(EE_Attendee $attendee): string
402
+	{
403
+		$countries = EEM_Country::instance()->get_all_countries();
404
+		$country   = isset($countries[ $attendee->country_ID() ])
405
+			? $countries[ $attendee->country_ID() ]->get('CNT_name')
406
+			: $attendee->country_ID();
407
+		$content = ! is_numeric($country) ? $country : '';
408
+		return $this->columnContent('CNT_ISO', $content);
409
+	}
410
+
411
+
412
+	/**
413
+	 * Phone Number column
414
+	 *
415
+	 * @param EE_Attendee $attendee
416
+	 * @return string
417
+	 * @throws EE_Error
418
+	 */
419
+	public function column_ATT_phone(EE_Attendee $attendee): string
420
+	{
421
+		return $this->columnContent('ATT_phone', $attendee->phone());
422
+	}
423 423
 }
Please login to merge, or discard this patch.
modules/ticket_selector/DisplayTicketSelector.php 1 patch
Indentation   +863 added lines, -863 removed lines patch added patch discarded remove patch
@@ -40,870 +40,870 @@
 block discarded – undo
40 40
  */
41 41
 class DisplayTicketSelector
42 42
 {
43
-    /**
44
-     * @var RequestInterface
45
-     */
46
-    protected $request;
47
-
48
-    /**
49
-     * @var EE_Ticket_Selector_Config
50
-     */
51
-    protected $config;
52
-
53
-    /**
54
-     * event that ticket selector is being generated for
55
-     *
56
-     * @access protected
57
-     * @var EE_Event $event
58
-     */
59
-    protected $event;
60
-
61
-    /**
62
-     * Used to flag when the ticket selector is being called from an external iframe.
63
-     *
64
-     * @var bool $iframe
65
-     */
66
-    protected $iframe = false;
67
-
68
-    /**
69
-     * max attendees that can register for event at one time
70
-     *
71
-     * @var int $max_attendees
72
-     */
73
-    private $max_attendees = EE_INF;
74
-
75
-    /**
76
-     * @var string $date_format
77
-     */
78
-    private $date_format;
79
-
80
-    /**
81
-     * @var string $time_format
82
-     */
83
-    private $time_format;
84
-
85
-    /**
86
-     * @var boolean $display_full_ui
87
-     */
88
-    private $display_full_ui;
89
-
90
-    /**
91
-     * @var CurrentUser
92
-     */
93
-    private $current_user;
94
-
95
-
96
-    /**
97
-     * DisplayTicketSelector constructor.
98
-     *
99
-     * @param CurrentUser $current_user
100
-     * @param RequestInterface          $request
101
-     * @param EE_Ticket_Selector_Config $config
102
-     * @param bool                      $iframe
103
-     */
104
-    public function __construct(
105
-        CurrentUser $current_user,
106
-        RequestInterface $request,
107
-        EE_Ticket_Selector_Config $config,
108
-        bool $iframe = false
109
-    ) {
110
-        $this->current_user = $current_user;
111
-        $this->request     = $request;
112
-        $this->config      = $config;
113
-        $this->setIframe($iframe);
114
-        $this->date_format = apply_filters(
115
-            'FHEE__EED_Ticket_Selector__display_ticket_selector__date_format',
116
-            get_option('date_format')
117
-        );
118
-        $this->time_format  = apply_filters(
119
-            'FHEE__EED_Ticket_Selector__display_ticket_selector__time_format',
120
-            get_option('time_format')
121
-        );
122
-    }
123
-
124
-
125
-    /**
126
-     * @return bool
127
-     */
128
-    public function isIframe(): bool
129
-    {
130
-        return $this->iframe;
131
-    }
132
-
133
-
134
-    /**
135
-     * @param boolean $iframe
136
-     */
137
-    public function setIframe(bool $iframe = true)
138
-    {
139
-        $this->iframe = filter_var($iframe, FILTER_VALIDATE_BOOLEAN);
140
-    }
141
-
142
-
143
-    /**
144
-     * finds and sets the \EE_Event object for use throughout class
145
-     *
146
-     * @param mixed $event
147
-     * @return bool
148
-     * @throws EE_Error
149
-     * @throws InvalidDataTypeException
150
-     * @throws InvalidInterfaceException
151
-     * @throws InvalidArgumentException
152
-     */
153
-    protected function setEvent($event = null): bool
154
-    {
155
-        if ($event === null) {
156
-            global $post;
157
-            $event = $post;
158
-        }
159
-        if ($event instanceof EE_Event) {
160
-            $this->event = $event;
161
-        } elseif ($event instanceof WP_Post) {
162
-            if (isset($event->EE_Event) && $event->EE_Event instanceof EE_Event) {
163
-                $this->event = $event->EE_Event;
164
-            } elseif ($event->post_type === 'espresso_events') {
165
-                $event->EE_Event = EEM_Event::instance()->instantiate_class_from_post_object($event);
166
-                $this->event     = $event->EE_Event;
167
-            }
168
-        } else {
169
-            $user_msg = esc_html__('No Event object or an invalid Event object was supplied.', 'event_espresso');
170
-            $dev_msg  = $user_msg . esc_html__(
171
-                'In order to generate a ticket selector, please ensure you are passing either an EE_Event object or a WP_Post object of the post type "espresso_event" to the EE_Ticket_Selector class constructor.',
172
-                'event_espresso'
173
-            );
174
-            EE_Error::add_error($user_msg . '||' . $dev_msg, __FILE__, __FUNCTION__, __LINE__);
175
-            return false;
176
-        }
177
-        return true;
178
-    }
179
-
180
-
181
-    /**
182
-     * @return int
183
-     */
184
-    public function getMaxAttendees(): int
185
-    {
186
-        return $this->max_attendees;
187
-    }
188
-
189
-
190
-    /**
191
-     * @param int $max_attendees
192
-     */
193
-    public function setMaxAttendees(int $max_attendees)
194
-    {
195
-        $this->max_attendees = absint(
196
-            apply_filters(
197
-                'FHEE__EE_Ticket_Selector__display_ticket_selector__max_tickets',
198
-                $max_attendees
199
-            )
200
-        );
201
-    }
202
-
203
-
204
-    /**
205
-     * Returns whether or not the full ticket selector should be shown or not.
206
-     * Currently, it displays on the frontend (including ajax requests) but not the backend
207
-     *
208
-     * @return bool
209
-     */
210
-    private function display_full_ui(): bool
211
-    {
212
-        if ($this->display_full_ui === null) {
213
-            $this->display_full_ui = ! is_admin() || (defined('DOING_AJAX') && DOING_AJAX);
214
-        }
215
-        return $this->display_full_ui;
216
-    }
217
-
218
-
219
-    /**
220
-     * creates buttons for selecting number of attendees for an event
221
-     *
222
-     * @param WP_Post|int $event
223
-     * @param bool        $view_details
224
-     * @return string
225
-     * @throws EE_Error
226
-     * @throws InvalidArgumentException
227
-     * @throws InvalidDataTypeException
228
-     * @throws InvalidInterfaceException
229
-     * @throws ReflectionException
230
-     * @throws Exception
231
-     */
232
-    public function display($event = null, bool $view_details = false)
233
-    {
234
-        // reset filter for displaying submit button
235
-        remove_filter('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', '__return_true');
236
-        // poke and prod incoming event till it tells us what it is
237
-        if (! $this->setEvent($event)) {
238
-            return $this->handleMissingEvent();
239
-        }
240
-        // is the event expired ?
241
-        $template_args['event_is_expired'] = ! is_admin() && $this->event->is_expired();
242
-        if ($template_args['event_is_expired']) {
243
-            return is_single()
244
-                ? $this->expiredEventMessage()
245
-                : $this->expiredEventMessage() . $this->displayViewDetailsButton();
246
-        }
247
-        // begin gathering template arguments by getting event status
248
-        $template_args = ['event_status' => $this->event->get_active_status()];
249
-        if (
250
-            $this->activeEventAndShowTicketSelector(
251
-                $event,
252
-                $template_args['event_status'],
253
-                $view_details
254
-            )
255
-        ) {
256
-            return ! is_single() ? $this->displayViewDetailsButton() : '';
257
-        }
258
-        // filter the maximum qty that can appear in the Ticket Selector qty dropdowns
259
-        $this->setMaxAttendees($this->event->additional_limit());
260
-        if ($this->getMaxAttendees() < 1) {
261
-            return $this->ticketSalesClosedMessage();
262
-        }
263
-        // get all tickets for this event ordered by the datetime
264
-        $tickets = $this->getTickets();
265
-        if (count($tickets) < 1) {
266
-            return $this->noTicketAvailableMessage();
267
-        }
268
-        // redirecting to another site for registration ??
269
-        $external_url = (string) $this->event->external_url()
270
-                        && $this->event->external_url() !== get_the_permalink()
271
-            ? $this->event->external_url()
272
-            : '';
273
-        // if redirecting to another site for registration, then we don't load the TS
274
-        $ticket_selector = $external_url
275
-            ? $this->externalEventRegistration()
276
-            : $this->loadTicketSelector($tickets, $template_args);
277
-        // now set up the form (but not for the admin)
278
-        $ticket_selector = $this->display_full_ui()
279
-            ? $this->formOpen($this->event->ID(), $external_url) . $ticket_selector
280
-            : $ticket_selector;
281
-        // submit button and form close tag
282
-        $ticket_selector .= $this->display_full_ui() ? $this->displaySubmitButton($external_url) : '';
283
-        return $ticket_selector;
284
-    }
285
-
286
-
287
-    /**
288
-     * displayTicketSelector
289
-     * examines the event properties and determines whether a Ticket Selector should be displayed
290
-     *
291
-     * @param WP_Post|int $event
292
-     * @param string      $_event_active_status
293
-     * @param bool        $view_details
294
-     * @return bool
295
-     * @throws EE_Error
296
-     * @throws ReflectionException
297
-     */
298
-    protected function activeEventAndShowTicketSelector($event, string $_event_active_status, bool $view_details): bool
299
-    {
300
-        $event_post = $this->event instanceof EE_Event ? $this->event->ID() : $event;
301
-        return $this->display_full_ui()
302
-               && (
303
-                   ! $this->event->display_ticket_selector()
304
-                   || $view_details
305
-                   || post_password_required($event_post)
306
-                   || (
307
-                       $_event_active_status !== EE_Datetime::active
308
-                       && $_event_active_status !== EE_Datetime::upcoming
309
-                       && $_event_active_status !== EE_Datetime::sold_out
310
-                       && ! (
311
-                           $_event_active_status === EE_Datetime::inactive
312
-                           && is_user_logged_in()
313
-                       )
314
-                   )
315
-               );
316
-    }
317
-
318
-
319
-    /**
320
-     * noTicketAvailableMessage
321
-     * notice displayed if event is expired
322
-     *
323
-     * @return string
324
-     */
325
-    protected function expiredEventMessage(): string
326
-    {
327
-        return '<div class="ee-event-expired-notice"><span class="important-notice">'
328
-           . esc_html__(
329
-               'We\'re sorry, but all tickets sales have ended because the event is expired.',
330
-               'event_espresso'
331
-           )
332
-           . '</span></div><!-- .ee-event-expired-notice -->';
333
-    }
334
-
335
-
336
-    /**
337
-     * noTicketAvailableMessage
338
-     * notice displayed if event has no more tickets available
339
-     *
340
-     * @return string
341
-     * @throws EE_Error
342
-     * @throws ReflectionException
343
-     */
344
-    protected function noTicketAvailableMessage(): string
345
-    {
346
-        $no_ticket_available_msg = esc_html__('We\'re sorry, but all ticket sales have ended.', 'event_espresso');
347
-        if (current_user_can('edit_post', $this->event->ID())) {
348
-            $no_ticket_available_msg .= sprintf(
349
-                esc_html__(
350
-                    '%1$sNote to Event Admin:%2$sNo tickets were found for this event. This effectively turns off ticket sales. Please ensure that at least one ticket is available for if you want people to be able to register.%3$s(click to edit this event)%4$s',
351
-                    'event_espresso'
352
-                ),
353
-                '<div class="ee-attention" style="text-align: left;"><b>',
354
-                '</b><br />',
355
-                '<span class="edit-link"><a class="post-edit-link" href="'
356
-                . get_edit_post_link($this->event->ID())
357
-                . '">',
358
-                '</a></span></div><!-- .ee-attention noTicketAvailableMessage -->'
359
-            );
360
-        }
361
-        return '
43
+	/**
44
+	 * @var RequestInterface
45
+	 */
46
+	protected $request;
47
+
48
+	/**
49
+	 * @var EE_Ticket_Selector_Config
50
+	 */
51
+	protected $config;
52
+
53
+	/**
54
+	 * event that ticket selector is being generated for
55
+	 *
56
+	 * @access protected
57
+	 * @var EE_Event $event
58
+	 */
59
+	protected $event;
60
+
61
+	/**
62
+	 * Used to flag when the ticket selector is being called from an external iframe.
63
+	 *
64
+	 * @var bool $iframe
65
+	 */
66
+	protected $iframe = false;
67
+
68
+	/**
69
+	 * max attendees that can register for event at one time
70
+	 *
71
+	 * @var int $max_attendees
72
+	 */
73
+	private $max_attendees = EE_INF;
74
+
75
+	/**
76
+	 * @var string $date_format
77
+	 */
78
+	private $date_format;
79
+
80
+	/**
81
+	 * @var string $time_format
82
+	 */
83
+	private $time_format;
84
+
85
+	/**
86
+	 * @var boolean $display_full_ui
87
+	 */
88
+	private $display_full_ui;
89
+
90
+	/**
91
+	 * @var CurrentUser
92
+	 */
93
+	private $current_user;
94
+
95
+
96
+	/**
97
+	 * DisplayTicketSelector constructor.
98
+	 *
99
+	 * @param CurrentUser $current_user
100
+	 * @param RequestInterface          $request
101
+	 * @param EE_Ticket_Selector_Config $config
102
+	 * @param bool                      $iframe
103
+	 */
104
+	public function __construct(
105
+		CurrentUser $current_user,
106
+		RequestInterface $request,
107
+		EE_Ticket_Selector_Config $config,
108
+		bool $iframe = false
109
+	) {
110
+		$this->current_user = $current_user;
111
+		$this->request     = $request;
112
+		$this->config      = $config;
113
+		$this->setIframe($iframe);
114
+		$this->date_format = apply_filters(
115
+			'FHEE__EED_Ticket_Selector__display_ticket_selector__date_format',
116
+			get_option('date_format')
117
+		);
118
+		$this->time_format  = apply_filters(
119
+			'FHEE__EED_Ticket_Selector__display_ticket_selector__time_format',
120
+			get_option('time_format')
121
+		);
122
+	}
123
+
124
+
125
+	/**
126
+	 * @return bool
127
+	 */
128
+	public function isIframe(): bool
129
+	{
130
+		return $this->iframe;
131
+	}
132
+
133
+
134
+	/**
135
+	 * @param boolean $iframe
136
+	 */
137
+	public function setIframe(bool $iframe = true)
138
+	{
139
+		$this->iframe = filter_var($iframe, FILTER_VALIDATE_BOOLEAN);
140
+	}
141
+
142
+
143
+	/**
144
+	 * finds and sets the \EE_Event object for use throughout class
145
+	 *
146
+	 * @param mixed $event
147
+	 * @return bool
148
+	 * @throws EE_Error
149
+	 * @throws InvalidDataTypeException
150
+	 * @throws InvalidInterfaceException
151
+	 * @throws InvalidArgumentException
152
+	 */
153
+	protected function setEvent($event = null): bool
154
+	{
155
+		if ($event === null) {
156
+			global $post;
157
+			$event = $post;
158
+		}
159
+		if ($event instanceof EE_Event) {
160
+			$this->event = $event;
161
+		} elseif ($event instanceof WP_Post) {
162
+			if (isset($event->EE_Event) && $event->EE_Event instanceof EE_Event) {
163
+				$this->event = $event->EE_Event;
164
+			} elseif ($event->post_type === 'espresso_events') {
165
+				$event->EE_Event = EEM_Event::instance()->instantiate_class_from_post_object($event);
166
+				$this->event     = $event->EE_Event;
167
+			}
168
+		} else {
169
+			$user_msg = esc_html__('No Event object or an invalid Event object was supplied.', 'event_espresso');
170
+			$dev_msg  = $user_msg . esc_html__(
171
+				'In order to generate a ticket selector, please ensure you are passing either an EE_Event object or a WP_Post object of the post type "espresso_event" to the EE_Ticket_Selector class constructor.',
172
+				'event_espresso'
173
+			);
174
+			EE_Error::add_error($user_msg . '||' . $dev_msg, __FILE__, __FUNCTION__, __LINE__);
175
+			return false;
176
+		}
177
+		return true;
178
+	}
179
+
180
+
181
+	/**
182
+	 * @return int
183
+	 */
184
+	public function getMaxAttendees(): int
185
+	{
186
+		return $this->max_attendees;
187
+	}
188
+
189
+
190
+	/**
191
+	 * @param int $max_attendees
192
+	 */
193
+	public function setMaxAttendees(int $max_attendees)
194
+	{
195
+		$this->max_attendees = absint(
196
+			apply_filters(
197
+				'FHEE__EE_Ticket_Selector__display_ticket_selector__max_tickets',
198
+				$max_attendees
199
+			)
200
+		);
201
+	}
202
+
203
+
204
+	/**
205
+	 * Returns whether or not the full ticket selector should be shown or not.
206
+	 * Currently, it displays on the frontend (including ajax requests) but not the backend
207
+	 *
208
+	 * @return bool
209
+	 */
210
+	private function display_full_ui(): bool
211
+	{
212
+		if ($this->display_full_ui === null) {
213
+			$this->display_full_ui = ! is_admin() || (defined('DOING_AJAX') && DOING_AJAX);
214
+		}
215
+		return $this->display_full_ui;
216
+	}
217
+
218
+
219
+	/**
220
+	 * creates buttons for selecting number of attendees for an event
221
+	 *
222
+	 * @param WP_Post|int $event
223
+	 * @param bool        $view_details
224
+	 * @return string
225
+	 * @throws EE_Error
226
+	 * @throws InvalidArgumentException
227
+	 * @throws InvalidDataTypeException
228
+	 * @throws InvalidInterfaceException
229
+	 * @throws ReflectionException
230
+	 * @throws Exception
231
+	 */
232
+	public function display($event = null, bool $view_details = false)
233
+	{
234
+		// reset filter for displaying submit button
235
+		remove_filter('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', '__return_true');
236
+		// poke and prod incoming event till it tells us what it is
237
+		if (! $this->setEvent($event)) {
238
+			return $this->handleMissingEvent();
239
+		}
240
+		// is the event expired ?
241
+		$template_args['event_is_expired'] = ! is_admin() && $this->event->is_expired();
242
+		if ($template_args['event_is_expired']) {
243
+			return is_single()
244
+				? $this->expiredEventMessage()
245
+				: $this->expiredEventMessage() . $this->displayViewDetailsButton();
246
+		}
247
+		// begin gathering template arguments by getting event status
248
+		$template_args = ['event_status' => $this->event->get_active_status()];
249
+		if (
250
+			$this->activeEventAndShowTicketSelector(
251
+				$event,
252
+				$template_args['event_status'],
253
+				$view_details
254
+			)
255
+		) {
256
+			return ! is_single() ? $this->displayViewDetailsButton() : '';
257
+		}
258
+		// filter the maximum qty that can appear in the Ticket Selector qty dropdowns
259
+		$this->setMaxAttendees($this->event->additional_limit());
260
+		if ($this->getMaxAttendees() < 1) {
261
+			return $this->ticketSalesClosedMessage();
262
+		}
263
+		// get all tickets for this event ordered by the datetime
264
+		$tickets = $this->getTickets();
265
+		if (count($tickets) < 1) {
266
+			return $this->noTicketAvailableMessage();
267
+		}
268
+		// redirecting to another site for registration ??
269
+		$external_url = (string) $this->event->external_url()
270
+						&& $this->event->external_url() !== get_the_permalink()
271
+			? $this->event->external_url()
272
+			: '';
273
+		// if redirecting to another site for registration, then we don't load the TS
274
+		$ticket_selector = $external_url
275
+			? $this->externalEventRegistration()
276
+			: $this->loadTicketSelector($tickets, $template_args);
277
+		// now set up the form (but not for the admin)
278
+		$ticket_selector = $this->display_full_ui()
279
+			? $this->formOpen($this->event->ID(), $external_url) . $ticket_selector
280
+			: $ticket_selector;
281
+		// submit button and form close tag
282
+		$ticket_selector .= $this->display_full_ui() ? $this->displaySubmitButton($external_url) : '';
283
+		return $ticket_selector;
284
+	}
285
+
286
+
287
+	/**
288
+	 * displayTicketSelector
289
+	 * examines the event properties and determines whether a Ticket Selector should be displayed
290
+	 *
291
+	 * @param WP_Post|int $event
292
+	 * @param string      $_event_active_status
293
+	 * @param bool        $view_details
294
+	 * @return bool
295
+	 * @throws EE_Error
296
+	 * @throws ReflectionException
297
+	 */
298
+	protected function activeEventAndShowTicketSelector($event, string $_event_active_status, bool $view_details): bool
299
+	{
300
+		$event_post = $this->event instanceof EE_Event ? $this->event->ID() : $event;
301
+		return $this->display_full_ui()
302
+			   && (
303
+				   ! $this->event->display_ticket_selector()
304
+				   || $view_details
305
+				   || post_password_required($event_post)
306
+				   || (
307
+					   $_event_active_status !== EE_Datetime::active
308
+					   && $_event_active_status !== EE_Datetime::upcoming
309
+					   && $_event_active_status !== EE_Datetime::sold_out
310
+					   && ! (
311
+						   $_event_active_status === EE_Datetime::inactive
312
+						   && is_user_logged_in()
313
+					   )
314
+				   )
315
+			   );
316
+	}
317
+
318
+
319
+	/**
320
+	 * noTicketAvailableMessage
321
+	 * notice displayed if event is expired
322
+	 *
323
+	 * @return string
324
+	 */
325
+	protected function expiredEventMessage(): string
326
+	{
327
+		return '<div class="ee-event-expired-notice"><span class="important-notice">'
328
+		   . esc_html__(
329
+			   'We\'re sorry, but all tickets sales have ended because the event is expired.',
330
+			   'event_espresso'
331
+		   )
332
+		   . '</span></div><!-- .ee-event-expired-notice -->';
333
+	}
334
+
335
+
336
+	/**
337
+	 * noTicketAvailableMessage
338
+	 * notice displayed if event has no more tickets available
339
+	 *
340
+	 * @return string
341
+	 * @throws EE_Error
342
+	 * @throws ReflectionException
343
+	 */
344
+	protected function noTicketAvailableMessage(): string
345
+	{
346
+		$no_ticket_available_msg = esc_html__('We\'re sorry, but all ticket sales have ended.', 'event_espresso');
347
+		if (current_user_can('edit_post', $this->event->ID())) {
348
+			$no_ticket_available_msg .= sprintf(
349
+				esc_html__(
350
+					'%1$sNote to Event Admin:%2$sNo tickets were found for this event. This effectively turns off ticket sales. Please ensure that at least one ticket is available for if you want people to be able to register.%3$s(click to edit this event)%4$s',
351
+					'event_espresso'
352
+				),
353
+				'<div class="ee-attention" style="text-align: left;"><b>',
354
+				'</b><br />',
355
+				'<span class="edit-link"><a class="post-edit-link" href="'
356
+				. get_edit_post_link($this->event->ID())
357
+				. '">',
358
+				'</a></span></div><!-- .ee-attention noTicketAvailableMessage -->'
359
+			);
360
+		}
361
+		return '
362 362
             <div class="ee-event-expired-notice">
363 363
                 <span class="important-notice">' . $no_ticket_available_msg . '</span>
364 364
             </div><!-- .ee-event-expired-notice -->';
365
-    }
366
-
367
-
368
-    /**
369
-     * ticketSalesClosed
370
-     * notice displayed if event ticket sales are turned off
371
-     *
372
-     * @return string
373
-     * @throws EE_Error
374
-     * @throws ReflectionException
375
-     */
376
-    protected function ticketSalesClosedMessage(): string
377
-    {
378
-        $sales_closed_msg = esc_html__(
379
-            'We\'re sorry, but ticket sales have been closed at this time. Please check back again later.',
380
-            'event_espresso'
381
-        );
382
-        if (current_user_can('edit_post', $this->event->ID())) {
383
-            $sales_closed_msg .= sprintf(
384
-                esc_html__(
385
-                    '%sNote to Event Admin:%sThe "Maximum number of tickets allowed per order for this event" in the Event Registration Options has been set to "0". This effectively turns off ticket sales. %s(click to edit this event)%s',
386
-                    'event_espresso'
387
-                ),
388
-                '<div class="ee-attention" style="text-align: left;"><b>',
389
-                '</b><br />',
390
-                '<span class="edit-link"><a class="post-edit-link" href="'
391
-                . get_edit_post_link($this->event->ID())
392
-                . '">',
393
-                '</a></span></div><!-- .ee-attention ticketSalesClosedMessage -->'
394
-            );
395
-        }
396
-        return '<p><span class="important-notice">' . $sales_closed_msg . '</span></p>';
397
-    }
398
-
399
-
400
-    /**
401
-     * getTickets
402
-     *
403
-     * @return EE_Base_Class[]|EE_Ticket[]
404
-     * @throws EE_Error
405
-     * @throws InvalidDataTypeException
406
-     * @throws InvalidInterfaceException
407
-     * @throws InvalidArgumentException
408
-     * @throws ReflectionException
409
-     */
410
-    protected function getTickets()
411
-    {
412
-        $show_expired_tickets = is_admin() || $this->config->show_expired_tickets;
413
-
414
-        $ticket_query_args = [
415
-            [
416
-                'Datetime.EVT_ID' => $this->event->ID(),
417
-                'TKT_visibility'  => ['>', EEM_Ticket::TICKET_VISIBILITY_NONE_VALUE],
418
-            ],
419
-            'order_by' => [
420
-                'TKT_order'              => 'ASC',
421
-                'TKT_required'           => 'DESC',
422
-                'TKT_start_date'         => 'ASC',
423
-                'TKT_end_date'           => 'ASC',
424
-                'Datetime.DTT_EVT_start' => 'DESC',
425
-            ],
426
-        ];
427
-
428
-        $datetime_id = $this->request->getRequestParam('datetime', 0, 'int');
429
-        if ($datetime_id) {
430
-            $ticket_query_args[0]['Datetime.DTT_ID'] = $datetime_id;
431
-        }
432
-
433
-        if (! $show_expired_tickets) {
434
-            // use the correct applicable time query depending on what version of core is being run.
435
-            $current_time                         = method_exists('EEM_Datetime', 'current_time_for_query')
436
-                ? time()
437
-                : current_time('timestamp');
438
-            $ticket_query_args[0]['TKT_end_date'] = ['>', $current_time];
439
-        }
440
-        /** @var EE_Ticket[] $tickets */
441
-        $tickets = EEM_Ticket::instance()->get_all($ticket_query_args);
442
-        // remove tickets based on their visibility and the current user's allowed access (crudely based on roles)
443
-        // and filter the returned results
444
-         $tickets = array_filter($tickets, [$this, 'ticketVisibilityFilter']);
445
-        return (array) apply_filters(
446
-            'FHEE__EventEspresso_modules_ticketSelector_DisplayTicketSelector__getTickets',
447
-            $tickets,
448
-            $ticket_query_args,
449
-            $this
450
-        );
451
-    }
452
-
453
-
454
-    /**
455
-     * returns true if any of the following is true:
456
-     *  - ticket visibility is PUBLIC
457
-     *  - ticket visibility is MEMBERS_ONLY and user is logged in
458
-     *  - ticket visibility is ADMINS_ONLY when user IS logged in as an admin
459
-     *  - ticket visibility is ADMIN_UI_ONLY when ticket selector is being viewed via an admin page UI
460
-     *
461
-     * @param EE_Ticket $ticket
462
-     * @return bool
463
-     * @throws EE_Error
464
-     * @throws ReflectionException
465
-     * @since   5.0.0.p
466
-     */
467
-    public function ticketVisibilityFilter(EE_Ticket $ticket): bool
468
-    {
469
-        return $ticket->isPublicOnly()
470
-               || ($ticket->isMembersOnly() && $this->current_user->isLoggedIn())
471
-               || ($ticket->isAdminsOnly() && $this->current_user->isEventManager())
472
-               || ($ticket->isAdminUiOnly() && is_admin());
473
-    }
474
-
475
-
476
-    /**
477
-     * loadTicketSelector
478
-     * begins to assemble template arguments
479
-     * and decides whether to load a "simple" ticket selector, or the standard
480
-     *
481
-     * @param EE_Ticket[] $tickets
482
-     * @param array       $template_args
483
-     * @return TicketSelectorSimple|TicketSelectorStandard
484
-     * @throws EE_Error
485
-     * @throws ReflectionException
486
-     */
487
-    protected function loadTicketSelector(array $tickets, array $template_args)
488
-    {
489
-        $template_args['event']            = $this->event;
490
-        $template_args['EVT_ID']           = $this->event->ID();
491
-        $template_args['event_is_expired'] = $this->event->is_expired();
492
-        $template_args['max_atndz']        = $this->getMaxAttendees();
493
-        $template_args['date_format']      = $this->date_format;
494
-        $template_args['time_format']      = $this->time_format;
495
-        /**
496
-         * Filters the anchor ID used when redirecting to the Ticket Selector if no quantity selected
497
-         *
498
-         * @param string  '#tkt-slctr-tbl-' . $EVT_ID The html ID to anchor to
499
-         * @param int $EVT_ID The Event ID
500
-         * @since 4.9.13
501
-         */
502
-        $template_args['anchor_id']    = apply_filters(
503
-            'FHEE__EE_Ticket_Selector__redirect_anchor_id',
504
-            '#tkt-slctr-tbl-' . $this->event->ID(),
505
-            $this->event->ID()
506
-        );
507
-        $template_args['tickets']      = $tickets;
508
-        $template_args['ticket_count'] = count($tickets);
509
-        $ticket_selector               = $this->simpleTicketSelector($tickets, $template_args);
510
-        if ($ticket_selector instanceof TicketSelectorSimple) {
511
-            return $ticket_selector;
512
-        }
513
-        return new TicketSelectorStandard(
514
-            $this->config,
515
-            $this->getTaxConfig(),
516
-            $this->event,
517
-            $tickets,
518
-            $this->getMaxAttendees(),
519
-            $template_args,
520
-            $this->date_format,
521
-            $this->time_format
522
-        );
523
-    }
524
-
525
-
526
-    /**
527
-     * simpleTicketSelector
528
-     * there's one ticket, and max attendees is set to one,
529
-     * so if the event is free, then this is a "simple" ticket selector
530
-     * a.k.a. "Dude Where's my Ticket Selector?"
531
-     *
532
-     * @param EE_Ticket[] $tickets
533
-     * @param array       $template_args
534
-     * @return string
535
-     * @throws EE_Error
536
-     * @throws ReflectionException
537
-     */
538
-    protected function simpleTicketSelector(array $tickets, array $template_args)
539
-    {
540
-        // if there is only ONE ticket with a max qty of ONE
541
-        if (count($tickets) > 1 || $this->getMaxAttendees() !== 1) {
542
-            return '';
543
-        }
544
-        /** @var EE_Ticket $ticket */
545
-        $ticket = reset($tickets);
546
-        // if the ticket is free... then not much need for the ticket selector
547
-        if (
548
-            apply_filters(
549
-                'FHEE__ticket_selector_chart_template__hide_ticket_selector',
550
-                $ticket->is_free(),
551
-                $this->event->ID()
552
-            )
553
-        ) {
554
-            return new TicketSelectorSimple(
555
-                $this->event,
556
-                $ticket,
557
-                $this->getMaxAttendees(),
558
-                $template_args
559
-            );
560
-        }
561
-        return '';
562
-    }
563
-
564
-
565
-    /**
566
-     * externalEventRegistration
567
-     *
568
-     * @return string
569
-     */
570
-    public function externalEventRegistration(): string
571
-    {
572
-        // if not we still need to trigger the display of the submit button
573
-        add_filter('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', '__return_true');
574
-        // display notice to admin that registration is external
575
-        return $this->display_full_ui()
576
-            ? esc_html__(
577
-                'Registration is at an external URL for this event.',
578
-                'event_espresso'
579
-            )
580
-            : '';
581
-    }
582
-
583
-
584
-    /**
585
-     * formOpen
586
-     *
587
-     * @param int    $ID
588
-     * @param string $external_url
589
-     * @return        string
590
-     */
591
-    public function formOpen(int $ID = 0, string $external_url = ''): string
592
-    {
593
-        // if redirecting, we don't need any anything else
594
-        if ($external_url) {
595
-            $html = '<form method="GET" ';
596
-            $html .= 'action="' . EEH_URL::refactor_url($external_url) . '" ';
597
-            $html .= 'name="ticket-selector-form-' . $ID . '"';
598
-            // open link in new window ?
599
-            $html       .= apply_filters(
600
-                'FHEE__EventEspresso_modules_ticket_selector_DisplayTicketSelector__formOpen__external_url_target_blank',
601
-                $this->isIframe(),
602
-                $this
603
-            )
604
-                ? ' target="_blank"'
605
-                : '';
606
-            $html       .= '>';
607
-            $query_args = EEH_URL::get_query_string($external_url);
608
-            foreach ((array) $query_args as $query_arg => $value) {
609
-                $html .= '<input type="hidden" name="' . $query_arg . '" value="' . $value . '">';
610
-            }
611
-            return $html;
612
-        }
613
-        // if there is no submit button, then don't start building a form
614
-        // because the "View Details" button will build its own form
615
-        if (! apply_filters('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', false)) {
616
-            return '';
617
-        }
618
-        $checkout_url = EEH_Event_View::event_link_url($ID);
619
-        if (! $checkout_url) {
620
-            EE_Error::add_error(
621
-                esc_html__('The URL for the Event Details page could not be retrieved.', 'event_espresso'),
622
-                __FILE__,
623
-                __FUNCTION__,
624
-                __LINE__
625
-            );
626
-        }
627
-        // set no cache headers and constants
628
-        EE_System::do_not_cache();
629
-        $html = '<form method="POST" ';
630
-        $html .= 'action="' . $checkout_url . '" ';
631
-        $html .= 'name="ticket-selector-form-' . $ID . '"';
632
-        $html .= $this->iframe ? ' target="_blank"' : '';
633
-        $html .= '>';
634
-        $html .= '<input type="hidden" name="ee" value="process_ticket_selections">';
635
-        return apply_filters('FHEE__EE_Ticket_Selector__ticket_selector_form_open__html', $html, $this->event);
636
-    }
637
-
638
-
639
-    /**
640
-     * displaySubmitButton
641
-     *
642
-     * @param string $external_url
643
-     * @return string
644
-     * @throws EE_Error
645
-     * @throws ReflectionException
646
-     */
647
-    public function displaySubmitButton(string $external_url = ''): string
648
-    {
649
-        $html = '';
650
-        if ($this->display_full_ui()) {
651
-            // standard TS displayed with submit button, ie: "Register Now"
652
-            if (apply_filters('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', false)) {
653
-                $html .= $this->displayRegisterNowButton();
654
-                $html .= empty($external_url)
655
-                    ? $this->ticketSelectorEndDiv()
656
-                    : $this->clearTicketSelector();
657
-                $html .= '<br/>' . $this->formClose();
658
-            } elseif ($this->getMaxAttendees() === 1) {
659
-                // its a "Dude Where's my Ticket Selector?" (DWMTS) type event (ie: $_max_atndz === 1)
660
-                if ($this->event->is_sold_out()) {
661
-                    // then instead of a View Details or Submit button, just display a "Sold Out" message
662
-                    $html .= apply_filters(
663
-                        'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__sold_out_msg',
664
-                        sprintf(
665
-                            esc_html__(
666
-                                '%1$s"%2$s" is currently sold out.%4$sPlease check back again later, as spots may become available.%3$s',
667
-                                'event_espresso'
668
-                            ),
669
-                            '<p class="no-ticket-selector-msg clear-float">',
670
-                            $this->event->name(),
671
-                            '</p>',
672
-                            '<br />'
673
-                        ),
674
-                        $this->event
675
-                    );
676
-                    if (
677
-                        apply_filters(
678
-                            'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__no_tickets_but_display_register_now_button',
679
-                            false,
680
-                            $this->event
681
-                        )
682
-                    ) {
683
-                        $html .= $this->displayRegisterNowButton();
684
-                    }
685
-                    // sold out DWMTS event, no TS, no submit or view details button, but has additional content
686
-                    $html .= $this->ticketSelectorEndDiv();
687
-                } elseif (
688
-                    apply_filters('FHEE__EE_Ticket_Selector__hide_ticket_selector', false)
689
-                    && ! is_single()
690
-                ) {
691
-                    // this is a "Dude Where's my Ticket Selector?" (DWMTS) type event,
692
-                    // but no tickets are available, so display event's "View Details" button.
693
-                    // it is being viewed via somewhere other than a single post
694
-                    $html .= $this->displayViewDetailsButton(true);
695
-                } else {
696
-                    $html .= $this->ticketSelectorEndDiv();
697
-                }
698
-            } elseif (is_archive()) {
699
-                // event list, no tickets available so display event's "View Details" button
700
-                $html .= $this->ticketSelectorEndDiv();
701
-                $html .= $this->displayViewDetailsButton();
702
-            } else {
703
-                if (
704
-                    apply_filters(
705
-                        'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__no_tickets_but_display_register_now_button',
706
-                        false,
707
-                        $this->event
708
-                    )
709
-                ) {
710
-                    $html .= $this->displayRegisterNowButton();
711
-                }
712
-                // no submit or view details button, and no additional content
713
-                $html .= $this->ticketSelectorEndDiv();
714
-            }
715
-            if (! $this->iframe && ! is_archive()) {
716
-                $html .= EEH_Template::powered_by_event_espresso('', '', ['utm_content' => 'ticket_selector']);
717
-            }
718
-        }
719
-        return apply_filters(
720
-            'FHEE__EventEspresso_modules_ticket_selector_DisplayTicketSelector__displaySubmitButton__html',
721
-            $html,
722
-            $this->event,
723
-            $this
724
-        );
725
-    }
726
-
727
-
728
-    /**
729
-     * @return string
730
-     * @throws EE_Error
731
-     * @throws ReflectionException
732
-     */
733
-    public function displayRegisterNowButton(): string
734
-    {
735
-        $btn_text     = apply_filters(
736
-            'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__btn_text',
737
-            esc_html__('Register Now', 'event_espresso'),
738
-            $this->event
739
-        );
740
-        $external_url = (string) $this->event->external_url()
741
-                        && $this->event->external_url() !== get_the_permalink()
742
-            ? $this->event->external_url()
743
-            : '';
744
-        $html         = EEH_HTML::div(
745
-            '',
746
-            'ticket-selector-submit-' . $this->event->ID() . '-btn-wrap',
747
-            'ticket-selector-submit-btn-wrap'
748
-        );
749
-        $html         .= '<input id="ticket-selector-submit-' . $this->event->ID() . '-btn"';
750
-        $html         .= ' class="ticket-selector-submit-btn ';
751
-        $html         .= empty($external_url) ? 'ticket-selector-submit-ajax"' : '"';
752
-        $html         .= ' type="submit" value="' . $btn_text . '" data-ee-disable-after-recaptcha="true" />';
753
-        $html         .= EEH_HTML::divx() . '<!-- .ticket-selector-submit-btn-wrap -->';
754
-        $html         .= apply_filters(
755
-            'FHEE__EE_Ticket_Selector__after_ticket_selector_submit',
756
-            '',
757
-            $this->event,
758
-            $this->iframe
759
-        );
760
-        return $html;
761
-    }
762
-
763
-
764
-    /**
765
-     * displayViewDetailsButton
766
-     *
767
-     * @param bool $DWMTS indicates a "Dude Where's my Ticket Selector?" (DWMTS) type event
768
-     *                    (ie: $_max_atndz === 1) where there are no available tickets,
769
-     *                    either because they are sold out, expired, or not yet on sale.
770
-     *                    In this case, we need to close the form BEFORE adding any closing divs
771
-     * @return string
772
-     * @throws EE_Error
773
-     * @throws ReflectionException
774
-     */
775
-    public function displayViewDetailsButton(bool $DWMTS = false): string
776
-    {
777
-        if (! $this->event->get_permalink()) {
778
-            EE_Error::add_error(
779
-                esc_html__('The URL for the Event Details page could not be retrieved.', 'event_espresso'),
780
-                __FILE__,
781
-                __FUNCTION__,
782
-                __LINE__
783
-            );
784
-        }
785
-        $view_details_btn = '<form method="GET" action="';
786
-        $view_details_btn .= apply_filters(
787
-            'FHEE__EE_Ticket_Selector__display_view_details_btn__btn_url',
788
-            $this->event->get_permalink(),
789
-            $this->event
790
-        );
791
-        $view_details_btn .= '"';
792
-        // open link in new window ?
793
-        $view_details_btn .= apply_filters(
794
-            'FHEE__EventEspresso_modules_ticket_selector_DisplayTicketSelector__displayViewDetailsButton__url_target_blank',
795
-            $this->isIframe(),
796
-            $this
797
-        )
798
-            ? ' target="_blank"'
799
-            : '';
800
-        $view_details_btn .= '>';
801
-        $btn_text         = apply_filters(
802
-            'FHEE__EE_Ticket_Selector__display_view_details_btn__btn_text',
803
-            esc_html__('View Details', 'event_espresso'),
804
-            $this->event
805
-        );
806
-        $view_details_btn .= '<input id="ticket-selector-submit-'
807
-                             . $this->event->ID()
808
-                             . '-btn" class="ticket-selector-submit-btn view-details-btn" type="submit" value="'
809
-                             . $btn_text
810
-                             . '" />';
811
-        $view_details_btn .= apply_filters('FHEE__EE_Ticket_Selector__after_view_details_btn', '', $this->event);
812
-        if ($DWMTS) {
813
-            $view_details_btn .= $this->formClose();
814
-            $view_details_btn .= $this->ticketSelectorEndDiv();
815
-            $view_details_btn .= '<br/>';
816
-        } else {
817
-            $view_details_btn .= $this->clearTicketSelector();
818
-            $view_details_btn .= '<br/>';
819
-            $view_details_btn .= $this->formClose();
820
-        }
821
-        return $view_details_btn;
822
-    }
823
-
824
-
825
-    /**
826
-     * @return string
827
-     */
828
-    public function ticketSelectorEndDiv(): string
829
-    {
830
-        return $this->clearTicketSelector() . '</div><!-- ticketSelectorEndDiv -->';
831
-    }
832
-
833
-
834
-    /**
835
-     * @return string
836
-     */
837
-    public function clearTicketSelector(): string
838
-    {
839
-        // standard TS displayed, appears after a "Register Now" or "view Details" button
840
-        return '<div class="clear"></div><!-- clearTicketSelector -->';
841
-    }
842
-
843
-
844
-    /**
845
-     * @access        public
846
-     * @return        string
847
-     */
848
-    public function formClose(): string
849
-    {
850
-        return '</form>';
851
-    }
852
-
853
-
854
-    /**
855
-     * handleMissingEvent
856
-     * Returns either false or an error to display when no valid event is passed.
857
-     *
858
-     * @return string
859
-     * @throws ExceptionStackTraceDisplay
860
-     * @throws InvalidInterfaceException
861
-     * @throws Exception
862
-     */
863
-    protected function handleMissingEvent()
864
-    {
865
-        // If this is not an iFrame request, simply return false.
866
-        if (! $this->isIframe()) {
867
-            return '';
868
-        }
869
-        // This is an iFrame so return an error.
870
-        // Display stack trace if WP_DEBUG is enabled.
871
-        if (WP_DEBUG === true && current_user_can('edit_pages')) {
872
-            $event_id = $this->request->getRequestParam('event', 0, 'int');
873
-            new ExceptionStackTraceDisplay(
874
-                new InvalidArgumentException(
875
-                    sprintf(
876
-                        esc_html__(
877
-                            'A valid Event ID is required to display the ticket selector.%3$sAn Event with an ID of "%1$s" could not be found.%3$sPlease verify that the embed code added to this post\'s content includes an "%2$s" argument and that its value corresponds to a valid Event ID.',
878
-                            'event_espresso'
879
-                        ),
880
-                        $event_id,
881
-                        'event',
882
-                        '<br />'
883
-                    )
884
-                )
885
-            );
886
-            return '';
887
-        }
888
-        // If WP_DEBUG is not enabled, display a message stating the event could not be found.
889
-        return EEH_HTML::p(
890
-            esc_html__(
891
-                'A valid Event could not be found. Please contact the event administrator for assistance.',
892
-                'event_espresso'
893
-            )
894
-        );
895
-    }
896
-
897
-
898
-    /**
899
-     * @return EE_Tax_Config
900
-     * @since   4.10.14.p
901
-     */
902
-    protected function getTaxConfig()
903
-    {
904
-        return isset(EE_Registry::instance()->CFG->tax_settings)
905
-               && EE_Registry::instance()->CFG->tax_settings instanceof EE_Tax_Config
906
-            ? EE_Registry::instance()->CFG->tax_settings
907
-            : new EE_Tax_Config();
908
-    }
365
+	}
366
+
367
+
368
+	/**
369
+	 * ticketSalesClosed
370
+	 * notice displayed if event ticket sales are turned off
371
+	 *
372
+	 * @return string
373
+	 * @throws EE_Error
374
+	 * @throws ReflectionException
375
+	 */
376
+	protected function ticketSalesClosedMessage(): string
377
+	{
378
+		$sales_closed_msg = esc_html__(
379
+			'We\'re sorry, but ticket sales have been closed at this time. Please check back again later.',
380
+			'event_espresso'
381
+		);
382
+		if (current_user_can('edit_post', $this->event->ID())) {
383
+			$sales_closed_msg .= sprintf(
384
+				esc_html__(
385
+					'%sNote to Event Admin:%sThe "Maximum number of tickets allowed per order for this event" in the Event Registration Options has been set to "0". This effectively turns off ticket sales. %s(click to edit this event)%s',
386
+					'event_espresso'
387
+				),
388
+				'<div class="ee-attention" style="text-align: left;"><b>',
389
+				'</b><br />',
390
+				'<span class="edit-link"><a class="post-edit-link" href="'
391
+				. get_edit_post_link($this->event->ID())
392
+				. '">',
393
+				'</a></span></div><!-- .ee-attention ticketSalesClosedMessage -->'
394
+			);
395
+		}
396
+		return '<p><span class="important-notice">' . $sales_closed_msg . '</span></p>';
397
+	}
398
+
399
+
400
+	/**
401
+	 * getTickets
402
+	 *
403
+	 * @return EE_Base_Class[]|EE_Ticket[]
404
+	 * @throws EE_Error
405
+	 * @throws InvalidDataTypeException
406
+	 * @throws InvalidInterfaceException
407
+	 * @throws InvalidArgumentException
408
+	 * @throws ReflectionException
409
+	 */
410
+	protected function getTickets()
411
+	{
412
+		$show_expired_tickets = is_admin() || $this->config->show_expired_tickets;
413
+
414
+		$ticket_query_args = [
415
+			[
416
+				'Datetime.EVT_ID' => $this->event->ID(),
417
+				'TKT_visibility'  => ['>', EEM_Ticket::TICKET_VISIBILITY_NONE_VALUE],
418
+			],
419
+			'order_by' => [
420
+				'TKT_order'              => 'ASC',
421
+				'TKT_required'           => 'DESC',
422
+				'TKT_start_date'         => 'ASC',
423
+				'TKT_end_date'           => 'ASC',
424
+				'Datetime.DTT_EVT_start' => 'DESC',
425
+			],
426
+		];
427
+
428
+		$datetime_id = $this->request->getRequestParam('datetime', 0, 'int');
429
+		if ($datetime_id) {
430
+			$ticket_query_args[0]['Datetime.DTT_ID'] = $datetime_id;
431
+		}
432
+
433
+		if (! $show_expired_tickets) {
434
+			// use the correct applicable time query depending on what version of core is being run.
435
+			$current_time                         = method_exists('EEM_Datetime', 'current_time_for_query')
436
+				? time()
437
+				: current_time('timestamp');
438
+			$ticket_query_args[0]['TKT_end_date'] = ['>', $current_time];
439
+		}
440
+		/** @var EE_Ticket[] $tickets */
441
+		$tickets = EEM_Ticket::instance()->get_all($ticket_query_args);
442
+		// remove tickets based on their visibility and the current user's allowed access (crudely based on roles)
443
+		// and filter the returned results
444
+		 $tickets = array_filter($tickets, [$this, 'ticketVisibilityFilter']);
445
+		return (array) apply_filters(
446
+			'FHEE__EventEspresso_modules_ticketSelector_DisplayTicketSelector__getTickets',
447
+			$tickets,
448
+			$ticket_query_args,
449
+			$this
450
+		);
451
+	}
452
+
453
+
454
+	/**
455
+	 * returns true if any of the following is true:
456
+	 *  - ticket visibility is PUBLIC
457
+	 *  - ticket visibility is MEMBERS_ONLY and user is logged in
458
+	 *  - ticket visibility is ADMINS_ONLY when user IS logged in as an admin
459
+	 *  - ticket visibility is ADMIN_UI_ONLY when ticket selector is being viewed via an admin page UI
460
+	 *
461
+	 * @param EE_Ticket $ticket
462
+	 * @return bool
463
+	 * @throws EE_Error
464
+	 * @throws ReflectionException
465
+	 * @since   5.0.0.p
466
+	 */
467
+	public function ticketVisibilityFilter(EE_Ticket $ticket): bool
468
+	{
469
+		return $ticket->isPublicOnly()
470
+			   || ($ticket->isMembersOnly() && $this->current_user->isLoggedIn())
471
+			   || ($ticket->isAdminsOnly() && $this->current_user->isEventManager())
472
+			   || ($ticket->isAdminUiOnly() && is_admin());
473
+	}
474
+
475
+
476
+	/**
477
+	 * loadTicketSelector
478
+	 * begins to assemble template arguments
479
+	 * and decides whether to load a "simple" ticket selector, or the standard
480
+	 *
481
+	 * @param EE_Ticket[] $tickets
482
+	 * @param array       $template_args
483
+	 * @return TicketSelectorSimple|TicketSelectorStandard
484
+	 * @throws EE_Error
485
+	 * @throws ReflectionException
486
+	 */
487
+	protected function loadTicketSelector(array $tickets, array $template_args)
488
+	{
489
+		$template_args['event']            = $this->event;
490
+		$template_args['EVT_ID']           = $this->event->ID();
491
+		$template_args['event_is_expired'] = $this->event->is_expired();
492
+		$template_args['max_atndz']        = $this->getMaxAttendees();
493
+		$template_args['date_format']      = $this->date_format;
494
+		$template_args['time_format']      = $this->time_format;
495
+		/**
496
+		 * Filters the anchor ID used when redirecting to the Ticket Selector if no quantity selected
497
+		 *
498
+		 * @param string  '#tkt-slctr-tbl-' . $EVT_ID The html ID to anchor to
499
+		 * @param int $EVT_ID The Event ID
500
+		 * @since 4.9.13
501
+		 */
502
+		$template_args['anchor_id']    = apply_filters(
503
+			'FHEE__EE_Ticket_Selector__redirect_anchor_id',
504
+			'#tkt-slctr-tbl-' . $this->event->ID(),
505
+			$this->event->ID()
506
+		);
507
+		$template_args['tickets']      = $tickets;
508
+		$template_args['ticket_count'] = count($tickets);
509
+		$ticket_selector               = $this->simpleTicketSelector($tickets, $template_args);
510
+		if ($ticket_selector instanceof TicketSelectorSimple) {
511
+			return $ticket_selector;
512
+		}
513
+		return new TicketSelectorStandard(
514
+			$this->config,
515
+			$this->getTaxConfig(),
516
+			$this->event,
517
+			$tickets,
518
+			$this->getMaxAttendees(),
519
+			$template_args,
520
+			$this->date_format,
521
+			$this->time_format
522
+		);
523
+	}
524
+
525
+
526
+	/**
527
+	 * simpleTicketSelector
528
+	 * there's one ticket, and max attendees is set to one,
529
+	 * so if the event is free, then this is a "simple" ticket selector
530
+	 * a.k.a. "Dude Where's my Ticket Selector?"
531
+	 *
532
+	 * @param EE_Ticket[] $tickets
533
+	 * @param array       $template_args
534
+	 * @return string
535
+	 * @throws EE_Error
536
+	 * @throws ReflectionException
537
+	 */
538
+	protected function simpleTicketSelector(array $tickets, array $template_args)
539
+	{
540
+		// if there is only ONE ticket with a max qty of ONE
541
+		if (count($tickets) > 1 || $this->getMaxAttendees() !== 1) {
542
+			return '';
543
+		}
544
+		/** @var EE_Ticket $ticket */
545
+		$ticket = reset($tickets);
546
+		// if the ticket is free... then not much need for the ticket selector
547
+		if (
548
+			apply_filters(
549
+				'FHEE__ticket_selector_chart_template__hide_ticket_selector',
550
+				$ticket->is_free(),
551
+				$this->event->ID()
552
+			)
553
+		) {
554
+			return new TicketSelectorSimple(
555
+				$this->event,
556
+				$ticket,
557
+				$this->getMaxAttendees(),
558
+				$template_args
559
+			);
560
+		}
561
+		return '';
562
+	}
563
+
564
+
565
+	/**
566
+	 * externalEventRegistration
567
+	 *
568
+	 * @return string
569
+	 */
570
+	public function externalEventRegistration(): string
571
+	{
572
+		// if not we still need to trigger the display of the submit button
573
+		add_filter('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', '__return_true');
574
+		// display notice to admin that registration is external
575
+		return $this->display_full_ui()
576
+			? esc_html__(
577
+				'Registration is at an external URL for this event.',
578
+				'event_espresso'
579
+			)
580
+			: '';
581
+	}
582
+
583
+
584
+	/**
585
+	 * formOpen
586
+	 *
587
+	 * @param int    $ID
588
+	 * @param string $external_url
589
+	 * @return        string
590
+	 */
591
+	public function formOpen(int $ID = 0, string $external_url = ''): string
592
+	{
593
+		// if redirecting, we don't need any anything else
594
+		if ($external_url) {
595
+			$html = '<form method="GET" ';
596
+			$html .= 'action="' . EEH_URL::refactor_url($external_url) . '" ';
597
+			$html .= 'name="ticket-selector-form-' . $ID . '"';
598
+			// open link in new window ?
599
+			$html       .= apply_filters(
600
+				'FHEE__EventEspresso_modules_ticket_selector_DisplayTicketSelector__formOpen__external_url_target_blank',
601
+				$this->isIframe(),
602
+				$this
603
+			)
604
+				? ' target="_blank"'
605
+				: '';
606
+			$html       .= '>';
607
+			$query_args = EEH_URL::get_query_string($external_url);
608
+			foreach ((array) $query_args as $query_arg => $value) {
609
+				$html .= '<input type="hidden" name="' . $query_arg . '" value="' . $value . '">';
610
+			}
611
+			return $html;
612
+		}
613
+		// if there is no submit button, then don't start building a form
614
+		// because the "View Details" button will build its own form
615
+		if (! apply_filters('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', false)) {
616
+			return '';
617
+		}
618
+		$checkout_url = EEH_Event_View::event_link_url($ID);
619
+		if (! $checkout_url) {
620
+			EE_Error::add_error(
621
+				esc_html__('The URL for the Event Details page could not be retrieved.', 'event_espresso'),
622
+				__FILE__,
623
+				__FUNCTION__,
624
+				__LINE__
625
+			);
626
+		}
627
+		// set no cache headers and constants
628
+		EE_System::do_not_cache();
629
+		$html = '<form method="POST" ';
630
+		$html .= 'action="' . $checkout_url . '" ';
631
+		$html .= 'name="ticket-selector-form-' . $ID . '"';
632
+		$html .= $this->iframe ? ' target="_blank"' : '';
633
+		$html .= '>';
634
+		$html .= '<input type="hidden" name="ee" value="process_ticket_selections">';
635
+		return apply_filters('FHEE__EE_Ticket_Selector__ticket_selector_form_open__html', $html, $this->event);
636
+	}
637
+
638
+
639
+	/**
640
+	 * displaySubmitButton
641
+	 *
642
+	 * @param string $external_url
643
+	 * @return string
644
+	 * @throws EE_Error
645
+	 * @throws ReflectionException
646
+	 */
647
+	public function displaySubmitButton(string $external_url = ''): string
648
+	{
649
+		$html = '';
650
+		if ($this->display_full_ui()) {
651
+			// standard TS displayed with submit button, ie: "Register Now"
652
+			if (apply_filters('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', false)) {
653
+				$html .= $this->displayRegisterNowButton();
654
+				$html .= empty($external_url)
655
+					? $this->ticketSelectorEndDiv()
656
+					: $this->clearTicketSelector();
657
+				$html .= '<br/>' . $this->formClose();
658
+			} elseif ($this->getMaxAttendees() === 1) {
659
+				// its a "Dude Where's my Ticket Selector?" (DWMTS) type event (ie: $_max_atndz === 1)
660
+				if ($this->event->is_sold_out()) {
661
+					// then instead of a View Details or Submit button, just display a "Sold Out" message
662
+					$html .= apply_filters(
663
+						'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__sold_out_msg',
664
+						sprintf(
665
+							esc_html__(
666
+								'%1$s"%2$s" is currently sold out.%4$sPlease check back again later, as spots may become available.%3$s',
667
+								'event_espresso'
668
+							),
669
+							'<p class="no-ticket-selector-msg clear-float">',
670
+							$this->event->name(),
671
+							'</p>',
672
+							'<br />'
673
+						),
674
+						$this->event
675
+					);
676
+					if (
677
+						apply_filters(
678
+							'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__no_tickets_but_display_register_now_button',
679
+							false,
680
+							$this->event
681
+						)
682
+					) {
683
+						$html .= $this->displayRegisterNowButton();
684
+					}
685
+					// sold out DWMTS event, no TS, no submit or view details button, but has additional content
686
+					$html .= $this->ticketSelectorEndDiv();
687
+				} elseif (
688
+					apply_filters('FHEE__EE_Ticket_Selector__hide_ticket_selector', false)
689
+					&& ! is_single()
690
+				) {
691
+					// this is a "Dude Where's my Ticket Selector?" (DWMTS) type event,
692
+					// but no tickets are available, so display event's "View Details" button.
693
+					// it is being viewed via somewhere other than a single post
694
+					$html .= $this->displayViewDetailsButton(true);
695
+				} else {
696
+					$html .= $this->ticketSelectorEndDiv();
697
+				}
698
+			} elseif (is_archive()) {
699
+				// event list, no tickets available so display event's "View Details" button
700
+				$html .= $this->ticketSelectorEndDiv();
701
+				$html .= $this->displayViewDetailsButton();
702
+			} else {
703
+				if (
704
+					apply_filters(
705
+						'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__no_tickets_but_display_register_now_button',
706
+						false,
707
+						$this->event
708
+					)
709
+				) {
710
+					$html .= $this->displayRegisterNowButton();
711
+				}
712
+				// no submit or view details button, and no additional content
713
+				$html .= $this->ticketSelectorEndDiv();
714
+			}
715
+			if (! $this->iframe && ! is_archive()) {
716
+				$html .= EEH_Template::powered_by_event_espresso('', '', ['utm_content' => 'ticket_selector']);
717
+			}
718
+		}
719
+		return apply_filters(
720
+			'FHEE__EventEspresso_modules_ticket_selector_DisplayTicketSelector__displaySubmitButton__html',
721
+			$html,
722
+			$this->event,
723
+			$this
724
+		);
725
+	}
726
+
727
+
728
+	/**
729
+	 * @return string
730
+	 * @throws EE_Error
731
+	 * @throws ReflectionException
732
+	 */
733
+	public function displayRegisterNowButton(): string
734
+	{
735
+		$btn_text     = apply_filters(
736
+			'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__btn_text',
737
+			esc_html__('Register Now', 'event_espresso'),
738
+			$this->event
739
+		);
740
+		$external_url = (string) $this->event->external_url()
741
+						&& $this->event->external_url() !== get_the_permalink()
742
+			? $this->event->external_url()
743
+			: '';
744
+		$html         = EEH_HTML::div(
745
+			'',
746
+			'ticket-selector-submit-' . $this->event->ID() . '-btn-wrap',
747
+			'ticket-selector-submit-btn-wrap'
748
+		);
749
+		$html         .= '<input id="ticket-selector-submit-' . $this->event->ID() . '-btn"';
750
+		$html         .= ' class="ticket-selector-submit-btn ';
751
+		$html         .= empty($external_url) ? 'ticket-selector-submit-ajax"' : '"';
752
+		$html         .= ' type="submit" value="' . $btn_text . '" data-ee-disable-after-recaptcha="true" />';
753
+		$html         .= EEH_HTML::divx() . '<!-- .ticket-selector-submit-btn-wrap -->';
754
+		$html         .= apply_filters(
755
+			'FHEE__EE_Ticket_Selector__after_ticket_selector_submit',
756
+			'',
757
+			$this->event,
758
+			$this->iframe
759
+		);
760
+		return $html;
761
+	}
762
+
763
+
764
+	/**
765
+	 * displayViewDetailsButton
766
+	 *
767
+	 * @param bool $DWMTS indicates a "Dude Where's my Ticket Selector?" (DWMTS) type event
768
+	 *                    (ie: $_max_atndz === 1) where there are no available tickets,
769
+	 *                    either because they are sold out, expired, or not yet on sale.
770
+	 *                    In this case, we need to close the form BEFORE adding any closing divs
771
+	 * @return string
772
+	 * @throws EE_Error
773
+	 * @throws ReflectionException
774
+	 */
775
+	public function displayViewDetailsButton(bool $DWMTS = false): string
776
+	{
777
+		if (! $this->event->get_permalink()) {
778
+			EE_Error::add_error(
779
+				esc_html__('The URL for the Event Details page could not be retrieved.', 'event_espresso'),
780
+				__FILE__,
781
+				__FUNCTION__,
782
+				__LINE__
783
+			);
784
+		}
785
+		$view_details_btn = '<form method="GET" action="';
786
+		$view_details_btn .= apply_filters(
787
+			'FHEE__EE_Ticket_Selector__display_view_details_btn__btn_url',
788
+			$this->event->get_permalink(),
789
+			$this->event
790
+		);
791
+		$view_details_btn .= '"';
792
+		// open link in new window ?
793
+		$view_details_btn .= apply_filters(
794
+			'FHEE__EventEspresso_modules_ticket_selector_DisplayTicketSelector__displayViewDetailsButton__url_target_blank',
795
+			$this->isIframe(),
796
+			$this
797
+		)
798
+			? ' target="_blank"'
799
+			: '';
800
+		$view_details_btn .= '>';
801
+		$btn_text         = apply_filters(
802
+			'FHEE__EE_Ticket_Selector__display_view_details_btn__btn_text',
803
+			esc_html__('View Details', 'event_espresso'),
804
+			$this->event
805
+		);
806
+		$view_details_btn .= '<input id="ticket-selector-submit-'
807
+							 . $this->event->ID()
808
+							 . '-btn" class="ticket-selector-submit-btn view-details-btn" type="submit" value="'
809
+							 . $btn_text
810
+							 . '" />';
811
+		$view_details_btn .= apply_filters('FHEE__EE_Ticket_Selector__after_view_details_btn', '', $this->event);
812
+		if ($DWMTS) {
813
+			$view_details_btn .= $this->formClose();
814
+			$view_details_btn .= $this->ticketSelectorEndDiv();
815
+			$view_details_btn .= '<br/>';
816
+		} else {
817
+			$view_details_btn .= $this->clearTicketSelector();
818
+			$view_details_btn .= '<br/>';
819
+			$view_details_btn .= $this->formClose();
820
+		}
821
+		return $view_details_btn;
822
+	}
823
+
824
+
825
+	/**
826
+	 * @return string
827
+	 */
828
+	public function ticketSelectorEndDiv(): string
829
+	{
830
+		return $this->clearTicketSelector() . '</div><!-- ticketSelectorEndDiv -->';
831
+	}
832
+
833
+
834
+	/**
835
+	 * @return string
836
+	 */
837
+	public function clearTicketSelector(): string
838
+	{
839
+		// standard TS displayed, appears after a "Register Now" or "view Details" button
840
+		return '<div class="clear"></div><!-- clearTicketSelector -->';
841
+	}
842
+
843
+
844
+	/**
845
+	 * @access        public
846
+	 * @return        string
847
+	 */
848
+	public function formClose(): string
849
+	{
850
+		return '</form>';
851
+	}
852
+
853
+
854
+	/**
855
+	 * handleMissingEvent
856
+	 * Returns either false or an error to display when no valid event is passed.
857
+	 *
858
+	 * @return string
859
+	 * @throws ExceptionStackTraceDisplay
860
+	 * @throws InvalidInterfaceException
861
+	 * @throws Exception
862
+	 */
863
+	protected function handleMissingEvent()
864
+	{
865
+		// If this is not an iFrame request, simply return false.
866
+		if (! $this->isIframe()) {
867
+			return '';
868
+		}
869
+		// This is an iFrame so return an error.
870
+		// Display stack trace if WP_DEBUG is enabled.
871
+		if (WP_DEBUG === true && current_user_can('edit_pages')) {
872
+			$event_id = $this->request->getRequestParam('event', 0, 'int');
873
+			new ExceptionStackTraceDisplay(
874
+				new InvalidArgumentException(
875
+					sprintf(
876
+						esc_html__(
877
+							'A valid Event ID is required to display the ticket selector.%3$sAn Event with an ID of "%1$s" could not be found.%3$sPlease verify that the embed code added to this post\'s content includes an "%2$s" argument and that its value corresponds to a valid Event ID.',
878
+							'event_espresso'
879
+						),
880
+						$event_id,
881
+						'event',
882
+						'<br />'
883
+					)
884
+				)
885
+			);
886
+			return '';
887
+		}
888
+		// If WP_DEBUG is not enabled, display a message stating the event could not be found.
889
+		return EEH_HTML::p(
890
+			esc_html__(
891
+				'A valid Event could not be found. Please contact the event administrator for assistance.',
892
+				'event_espresso'
893
+			)
894
+		);
895
+	}
896
+
897
+
898
+	/**
899
+	 * @return EE_Tax_Config
900
+	 * @since   4.10.14.p
901
+	 */
902
+	protected function getTaxConfig()
903
+	{
904
+		return isset(EE_Registry::instance()->CFG->tax_settings)
905
+			   && EE_Registry::instance()->CFG->tax_settings instanceof EE_Tax_Config
906
+			? EE_Registry::instance()->CFG->tax_settings
907
+			: new EE_Tax_Config();
908
+	}
909 909
 }
Please login to merge, or discard this patch.
attendee_information/EE_SPCO_Reg_Step_Attendee_Information.class.php 1 patch
Indentation   +858 added lines, -858 removed lines patch added patch discarded remove patch
@@ -22,862 +22,862 @@
 block discarded – undo
22 22
  */
23 23
 class EE_SPCO_Reg_Step_Attendee_Information extends EE_SPCO_Reg_Step
24 24
 {
25
-    /**
26
-     * @var RegForm
27
-     */
28
-    public $reg_form;
29
-
30
-    /**
31
-     * @var int
32
-     */
33
-    protected $reg_form_count = 0;
34
-
35
-
36
-    /**
37
-     *    class constructor
38
-     *
39
-     * @access    public
40
-     * @param EE_Checkout $checkout
41
-     */
42
-    public function __construct(EE_Checkout $checkout)
43
-    {
44
-        $this->_slug    = 'attendee_information';
45
-        $this->_name    = esc_html__('Attendee Information', 'event_espresso');
46
-        $this->checkout = $checkout;
47
-        $this->_reset_success_message();
48
-        $this->set_instructions(
49
-            esc_html__('Please answer the following registration questions before proceeding.', 'event_espresso')
50
-        );
51
-    }
52
-
53
-
54
-    public function translate_js_strings()
55
-    {
56
-        EE_Registry::$i18n_js_strings['required_field']            = esc_html__(
57
-            ' is a required question.',
58
-            'event_espresso'
59
-        );
60
-        EE_Registry::$i18n_js_strings['required_multi_field']      = esc_html__(
61
-            ' is a required question. Please enter a value for at least one of the options.',
62
-            'event_espresso'
63
-        );
64
-        EE_Registry::$i18n_js_strings['answer_required_questions'] = esc_html__(
65
-            'Please answer all required questions correctly before proceeding.',
66
-            'event_espresso'
67
-        );
68
-        EE_Registry::$i18n_js_strings['attendee_info_copied']      = sprintf(
69
-            esc_html_x(
70
-                'The attendee information was successfully copied.%sPlease ensure the rest of the registration form is completed before proceeding.',
71
-                'The attendee information was successfully copied.(line break)Please ensure the rest of the registration form is completed before proceeding.',
72
-                'event_espresso'
73
-            ),
74
-            '<br/>'
75
-        );
76
-        EE_Registry::$i18n_js_strings['attendee_info_copy_error']  = esc_html__(
77
-            'An unknown error occurred on the server while attempting to copy the attendee information. Please refresh the page and try again.',
78
-            'event_espresso'
79
-        );
80
-        EE_Registry::$i18n_js_strings['enter_valid_email']         = esc_html__(
81
-            'You must enter a valid email address.',
82
-            'event_espresso'
83
-        );
84
-        EE_Registry::$i18n_js_strings['valid_email_and_questions'] = esc_html__(
85
-            'You must enter a valid email address and answer all other required questions before you can proceed.',
86
-            'event_espresso'
87
-        );
88
-    }
89
-
90
-
91
-    public function enqueue_styles_and_scripts()
92
-    {
93
-    }
94
-
95
-
96
-    /**
97
-     * @return boolean
98
-     */
99
-    public function initialize_reg_step(): bool
100
-    {
101
-        return true;
102
-    }
103
-
104
-
105
-    /**
106
-     * @return RegForm
107
-     * @throws DomainException
108
-     * @throws InvalidArgumentException
109
-     * @throws EntityNotFoundException
110
-     * @throws InvalidDataTypeException
111
-     * @throws InvalidInterfaceException
112
-     */
113
-    public function generate_reg_form(): RegForm
114
-    {
115
-        $this->setLegacyFiltersForRegFormGeneration();
116
-        /** @var RegFormDependencyHandler $dependency_handler */
117
-        $dependency_handler = LoaderFactory::getShared(RegFormDependencyHandler::class);
118
-        $dependency_handler->registerDependencies();
119
-        // TODO detect if event has a reg form UUID and swap this out for form generated by new reg form builder
120
-        return LoaderFactory::getShared(RegForm::class, [$this]);
121
-    }
122
-
123
-
124
-    /**
125
-     * @since   5.0.0.p
126
-     */
127
-    private function setLegacyFiltersForRegFormGeneration()
128
-    {
129
-        add_filter(
130
-            'FHEE__EventEspresso_core_domain_services_registration_form_v1_RegistrantForm__generateFormArgs__question_groups_query_parameters',
131
-            [$this, 'registrationQuestionGroupsQueryParameters'],
132
-            1,
133
-            2
134
-        );
135
-        add_filter(
136
-            'FHEE__EventEspresso_core_domain_services_registration_form_v1_RegistrantForm__generateFormArgs__question_group_reg_form',
137
-            [$this, 'registrationQuestionGroupsRegForm'],
138
-            1,
139
-            3
140
-        );
141
-        add_filter(
142
-            'FHEE__EventEspresso_core_domain_services_registration_form_v1_RegistrantForm__generateFormArgs__printCopyInfo',
143
-            [$this, 'registrationRegFormPrintCopyInfo'],
144
-            1,
145
-            2
146
-        );
147
-        add_filter(
148
-            'FHEE__EventEspresso_core_domain_services_registration_form_v1_RegFormQuestionGroup__generateFormArgs__related_questions_query_params',
149
-            [$this, 'registrationRegFormRelatedQuestionsQueryParams'],
150
-            1,
151
-            3
152
-        );
153
-        add_filter(
154
-            'FHEE__EventEspresso_core_domain_services_registration_form_v1_RegFormQuestionGroup__generateFormArgs__before_question_group_questions',
155
-            [$this, 'registrationRegFormBeforeQuestionGroupQuestions'],
156
-            1,
157
-            3
158
-        );
159
-        add_filter(
160
-            'FHEE__EventEspresso_core_domain_services_registration_form_v1_RegFormQuestionGroup__generateFormArgs__subsections_array',
161
-            [$this, 'registrationRegFormSubsections'],
162
-            1,
163
-            3
164
-        );
165
-        add_filter(
166
-            'FHEE__EventEspresso_core_domain_services_registration_form_v1_RegFormQuestionGroup__generateFormArgs__after_question_group_questions',
167
-            [$this, 'registrationRegFormAfterQuestionGroupQuestions'],
168
-            1,
169
-            3
170
-        );
171
-        add_filter(
172
-            'FHEE__EventEspresso_core_domain_services_registration_form_v1_AutoCopyAttendeeInfoForm__construct__template_args',
173
-            [$this, 'autoCopyAttendeeInfoTemplateArgs'],
174
-            1
175
-        );
176
-        add_filter(
177
-            'FHEE__EventEspresso_core_domain_services_registration_form_v1_CountryOptions__generateLegacyCountryOptions__country_options',
178
-            [$this, 'generateQuestionInputCountryOptions'],
179
-            1,
180
-            4
181
-        );
182
-        add_filter(
183
-            'FHEE__EventEspresso_core_domain_services_registration_form_v1_StateOptions__generateLegacyStateOptions__state_options',
184
-            [$this, 'generateQuestionInputStateOptions'],
185
-            1,
186
-            4
187
-        );
188
-    }
189
-
190
-
191
-    /**
192
-     * @param array           $query_params
193
-     * @param EE_Registration $registration
194
-     * @return mixed|void
195
-     * @since   5.0.0.p
196
-     */
197
-    public function registrationQuestionGroupsQueryParameters(
198
-        array $query_params,
199
-        EE_Registration $registration
200
-    ) {
201
-        return apply_filters(
202
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___registrations_reg_form__question_groups_query_parameters',
203
-            $query_params,
204
-            $registration,
205
-            $this
206
-        );
207
-    }
208
-
209
-
210
-    /**
211
-     * @param RegFormQuestionGroup $question_group_reg_form
212
-     * @param EE_Registration      $registration
213
-     * @param EE_Question_Group    $question_group
214
-     * @return mixed|void
215
-     * @since   5.0.0.p
216
-     */
217
-    public function registrationQuestionGroupsRegForm(
218
-        RegFormQuestionGroup $question_group_reg_form,
219
-        EE_Registration $registration,
220
-        EE_Question_Group $question_group
221
-    ) {
222
-        return apply_filters(
223
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__question_group_reg_form',
224
-            $question_group_reg_form,
225
-            $registration,
226
-            $question_group,
227
-            $this
228
-        );
229
-    }
230
-
231
-
232
-    /**
233
-     * @param int $print_copy_info
234
-     * @param int $attendee_nmbr
235
-     * @return mixed|void
236
-     * @since   5.0.0.p
237
-     */
238
-    public function registrationRegFormPrintCopyInfo(
239
-        int $print_copy_info,
240
-        int $attendee_nmbr
241
-    ) {
242
-        return apply_filters(
243
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___registrations_reg_form___printCopyInfo',
244
-            $print_copy_info,
245
-            $attendee_nmbr
246
-        );
247
-    }
248
-
249
-
250
-    /**
251
-     * @param array             $query_params
252
-     * @param EE_Question_Group $question_group
253
-     * @param EE_Registration   $registration
254
-     * @return mixed|void
255
-     * @since   5.0.0.p
256
-     */
257
-    public function registrationRegFormRelatedQuestionsQueryParams(
258
-        array $query_params,
259
-        EE_Question_Group $question_group,
260
-        EE_Registration $registration
261
-    ) {
262
-        return apply_filters(
263
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__related_questions_query_params',
264
-            $query_params,
265
-            $question_group,
266
-            $registration,
267
-            $this
268
-        );
269
-    }
270
-
271
-
272
-    /**
273
-     * @param                   $html
274
-     * @param EE_Registration   $registration
275
-     * @param EE_Question_Group $question_group
276
-     * @return mixed|void
277
-     * @since   5.0.0.p
278
-     */
279
-    public function registrationRegFormBeforeQuestionGroupQuestions(
280
-        $html,
281
-        EE_Registration $registration,
282
-        EE_Question_Group $question_group
283
-    ) {
284
-        return apply_filters(
285
-            'FHEE__EEH_Form_Fields__generate_question_groups_html__before_question_group_questions',
286
-            $html,
287
-            $registration,
288
-            $question_group,
289
-            $this
290
-        );
291
-    }
292
-
293
-
294
-    /**
295
-     * @param array             $form_subsections
296
-     * @param EE_Registration   $registration
297
-     * @param EE_Question_Group $question_group
298
-     * @return mixed|void
299
-     * @since   5.0.0.p
300
-     */
301
-    public function registrationRegFormSubsections(
302
-        array $form_subsections,
303
-        EE_Registration $registration,
304
-        EE_Question_Group $question_group
305
-    ) {
306
-        return apply_filters(
307
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information__question_group_reg_form__subsections_array',
308
-            $form_subsections,
309
-            $registration,
310
-            $question_group,
311
-            $this
312
-        );
313
-    }
314
-
315
-
316
-    /**
317
-     * @param                   $html
318
-     * @param EE_Registration   $registration
319
-     * @param EE_Question_Group $question_group
320
-     * @return mixed|void
321
-     * @since   5.0.0.p
322
-     */
323
-    public function registrationRegFormAfterQuestionGroupQuestions(
324
-        $html,
325
-        EE_Registration $registration,
326
-        EE_Question_Group $question_group
327
-    ) {
328
-        return apply_filters(
329
-            'FHEE__EEH_Form_Fields__generate_question_groups_html__after_question_group_questions',
330
-            $html,
331
-            $registration,
332
-            $question_group,
333
-            $this
334
-        );
335
-    }
336
-
337
-
338
-    /**
339
-     * @param array $template_args
340
-     * @return mixed|void
341
-     * @since   5.0.0.p
342
-     */
343
-    public function autoCopyAttendeeInfoTemplateArgs(array $template_args = [])
344
-    {
345
-        return apply_filters(
346
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information__auto_copy_attendee_info__template_args',
347
-            $template_args
348
-        );
349
-    }
350
-
351
-
352
-    /**
353
-     * @param array           $country_options
354
-     * @param EE_Registration $registration
355
-     * @param EE_Question     $question
356
-     * @param EE_Answer|null  $answer
357
-     * @return mixed|void
358
-     * @since   5.0.0.p
359
-     */
360
-    public function generateQuestionInputCountryOptions(
361
-        array $country_options,
362
-        EE_Registration $registration,
363
-        EE_Question $question,
364
-        ?EE_Answer $answer
365
-    ) {
366
-        return apply_filters(
367
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__country_options',
368
-            $country_options,
369
-            $this,
370
-            $registration,
371
-            $question,
372
-            $answer
373
-        );
374
-    }
375
-
376
-
377
-    /**
378
-     * @param array           $state_options
379
-     * @param EE_Registration $registration
380
-     * @param EE_Question     $question
381
-     * @param EE_Answer|null  $answer
382
-     * @return mixed|void
383
-     * @since   5.0.0.p
384
-     */
385
-    public function generateQuestionInputStateOptions(
386
-        array $state_options,
387
-        EE_Registration $registration,
388
-        EE_Question $question,
389
-        ?EE_Answer $answer
390
-    ) {
391
-        return apply_filters(
392
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__state_options',
393
-            $state_options,
394
-            $this,
395
-            $registration,
396
-            $question,
397
-            $answer
398
-        );
399
-    }
400
-
401
-
402
-    /**
403
-     * looking for hooks?
404
-     * this method has been replaced by:
405
-     * EventEspresso\core\domain\services\registration\form\v1\RegForm::getRegForm()
406
-     *
407
-     * @deprecated   5.0.0.p
408
-     */
409
-    private function _registrations_reg_form()
410
-    {
411
-    }
412
-
413
-
414
-    /**
415
-     * looking for hooks?
416
-     * this method has been replaced by:
417
-     * EventEspresso\core\domain\services\registration\form\v1\RegForm::additionalAttendeeRegInfoInput()
418
-     *
419
-     * @deprecated   5.0.0.p
420
-     */
421
-    private function _additional_attendee_reg_info_input()
422
-    {
423
-    }
424
-
425
-
426
-    /**
427
-     * looking for hooks?
428
-     * this method has been replaced by:
429
-     * EventEspresso\core\domain\services\registration\form\v1\RegForm::questionGroupRegForm()
430
-     *
431
-     * @deprecated   5.0.0.p
432
-     */
433
-    private function _question_group_reg_form()
434
-    {
435
-    }
436
-
437
-
438
-    /**
439
-     * looking for hooks?
440
-     * this method has been replaced by:
441
-     * EventEspresso\core\domain\services\registration\form\v1\RegForm::questionGroupHeader()
442
-     *
443
-     * @deprecated   5.0.0.p
444
-     */
445
-    private function _question_group_header()
446
-    {
447
-    }
448
-
449
-
450
-    /**
451
-     * looking for hooks?
452
-     * this method has been replaced by:
453
-     * EventEspresso\core\domain\services\registration\form\v1\CopyAttendeeInfoForm
454
-     *
455
-     * @deprecated   5.0.0.p
456
-     */
457
-    private function _copy_attendee_info_form()
458
-    {
459
-    }
460
-
461
-
462
-    /**
463
-     * looking for hooks?
464
-     * this method has been replaced by:
465
-     * EventEspresso\core\domain\services\registration\form\v1\AutoCopyAttendeeInfoForm
466
-     *
467
-     * @deprecated   5.0.0.p
468
-     */
469
-    private function _auto_copy_attendee_info()
470
-    {
471
-    }
472
-
473
-
474
-    /**
475
-     * looking for hooks?
476
-     * this method has been replaced by:
477
-     * EventEspresso\core\domain\services\registration\form\v1\CopyAttendeeInfoForm
478
-     *
479
-     * @deprecated   5.0.0.p
480
-     */
481
-    private function _copy_attendee_info_inputs()
482
-    {
483
-    }
484
-
485
-
486
-    /**
487
-     * looking for hooks?
488
-     * this method has been replaced by:
489
-     * EventEspresso\core\domain\services\registration\form\v1\RegForm::additionalPrimaryRegistrantInputs()
490
-     *
491
-     * @deprecated   5.0.0.p
492
-     */
493
-    private function _additional_primary_registrant_inputs()
494
-    {
495
-    }
496
-
497
-
498
-    /**
499
-     * looking for hooks?
500
-     * this method has been replaced by:
501
-     * EventEspresso\core\domain\services\registration\form\v1\RegFormQuestionFactory::create()
502
-     *
503
-     * @param EE_Registration $registration
504
-     * @param EE_Question     $question
505
-     * @return EE_Form_Input_Base
506
-     * @throws EE_Error
507
-     * @throws ReflectionException
508
-     * @deprecated   5.0.0.p
509
-     */
510
-    public function reg_form_question(EE_Registration $registration, EE_Question $question): EE_Form_Input_Base
511
-    {
512
-        /** @var RegFormQuestionFactory $reg_form_question_factory */
513
-        $reg_form_question_factory = LoaderFactory::getShared(RegFormQuestionFactory::class);
514
-        return $reg_form_question_factory->create($registration, $question);
515
-    }
516
-
517
-
518
-    /**
519
-     * looking for hooks?
520
-     * this method has been replaced by:
521
-     * EventEspresso\core\domain\services\registration\form\v1\RegForm::generateQuestionInput()
522
-     *
523
-     * @deprecated   5.0.0.p
524
-     */
525
-    private function _generate_question_input()
526
-    {
527
-    }
528
-
529
-
530
-    /**
531
-     * looking for hooks?
532
-     * this method has been replaced by:
533
-     * EventEspresso\core\domain\services\registration\form\v1\CountryOptions::forLegacyFormInput()
534
-     *
535
-     * @param array|null           $countries_list
536
-     * @param EE_Question|null     $question
537
-     * @param EE_Registration|null $registration
538
-     * @param EE_Answer|null       $answer
539
-     * @return array 2d keys are country IDs, values are their names
540
-     * @throws EE_Error
541
-     * @throws ReflectionException
542
-     * @deprecated   5.0.0.p
543
-     */
544
-    public function use_cached_countries_for_form_input(
545
-        array $countries_list = null,
546
-        EE_Question $question = null,
547
-        EE_Registration $registration = null,
548
-        EE_Answer $answer = null
549
-    ): array {
550
-        /** @var CountryOptions $country_options */
551
-        $country_options = LoaderFactory::getShared(CountryOptions::class, [$this->checkout->action]);
552
-        return $country_options->forLegacyFormInput($countries_list, $question, $registration, $answer);
553
-    }
554
-
555
-
556
-    /**
557
-     * looking for hooks?
558
-     * this method has been replaced by:
559
-     * EventEspresso\core\domain\services\registration\form\v1\StateOptions::forLegacyFormInput()
560
-     *
561
-     * @param array|null           $states_list
562
-     * @param EE_Question|null     $question
563
-     * @param EE_Registration|null $registration
564
-     * @param EE_Answer|null       $answer
565
-     * @return array 2d keys are state IDs, values are their names
566
-     * @throws EE_Error
567
-     * @throws ReflectionException
568
-     * @deprecated   5.0.0.p
569
-     */
570
-    public function use_cached_states_for_form_input(
571
-        array $states_list = null,
572
-        EE_Question $question = null,
573
-        EE_Registration $registration = null,
574
-        EE_Answer $answer = null
575
-    ): array {
576
-        /** @var StateOptions $state_options */
577
-        $state_options = LoaderFactory::getShared(StateOptions::class, [$this->checkout->action]);
578
-        return $state_options->forLegacyFormInput($states_list, $question, $registration, $answer);
579
-    }
580
-
581
-
582
-    /********************************************************************************************************/
583
-    /****************************************  PROCESS REG STEP  ****************************************/
584
-    /********************************************************************************************************/
585
-
586
-
587
-    /**
588
-     * @return bool
589
-     * @throws EE_Error
590
-     * @throws InvalidArgumentException
591
-     * @throws ReflectionException
592
-     * @throws RuntimeException
593
-     * @throws InvalidDataTypeException
594
-     * @throws InvalidInterfaceException
595
-     */
596
-    public function process_reg_step(): bool
597
-    {
598
-        $this->setLegacyFiltersForRegFormProcessing();
599
-        // grab validated data from form
600
-        $valid_data = $this->checkout->current_step->valid_data();
601
-        // if we don't have any $valid_data then something went TERRIBLY WRONG !!!
602
-        if (empty($valid_data)) {
603
-            return $this->inValidDataError();
604
-        }
605
-        if (! $this->checkout->transaction instanceof EE_Transaction || ! $this->checkout->continue_reg) {
606
-            return $this->inValidTransactionError();
607
-        }
608
-        // get cached registrations
609
-        $registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
610
-        // verify we got the goods
611
-        if (empty($registrations)) {
612
-            return $this->noRegistrationsError();
613
-        }
614
-        /** @var RegFormHandler $reg_form_handler */
615
-        $reg_form_handler = LoaderFactory::getNew(RegFormHandler::class, [$this->checkout]);
616
-        // extract attendee info from form data and save to model objects
617
-        if (! $reg_form_handler->processRegistrations($registrations, $valid_data)) {
618
-            // return immediately if the previous step exited early due to errors
619
-            return false;
620
-        }
621
-        // if first pass thru SPCO,
622
-        // then let's check processed registrations against the total number of tickets in the cart
623
-        $registrations_processed = $reg_form_handler->attendeeCount();
624
-        if (! $this->checkout->revisit && $registrations_processed !== $this->checkout->total_ticket_count) {
625
-            return $this->registrationProcessingError($registrations_processed);
626
-        }
627
-        // mark this reg step as completed
628
-        $this->set_completed();
629
-        $this->_set_success_message(
630
-            esc_html__('The Attendee Information Step has been successfully completed.', 'event_espresso')
631
-        );
632
-        // do action in case a plugin wants to do something with the data submitted in step 1.
633
-        // passes EE_Single_Page_Checkout, and it's posted data
634
-        do_action('AHEE__EE_Single_Page_Checkout__process_attendee_information__end', $this, $valid_data);
635
-        return true;
636
-    }
637
-
638
-
639
-    /**
640
-     * @since   5.0.0.p
641
-     */
642
-    private function setLegacyFiltersForRegFormProcessing()
643
-    {
644
-        add_filter(
645
-            'FHEE__EventEspresso_core_domain_services_registration_form_v1_RegFormHandler__processRegistrations__bypass',
646
-            [$this, 'preRegistrationProcess'],
647
-            1,
648
-            5
649
-        );
650
-        add_filter(
651
-            'FHEE__EventEspresso_core_domain_services_registration_form_v1_RegFormHandler__processRegFormData__registrant_form_data',
652
-            [$this, 'validDataLineItem'],
653
-            1,
654
-            2
655
-        );
656
-        add_filter(
657
-            'FHEE__EventEspresso_core_domain_services_registration_form_v1_RegFormInputHandler__saveRegistrationFormInput',
658
-            [$this, 'saveRegistrationFormInput'],
659
-            1,
660
-            4
661
-        );
662
-        add_filter(
663
-            'FHEE__EventEspresso_core_domain_services_registration_form_v1_RegistrantData__ensureCriticalRegistrantDataIsSet',
664
-            [$this, 'mergeAddressDetailsWithCriticalAttendeeDetails'],
665
-            1
666
-        );
667
-    }
668
-
669
-
670
-    /**
671
-     * @param bool            $bypass
672
-     * @param int             $attendee_count
673
-     * @param EE_Registration $registration
674
-     * @param array           $registrations
675
-     * @param array           $reg_form_data
676
-     * @return mixed|void
677
-     * @since   5.0.0.p
678
-     */
679
-    public function preRegistrationProcess(
680
-        bool $bypass,
681
-        int $attendee_count,
682
-        EE_Registration $registration,
683
-        array $registrations,
684
-        array $reg_form_data
685
-    ) {
686
-        return apply_filters(
687
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___process_registrations__pre_registration_process',
688
-            $bypass,
689
-            $attendee_count,
690
-            $registration,
691
-            $registrations,
692
-            $reg_form_data,
693
-            $this
694
-        );
695
-    }
696
-
697
-
698
-    /**
699
-     * @param array           $reg_form_data
700
-     * @param EE_Registration $registration
701
-     * @return mixed|void
702
-     * @since   5.0.0.p
703
-     */
704
-    public function validDataLineItem(array $reg_form_data, EE_Registration $registration)
705
-    {
706
-        return apply_filters(
707
-            'FHEE__EE_Single_Page_Checkout__process_attendee_information__valid_data_line_item',
708
-            $reg_form_data,
709
-            $registration
710
-        );
711
-    }
712
-
713
-
714
-    /**
715
-     * @param bool            $save
716
-     * @param EE_Registration $registration
717
-     * @param                 $form_input
718
-     * @param                 $input_value
719
-     * @return mixed|void
720
-     * @since   5.0.0.p
721
-     */
722
-    public function saveRegistrationFormInput(bool $save, EE_Registration $registration, $form_input, $input_value)
723
-    {
724
-        return apply_filters(
725
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___save_registration_form_input',
726
-            $save,
727
-            $registration,
728
-            $form_input,
729
-            $input_value,
730
-            $this
731
-        );
732
-    }
733
-
734
-
735
-    /**
736
-     * @param bool $merge_data
737
-     * @return mixed|void
738
-     * @since   5.0.0.p
739
-     */
740
-    public function mergeAddressDetailsWithCriticalAttendeeDetails(bool $merge_data)
741
-    {
742
-        return apply_filters(
743
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information__merge_address_details_with_critical_attendee_details',
744
-            $merge_data
745
-        );
746
-    }
747
-
748
-
749
-    /**
750
-     * @return bool
751
-     * @since   5.0.0.p
752
-     */
753
-    private function inValidDataError(): bool
754
-    {
755
-        EE_Error::add_error(
756
-            esc_html__('No valid question responses were received.', 'event_espresso'),
757
-            __FILE__,
758
-            __FUNCTION__,
759
-            __LINE__
760
-        );
761
-        return false;
762
-    }
763
-
764
-
765
-    /**
766
-     * @return bool
767
-     * @since   5.0.0.p
768
-     */
769
-    private function inValidTransactionError(): bool
770
-    {
771
-        EE_Error::add_error(
772
-            esc_html__(
773
-                'A valid transaction could not be initiated for processing your registrations.',
774
-                'event_espresso'
775
-            ),
776
-            __FILE__,
777
-            __FUNCTION__,
778
-            __LINE__
779
-        );
780
-        return false;
781
-    }
782
-
783
-
784
-    /**
785
-     * @return bool
786
-     * @since   5.0.0.p
787
-     */
788
-    private function noRegistrationsError(): bool
789
-    {
790
-        // combine the old translated string with a new one, in order to not break translations
791
-        $error_message = esc_html__(
792
-            'Your form data could not be applied to any valid registrations.',
793
-            'event_espresso'
794
-        );
795
-        $error_message .= sprintf(
796
-            esc_html_x(
797
-                '%3$sThis can sometimes happen if too much time has been taken to complete the registration process.%3$sPlease return to the %1$sEvent List%2$s and reselect your tickets. If the problem continues, please contact the site administrator.',
798
-                '(line break)This can sometimes happen if too much time has been taken to complete the registration process.(line break)Please return to the (link)Event List(end link) and reselect your tickets. If the problem continues, please contact the site administrator.',
799
-                'event_espresso'
800
-            ),
801
-            '<a href="' . get_post_type_archive_link('espresso_events') . '" >',
802
-            '</a>',
803
-            '<br />'
804
-        );
805
-        EE_Error::add_error($error_message, __FILE__, __FUNCTION__, __LINE__);
806
-        return false;
807
-    }
808
-
809
-
810
-    /**
811
-     * @param int $registrations_processed
812
-     * @return bool
813
-     * @since   5.0.0.p
814
-     */
815
-    private function registrationProcessingError(int $registrations_processed): bool
816
-    {
817
-        // generate a correctly translated string for all possible singular/plural combinations
818
-        if ($this->checkout->total_ticket_count === 1 && $registrations_processed !== 1) {
819
-            $error_msg = sprintf(
820
-                esc_html_x(
821
-                    'There was %1$d ticket in the Event Queue, but %2$ds registrations were processed',
822
-                    'There was 1 ticket in the Event Queue, but 2 registrations were processed',
823
-                    'event_espresso'
824
-                ),
825
-                $this->checkout->total_ticket_count,
826
-                $registrations_processed
827
-            );
828
-        } elseif ($this->checkout->total_ticket_count !== 1 && $registrations_processed === 1) {
829
-            $error_msg = sprintf(
830
-                esc_html_x(
831
-                    'There was a total of %1$d tickets in the Event Queue, but only %2$ds registration was processed',
832
-                    'There was a total of 2 tickets in the Event Queue, but only 1 registration was processed',
833
-                    'event_espresso'
834
-                ),
835
-                $this->checkout->total_ticket_count,
836
-                $registrations_processed
837
-            );
838
-        } else {
839
-            $error_msg = sprintf(
840
-                esc_html__(
841
-                    'There was a total of 2 tickets in the Event Queue, but 2 registrations were processed',
842
-                    'event_espresso'
843
-                ),
844
-                $this->checkout->total_ticket_count,
845
-                $registrations_processed
846
-            );
847
-        }
848
-        EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
849
-        return false;
850
-    }
851
-
852
-
853
-    /**
854
-     *    update_reg_step
855
-     *    this is the final step after a user  revisits the site to edit their attendee information
856
-     *    this gets called AFTER the process_reg_step() method above
857
-     *
858
-     * @return bool
859
-     * @throws EE_Error
860
-     * @throws InvalidArgumentException
861
-     * @throws ReflectionException
862
-     * @throws RuntimeException
863
-     * @throws InvalidDataTypeException
864
-     * @throws InvalidInterfaceException
865
-     */
866
-    public function update_reg_step(): bool
867
-    {
868
-        // save everything
869
-        if ($this->process_reg_step()) {
870
-            $this->checkout->redirect     = true;
871
-            $this->checkout->redirect_url = add_query_arg(
872
-                [
873
-                    'e_reg_url_link' => $this->checkout->reg_url_link,
874
-                    'revisit'        => true,
875
-                ],
876
-                $this->checkout->thank_you_page_url
877
-            );
878
-            $this->checkout->json_response->set_redirect_url($this->checkout->redirect_url);
879
-            return true;
880
-        }
881
-        return false;
882
-    }
25
+	/**
26
+	 * @var RegForm
27
+	 */
28
+	public $reg_form;
29
+
30
+	/**
31
+	 * @var int
32
+	 */
33
+	protected $reg_form_count = 0;
34
+
35
+
36
+	/**
37
+	 *    class constructor
38
+	 *
39
+	 * @access    public
40
+	 * @param EE_Checkout $checkout
41
+	 */
42
+	public function __construct(EE_Checkout $checkout)
43
+	{
44
+		$this->_slug    = 'attendee_information';
45
+		$this->_name    = esc_html__('Attendee Information', 'event_espresso');
46
+		$this->checkout = $checkout;
47
+		$this->_reset_success_message();
48
+		$this->set_instructions(
49
+			esc_html__('Please answer the following registration questions before proceeding.', 'event_espresso')
50
+		);
51
+	}
52
+
53
+
54
+	public function translate_js_strings()
55
+	{
56
+		EE_Registry::$i18n_js_strings['required_field']            = esc_html__(
57
+			' is a required question.',
58
+			'event_espresso'
59
+		);
60
+		EE_Registry::$i18n_js_strings['required_multi_field']      = esc_html__(
61
+			' is a required question. Please enter a value for at least one of the options.',
62
+			'event_espresso'
63
+		);
64
+		EE_Registry::$i18n_js_strings['answer_required_questions'] = esc_html__(
65
+			'Please answer all required questions correctly before proceeding.',
66
+			'event_espresso'
67
+		);
68
+		EE_Registry::$i18n_js_strings['attendee_info_copied']      = sprintf(
69
+			esc_html_x(
70
+				'The attendee information was successfully copied.%sPlease ensure the rest of the registration form is completed before proceeding.',
71
+				'The attendee information was successfully copied.(line break)Please ensure the rest of the registration form is completed before proceeding.',
72
+				'event_espresso'
73
+			),
74
+			'<br/>'
75
+		);
76
+		EE_Registry::$i18n_js_strings['attendee_info_copy_error']  = esc_html__(
77
+			'An unknown error occurred on the server while attempting to copy the attendee information. Please refresh the page and try again.',
78
+			'event_espresso'
79
+		);
80
+		EE_Registry::$i18n_js_strings['enter_valid_email']         = esc_html__(
81
+			'You must enter a valid email address.',
82
+			'event_espresso'
83
+		);
84
+		EE_Registry::$i18n_js_strings['valid_email_and_questions'] = esc_html__(
85
+			'You must enter a valid email address and answer all other required questions before you can proceed.',
86
+			'event_espresso'
87
+		);
88
+	}
89
+
90
+
91
+	public function enqueue_styles_and_scripts()
92
+	{
93
+	}
94
+
95
+
96
+	/**
97
+	 * @return boolean
98
+	 */
99
+	public function initialize_reg_step(): bool
100
+	{
101
+		return true;
102
+	}
103
+
104
+
105
+	/**
106
+	 * @return RegForm
107
+	 * @throws DomainException
108
+	 * @throws InvalidArgumentException
109
+	 * @throws EntityNotFoundException
110
+	 * @throws InvalidDataTypeException
111
+	 * @throws InvalidInterfaceException
112
+	 */
113
+	public function generate_reg_form(): RegForm
114
+	{
115
+		$this->setLegacyFiltersForRegFormGeneration();
116
+		/** @var RegFormDependencyHandler $dependency_handler */
117
+		$dependency_handler = LoaderFactory::getShared(RegFormDependencyHandler::class);
118
+		$dependency_handler->registerDependencies();
119
+		// TODO detect if event has a reg form UUID and swap this out for form generated by new reg form builder
120
+		return LoaderFactory::getShared(RegForm::class, [$this]);
121
+	}
122
+
123
+
124
+	/**
125
+	 * @since   5.0.0.p
126
+	 */
127
+	private function setLegacyFiltersForRegFormGeneration()
128
+	{
129
+		add_filter(
130
+			'FHEE__EventEspresso_core_domain_services_registration_form_v1_RegistrantForm__generateFormArgs__question_groups_query_parameters',
131
+			[$this, 'registrationQuestionGroupsQueryParameters'],
132
+			1,
133
+			2
134
+		);
135
+		add_filter(
136
+			'FHEE__EventEspresso_core_domain_services_registration_form_v1_RegistrantForm__generateFormArgs__question_group_reg_form',
137
+			[$this, 'registrationQuestionGroupsRegForm'],
138
+			1,
139
+			3
140
+		);
141
+		add_filter(
142
+			'FHEE__EventEspresso_core_domain_services_registration_form_v1_RegistrantForm__generateFormArgs__printCopyInfo',
143
+			[$this, 'registrationRegFormPrintCopyInfo'],
144
+			1,
145
+			2
146
+		);
147
+		add_filter(
148
+			'FHEE__EventEspresso_core_domain_services_registration_form_v1_RegFormQuestionGroup__generateFormArgs__related_questions_query_params',
149
+			[$this, 'registrationRegFormRelatedQuestionsQueryParams'],
150
+			1,
151
+			3
152
+		);
153
+		add_filter(
154
+			'FHEE__EventEspresso_core_domain_services_registration_form_v1_RegFormQuestionGroup__generateFormArgs__before_question_group_questions',
155
+			[$this, 'registrationRegFormBeforeQuestionGroupQuestions'],
156
+			1,
157
+			3
158
+		);
159
+		add_filter(
160
+			'FHEE__EventEspresso_core_domain_services_registration_form_v1_RegFormQuestionGroup__generateFormArgs__subsections_array',
161
+			[$this, 'registrationRegFormSubsections'],
162
+			1,
163
+			3
164
+		);
165
+		add_filter(
166
+			'FHEE__EventEspresso_core_domain_services_registration_form_v1_RegFormQuestionGroup__generateFormArgs__after_question_group_questions',
167
+			[$this, 'registrationRegFormAfterQuestionGroupQuestions'],
168
+			1,
169
+			3
170
+		);
171
+		add_filter(
172
+			'FHEE__EventEspresso_core_domain_services_registration_form_v1_AutoCopyAttendeeInfoForm__construct__template_args',
173
+			[$this, 'autoCopyAttendeeInfoTemplateArgs'],
174
+			1
175
+		);
176
+		add_filter(
177
+			'FHEE__EventEspresso_core_domain_services_registration_form_v1_CountryOptions__generateLegacyCountryOptions__country_options',
178
+			[$this, 'generateQuestionInputCountryOptions'],
179
+			1,
180
+			4
181
+		);
182
+		add_filter(
183
+			'FHEE__EventEspresso_core_domain_services_registration_form_v1_StateOptions__generateLegacyStateOptions__state_options',
184
+			[$this, 'generateQuestionInputStateOptions'],
185
+			1,
186
+			4
187
+		);
188
+	}
189
+
190
+
191
+	/**
192
+	 * @param array           $query_params
193
+	 * @param EE_Registration $registration
194
+	 * @return mixed|void
195
+	 * @since   5.0.0.p
196
+	 */
197
+	public function registrationQuestionGroupsQueryParameters(
198
+		array $query_params,
199
+		EE_Registration $registration
200
+	) {
201
+		return apply_filters(
202
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___registrations_reg_form__question_groups_query_parameters',
203
+			$query_params,
204
+			$registration,
205
+			$this
206
+		);
207
+	}
208
+
209
+
210
+	/**
211
+	 * @param RegFormQuestionGroup $question_group_reg_form
212
+	 * @param EE_Registration      $registration
213
+	 * @param EE_Question_Group    $question_group
214
+	 * @return mixed|void
215
+	 * @since   5.0.0.p
216
+	 */
217
+	public function registrationQuestionGroupsRegForm(
218
+		RegFormQuestionGroup $question_group_reg_form,
219
+		EE_Registration $registration,
220
+		EE_Question_Group $question_group
221
+	) {
222
+		return apply_filters(
223
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__question_group_reg_form',
224
+			$question_group_reg_form,
225
+			$registration,
226
+			$question_group,
227
+			$this
228
+		);
229
+	}
230
+
231
+
232
+	/**
233
+	 * @param int $print_copy_info
234
+	 * @param int $attendee_nmbr
235
+	 * @return mixed|void
236
+	 * @since   5.0.0.p
237
+	 */
238
+	public function registrationRegFormPrintCopyInfo(
239
+		int $print_copy_info,
240
+		int $attendee_nmbr
241
+	) {
242
+		return apply_filters(
243
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___registrations_reg_form___printCopyInfo',
244
+			$print_copy_info,
245
+			$attendee_nmbr
246
+		);
247
+	}
248
+
249
+
250
+	/**
251
+	 * @param array             $query_params
252
+	 * @param EE_Question_Group $question_group
253
+	 * @param EE_Registration   $registration
254
+	 * @return mixed|void
255
+	 * @since   5.0.0.p
256
+	 */
257
+	public function registrationRegFormRelatedQuestionsQueryParams(
258
+		array $query_params,
259
+		EE_Question_Group $question_group,
260
+		EE_Registration $registration
261
+	) {
262
+		return apply_filters(
263
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__related_questions_query_params',
264
+			$query_params,
265
+			$question_group,
266
+			$registration,
267
+			$this
268
+		);
269
+	}
270
+
271
+
272
+	/**
273
+	 * @param                   $html
274
+	 * @param EE_Registration   $registration
275
+	 * @param EE_Question_Group $question_group
276
+	 * @return mixed|void
277
+	 * @since   5.0.0.p
278
+	 */
279
+	public function registrationRegFormBeforeQuestionGroupQuestions(
280
+		$html,
281
+		EE_Registration $registration,
282
+		EE_Question_Group $question_group
283
+	) {
284
+		return apply_filters(
285
+			'FHEE__EEH_Form_Fields__generate_question_groups_html__before_question_group_questions',
286
+			$html,
287
+			$registration,
288
+			$question_group,
289
+			$this
290
+		);
291
+	}
292
+
293
+
294
+	/**
295
+	 * @param array             $form_subsections
296
+	 * @param EE_Registration   $registration
297
+	 * @param EE_Question_Group $question_group
298
+	 * @return mixed|void
299
+	 * @since   5.0.0.p
300
+	 */
301
+	public function registrationRegFormSubsections(
302
+		array $form_subsections,
303
+		EE_Registration $registration,
304
+		EE_Question_Group $question_group
305
+	) {
306
+		return apply_filters(
307
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information__question_group_reg_form__subsections_array',
308
+			$form_subsections,
309
+			$registration,
310
+			$question_group,
311
+			$this
312
+		);
313
+	}
314
+
315
+
316
+	/**
317
+	 * @param                   $html
318
+	 * @param EE_Registration   $registration
319
+	 * @param EE_Question_Group $question_group
320
+	 * @return mixed|void
321
+	 * @since   5.0.0.p
322
+	 */
323
+	public function registrationRegFormAfterQuestionGroupQuestions(
324
+		$html,
325
+		EE_Registration $registration,
326
+		EE_Question_Group $question_group
327
+	) {
328
+		return apply_filters(
329
+			'FHEE__EEH_Form_Fields__generate_question_groups_html__after_question_group_questions',
330
+			$html,
331
+			$registration,
332
+			$question_group,
333
+			$this
334
+		);
335
+	}
336
+
337
+
338
+	/**
339
+	 * @param array $template_args
340
+	 * @return mixed|void
341
+	 * @since   5.0.0.p
342
+	 */
343
+	public function autoCopyAttendeeInfoTemplateArgs(array $template_args = [])
344
+	{
345
+		return apply_filters(
346
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information__auto_copy_attendee_info__template_args',
347
+			$template_args
348
+		);
349
+	}
350
+
351
+
352
+	/**
353
+	 * @param array           $country_options
354
+	 * @param EE_Registration $registration
355
+	 * @param EE_Question     $question
356
+	 * @param EE_Answer|null  $answer
357
+	 * @return mixed|void
358
+	 * @since   5.0.0.p
359
+	 */
360
+	public function generateQuestionInputCountryOptions(
361
+		array $country_options,
362
+		EE_Registration $registration,
363
+		EE_Question $question,
364
+		?EE_Answer $answer
365
+	) {
366
+		return apply_filters(
367
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__country_options',
368
+			$country_options,
369
+			$this,
370
+			$registration,
371
+			$question,
372
+			$answer
373
+		);
374
+	}
375
+
376
+
377
+	/**
378
+	 * @param array           $state_options
379
+	 * @param EE_Registration $registration
380
+	 * @param EE_Question     $question
381
+	 * @param EE_Answer|null  $answer
382
+	 * @return mixed|void
383
+	 * @since   5.0.0.p
384
+	 */
385
+	public function generateQuestionInputStateOptions(
386
+		array $state_options,
387
+		EE_Registration $registration,
388
+		EE_Question $question,
389
+		?EE_Answer $answer
390
+	) {
391
+		return apply_filters(
392
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__state_options',
393
+			$state_options,
394
+			$this,
395
+			$registration,
396
+			$question,
397
+			$answer
398
+		);
399
+	}
400
+
401
+
402
+	/**
403
+	 * looking for hooks?
404
+	 * this method has been replaced by:
405
+	 * EventEspresso\core\domain\services\registration\form\v1\RegForm::getRegForm()
406
+	 *
407
+	 * @deprecated   5.0.0.p
408
+	 */
409
+	private function _registrations_reg_form()
410
+	{
411
+	}
412
+
413
+
414
+	/**
415
+	 * looking for hooks?
416
+	 * this method has been replaced by:
417
+	 * EventEspresso\core\domain\services\registration\form\v1\RegForm::additionalAttendeeRegInfoInput()
418
+	 *
419
+	 * @deprecated   5.0.0.p
420
+	 */
421
+	private function _additional_attendee_reg_info_input()
422
+	{
423
+	}
424
+
425
+
426
+	/**
427
+	 * looking for hooks?
428
+	 * this method has been replaced by:
429
+	 * EventEspresso\core\domain\services\registration\form\v1\RegForm::questionGroupRegForm()
430
+	 *
431
+	 * @deprecated   5.0.0.p
432
+	 */
433
+	private function _question_group_reg_form()
434
+	{
435
+	}
436
+
437
+
438
+	/**
439
+	 * looking for hooks?
440
+	 * this method has been replaced by:
441
+	 * EventEspresso\core\domain\services\registration\form\v1\RegForm::questionGroupHeader()
442
+	 *
443
+	 * @deprecated   5.0.0.p
444
+	 */
445
+	private function _question_group_header()
446
+	{
447
+	}
448
+
449
+
450
+	/**
451
+	 * looking for hooks?
452
+	 * this method has been replaced by:
453
+	 * EventEspresso\core\domain\services\registration\form\v1\CopyAttendeeInfoForm
454
+	 *
455
+	 * @deprecated   5.0.0.p
456
+	 */
457
+	private function _copy_attendee_info_form()
458
+	{
459
+	}
460
+
461
+
462
+	/**
463
+	 * looking for hooks?
464
+	 * this method has been replaced by:
465
+	 * EventEspresso\core\domain\services\registration\form\v1\AutoCopyAttendeeInfoForm
466
+	 *
467
+	 * @deprecated   5.0.0.p
468
+	 */
469
+	private function _auto_copy_attendee_info()
470
+	{
471
+	}
472
+
473
+
474
+	/**
475
+	 * looking for hooks?
476
+	 * this method has been replaced by:
477
+	 * EventEspresso\core\domain\services\registration\form\v1\CopyAttendeeInfoForm
478
+	 *
479
+	 * @deprecated   5.0.0.p
480
+	 */
481
+	private function _copy_attendee_info_inputs()
482
+	{
483
+	}
484
+
485
+
486
+	/**
487
+	 * looking for hooks?
488
+	 * this method has been replaced by:
489
+	 * EventEspresso\core\domain\services\registration\form\v1\RegForm::additionalPrimaryRegistrantInputs()
490
+	 *
491
+	 * @deprecated   5.0.0.p
492
+	 */
493
+	private function _additional_primary_registrant_inputs()
494
+	{
495
+	}
496
+
497
+
498
+	/**
499
+	 * looking for hooks?
500
+	 * this method has been replaced by:
501
+	 * EventEspresso\core\domain\services\registration\form\v1\RegFormQuestionFactory::create()
502
+	 *
503
+	 * @param EE_Registration $registration
504
+	 * @param EE_Question     $question
505
+	 * @return EE_Form_Input_Base
506
+	 * @throws EE_Error
507
+	 * @throws ReflectionException
508
+	 * @deprecated   5.0.0.p
509
+	 */
510
+	public function reg_form_question(EE_Registration $registration, EE_Question $question): EE_Form_Input_Base
511
+	{
512
+		/** @var RegFormQuestionFactory $reg_form_question_factory */
513
+		$reg_form_question_factory = LoaderFactory::getShared(RegFormQuestionFactory::class);
514
+		return $reg_form_question_factory->create($registration, $question);
515
+	}
516
+
517
+
518
+	/**
519
+	 * looking for hooks?
520
+	 * this method has been replaced by:
521
+	 * EventEspresso\core\domain\services\registration\form\v1\RegForm::generateQuestionInput()
522
+	 *
523
+	 * @deprecated   5.0.0.p
524
+	 */
525
+	private function _generate_question_input()
526
+	{
527
+	}
528
+
529
+
530
+	/**
531
+	 * looking for hooks?
532
+	 * this method has been replaced by:
533
+	 * EventEspresso\core\domain\services\registration\form\v1\CountryOptions::forLegacyFormInput()
534
+	 *
535
+	 * @param array|null           $countries_list
536
+	 * @param EE_Question|null     $question
537
+	 * @param EE_Registration|null $registration
538
+	 * @param EE_Answer|null       $answer
539
+	 * @return array 2d keys are country IDs, values are their names
540
+	 * @throws EE_Error
541
+	 * @throws ReflectionException
542
+	 * @deprecated   5.0.0.p
543
+	 */
544
+	public function use_cached_countries_for_form_input(
545
+		array $countries_list = null,
546
+		EE_Question $question = null,
547
+		EE_Registration $registration = null,
548
+		EE_Answer $answer = null
549
+	): array {
550
+		/** @var CountryOptions $country_options */
551
+		$country_options = LoaderFactory::getShared(CountryOptions::class, [$this->checkout->action]);
552
+		return $country_options->forLegacyFormInput($countries_list, $question, $registration, $answer);
553
+	}
554
+
555
+
556
+	/**
557
+	 * looking for hooks?
558
+	 * this method has been replaced by:
559
+	 * EventEspresso\core\domain\services\registration\form\v1\StateOptions::forLegacyFormInput()
560
+	 *
561
+	 * @param array|null           $states_list
562
+	 * @param EE_Question|null     $question
563
+	 * @param EE_Registration|null $registration
564
+	 * @param EE_Answer|null       $answer
565
+	 * @return array 2d keys are state IDs, values are their names
566
+	 * @throws EE_Error
567
+	 * @throws ReflectionException
568
+	 * @deprecated   5.0.0.p
569
+	 */
570
+	public function use_cached_states_for_form_input(
571
+		array $states_list = null,
572
+		EE_Question $question = null,
573
+		EE_Registration $registration = null,
574
+		EE_Answer $answer = null
575
+	): array {
576
+		/** @var StateOptions $state_options */
577
+		$state_options = LoaderFactory::getShared(StateOptions::class, [$this->checkout->action]);
578
+		return $state_options->forLegacyFormInput($states_list, $question, $registration, $answer);
579
+	}
580
+
581
+
582
+	/********************************************************************************************************/
583
+	/****************************************  PROCESS REG STEP  ****************************************/
584
+	/********************************************************************************************************/
585
+
586
+
587
+	/**
588
+	 * @return bool
589
+	 * @throws EE_Error
590
+	 * @throws InvalidArgumentException
591
+	 * @throws ReflectionException
592
+	 * @throws RuntimeException
593
+	 * @throws InvalidDataTypeException
594
+	 * @throws InvalidInterfaceException
595
+	 */
596
+	public function process_reg_step(): bool
597
+	{
598
+		$this->setLegacyFiltersForRegFormProcessing();
599
+		// grab validated data from form
600
+		$valid_data = $this->checkout->current_step->valid_data();
601
+		// if we don't have any $valid_data then something went TERRIBLY WRONG !!!
602
+		if (empty($valid_data)) {
603
+			return $this->inValidDataError();
604
+		}
605
+		if (! $this->checkout->transaction instanceof EE_Transaction || ! $this->checkout->continue_reg) {
606
+			return $this->inValidTransactionError();
607
+		}
608
+		// get cached registrations
609
+		$registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
610
+		// verify we got the goods
611
+		if (empty($registrations)) {
612
+			return $this->noRegistrationsError();
613
+		}
614
+		/** @var RegFormHandler $reg_form_handler */
615
+		$reg_form_handler = LoaderFactory::getNew(RegFormHandler::class, [$this->checkout]);
616
+		// extract attendee info from form data and save to model objects
617
+		if (! $reg_form_handler->processRegistrations($registrations, $valid_data)) {
618
+			// return immediately if the previous step exited early due to errors
619
+			return false;
620
+		}
621
+		// if first pass thru SPCO,
622
+		// then let's check processed registrations against the total number of tickets in the cart
623
+		$registrations_processed = $reg_form_handler->attendeeCount();
624
+		if (! $this->checkout->revisit && $registrations_processed !== $this->checkout->total_ticket_count) {
625
+			return $this->registrationProcessingError($registrations_processed);
626
+		}
627
+		// mark this reg step as completed
628
+		$this->set_completed();
629
+		$this->_set_success_message(
630
+			esc_html__('The Attendee Information Step has been successfully completed.', 'event_espresso')
631
+		);
632
+		// do action in case a plugin wants to do something with the data submitted in step 1.
633
+		// passes EE_Single_Page_Checkout, and it's posted data
634
+		do_action('AHEE__EE_Single_Page_Checkout__process_attendee_information__end', $this, $valid_data);
635
+		return true;
636
+	}
637
+
638
+
639
+	/**
640
+	 * @since   5.0.0.p
641
+	 */
642
+	private function setLegacyFiltersForRegFormProcessing()
643
+	{
644
+		add_filter(
645
+			'FHEE__EventEspresso_core_domain_services_registration_form_v1_RegFormHandler__processRegistrations__bypass',
646
+			[$this, 'preRegistrationProcess'],
647
+			1,
648
+			5
649
+		);
650
+		add_filter(
651
+			'FHEE__EventEspresso_core_domain_services_registration_form_v1_RegFormHandler__processRegFormData__registrant_form_data',
652
+			[$this, 'validDataLineItem'],
653
+			1,
654
+			2
655
+		);
656
+		add_filter(
657
+			'FHEE__EventEspresso_core_domain_services_registration_form_v1_RegFormInputHandler__saveRegistrationFormInput',
658
+			[$this, 'saveRegistrationFormInput'],
659
+			1,
660
+			4
661
+		);
662
+		add_filter(
663
+			'FHEE__EventEspresso_core_domain_services_registration_form_v1_RegistrantData__ensureCriticalRegistrantDataIsSet',
664
+			[$this, 'mergeAddressDetailsWithCriticalAttendeeDetails'],
665
+			1
666
+		);
667
+	}
668
+
669
+
670
+	/**
671
+	 * @param bool            $bypass
672
+	 * @param int             $attendee_count
673
+	 * @param EE_Registration $registration
674
+	 * @param array           $registrations
675
+	 * @param array           $reg_form_data
676
+	 * @return mixed|void
677
+	 * @since   5.0.0.p
678
+	 */
679
+	public function preRegistrationProcess(
680
+		bool $bypass,
681
+		int $attendee_count,
682
+		EE_Registration $registration,
683
+		array $registrations,
684
+		array $reg_form_data
685
+	) {
686
+		return apply_filters(
687
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___process_registrations__pre_registration_process',
688
+			$bypass,
689
+			$attendee_count,
690
+			$registration,
691
+			$registrations,
692
+			$reg_form_data,
693
+			$this
694
+		);
695
+	}
696
+
697
+
698
+	/**
699
+	 * @param array           $reg_form_data
700
+	 * @param EE_Registration $registration
701
+	 * @return mixed|void
702
+	 * @since   5.0.0.p
703
+	 */
704
+	public function validDataLineItem(array $reg_form_data, EE_Registration $registration)
705
+	{
706
+		return apply_filters(
707
+			'FHEE__EE_Single_Page_Checkout__process_attendee_information__valid_data_line_item',
708
+			$reg_form_data,
709
+			$registration
710
+		);
711
+	}
712
+
713
+
714
+	/**
715
+	 * @param bool            $save
716
+	 * @param EE_Registration $registration
717
+	 * @param                 $form_input
718
+	 * @param                 $input_value
719
+	 * @return mixed|void
720
+	 * @since   5.0.0.p
721
+	 */
722
+	public function saveRegistrationFormInput(bool $save, EE_Registration $registration, $form_input, $input_value)
723
+	{
724
+		return apply_filters(
725
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___save_registration_form_input',
726
+			$save,
727
+			$registration,
728
+			$form_input,
729
+			$input_value,
730
+			$this
731
+		);
732
+	}
733
+
734
+
735
+	/**
736
+	 * @param bool $merge_data
737
+	 * @return mixed|void
738
+	 * @since   5.0.0.p
739
+	 */
740
+	public function mergeAddressDetailsWithCriticalAttendeeDetails(bool $merge_data)
741
+	{
742
+		return apply_filters(
743
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information__merge_address_details_with_critical_attendee_details',
744
+			$merge_data
745
+		);
746
+	}
747
+
748
+
749
+	/**
750
+	 * @return bool
751
+	 * @since   5.0.0.p
752
+	 */
753
+	private function inValidDataError(): bool
754
+	{
755
+		EE_Error::add_error(
756
+			esc_html__('No valid question responses were received.', 'event_espresso'),
757
+			__FILE__,
758
+			__FUNCTION__,
759
+			__LINE__
760
+		);
761
+		return false;
762
+	}
763
+
764
+
765
+	/**
766
+	 * @return bool
767
+	 * @since   5.0.0.p
768
+	 */
769
+	private function inValidTransactionError(): bool
770
+	{
771
+		EE_Error::add_error(
772
+			esc_html__(
773
+				'A valid transaction could not be initiated for processing your registrations.',
774
+				'event_espresso'
775
+			),
776
+			__FILE__,
777
+			__FUNCTION__,
778
+			__LINE__
779
+		);
780
+		return false;
781
+	}
782
+
783
+
784
+	/**
785
+	 * @return bool
786
+	 * @since   5.0.0.p
787
+	 */
788
+	private function noRegistrationsError(): bool
789
+	{
790
+		// combine the old translated string with a new one, in order to not break translations
791
+		$error_message = esc_html__(
792
+			'Your form data could not be applied to any valid registrations.',
793
+			'event_espresso'
794
+		);
795
+		$error_message .= sprintf(
796
+			esc_html_x(
797
+				'%3$sThis can sometimes happen if too much time has been taken to complete the registration process.%3$sPlease return to the %1$sEvent List%2$s and reselect your tickets. If the problem continues, please contact the site administrator.',
798
+				'(line break)This can sometimes happen if too much time has been taken to complete the registration process.(line break)Please return to the (link)Event List(end link) and reselect your tickets. If the problem continues, please contact the site administrator.',
799
+				'event_espresso'
800
+			),
801
+			'<a href="' . get_post_type_archive_link('espresso_events') . '" >',
802
+			'</a>',
803
+			'<br />'
804
+		);
805
+		EE_Error::add_error($error_message, __FILE__, __FUNCTION__, __LINE__);
806
+		return false;
807
+	}
808
+
809
+
810
+	/**
811
+	 * @param int $registrations_processed
812
+	 * @return bool
813
+	 * @since   5.0.0.p
814
+	 */
815
+	private function registrationProcessingError(int $registrations_processed): bool
816
+	{
817
+		// generate a correctly translated string for all possible singular/plural combinations
818
+		if ($this->checkout->total_ticket_count === 1 && $registrations_processed !== 1) {
819
+			$error_msg = sprintf(
820
+				esc_html_x(
821
+					'There was %1$d ticket in the Event Queue, but %2$ds registrations were processed',
822
+					'There was 1 ticket in the Event Queue, but 2 registrations were processed',
823
+					'event_espresso'
824
+				),
825
+				$this->checkout->total_ticket_count,
826
+				$registrations_processed
827
+			);
828
+		} elseif ($this->checkout->total_ticket_count !== 1 && $registrations_processed === 1) {
829
+			$error_msg = sprintf(
830
+				esc_html_x(
831
+					'There was a total of %1$d tickets in the Event Queue, but only %2$ds registration was processed',
832
+					'There was a total of 2 tickets in the Event Queue, but only 1 registration was processed',
833
+					'event_espresso'
834
+				),
835
+				$this->checkout->total_ticket_count,
836
+				$registrations_processed
837
+			);
838
+		} else {
839
+			$error_msg = sprintf(
840
+				esc_html__(
841
+					'There was a total of 2 tickets in the Event Queue, but 2 registrations were processed',
842
+					'event_espresso'
843
+				),
844
+				$this->checkout->total_ticket_count,
845
+				$registrations_processed
846
+			);
847
+		}
848
+		EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
849
+		return false;
850
+	}
851
+
852
+
853
+	/**
854
+	 *    update_reg_step
855
+	 *    this is the final step after a user  revisits the site to edit their attendee information
856
+	 *    this gets called AFTER the process_reg_step() method above
857
+	 *
858
+	 * @return bool
859
+	 * @throws EE_Error
860
+	 * @throws InvalidArgumentException
861
+	 * @throws ReflectionException
862
+	 * @throws RuntimeException
863
+	 * @throws InvalidDataTypeException
864
+	 * @throws InvalidInterfaceException
865
+	 */
866
+	public function update_reg_step(): bool
867
+	{
868
+		// save everything
869
+		if ($this->process_reg_step()) {
870
+			$this->checkout->redirect     = true;
871
+			$this->checkout->redirect_url = add_query_arg(
872
+				[
873
+					'e_reg_url_link' => $this->checkout->reg_url_link,
874
+					'revisit'        => true,
875
+				],
876
+				$this->checkout->thank_you_page_url
877
+			);
878
+			$this->checkout->json_response->set_redirect_url($this->checkout->redirect_url);
879
+			return true;
880
+		}
881
+		return false;
882
+	}
883 883
 }
Please login to merge, or discard this patch.
modules/core_rest_api/EED_Core_Rest_Api.module.php 1 patch
Indentation   +1378 added lines, -1378 removed lines patch added patch discarded remove patch
@@ -21,1382 +21,1382 @@
 block discarded – undo
21 21
  */
22 22
 class EED_Core_Rest_Api extends EED_Module
23 23
 {
24
-    const ee_api_namespace = Domain::API_NAMESPACE;
25
-
26
-    const ee_api_namespace_for_regex = 'ee\/v([^/]*)\/';
27
-
28
-    const saved_routes_option_names = 'ee_core_routes';
29
-
30
-    /**
31
-     * string used in _links response bodies to make them globally unique.
32
-     *
33
-     * @see http://v2.wp-api.org/extending/linking/
34
-     */
35
-    const ee_api_link_namespace = 'https://api.eventespresso.com/';
36
-
37
-    /**
38
-     * @var CalculatedModelFields
39
-     */
40
-    protected static $_field_calculator;
41
-
42
-
43
-    /**
44
-     * @return EED_Core_Rest_Api|EED_Module
45
-     */
46
-    public static function instance()
47
-    {
48
-        return parent::get_instance(EED_Core_Rest_Api::class);
49
-    }
50
-
51
-
52
-    /**
53
-     *    set_hooks - for hooking into EE Core, other modules, etc
54
-     *
55
-     * @access    public
56
-     * @return    void
57
-     */
58
-    public static function set_hooks()
59
-    {
60
-    }
61
-
62
-
63
-    /**
64
-     *    set_hooks_admin - for hooking into EE Admin Core, other modules, etc
65
-     *
66
-     * @access    public
67
-     * @return    void
68
-     */
69
-    public static function set_hooks_admin()
70
-    {
71
-    }
72
-
73
-
74
-    public static function set_hooks_both()
75
-    {
76
-        add_action('rest_api_init', ['EED_Core_Rest_Api', 'set_hooks_rest_api'], 5);
77
-        add_action('rest_api_init', ['EED_Core_Rest_Api', 'register_routes'], 10);
78
-        add_filter('rest_route_data', ['EED_Core_Rest_Api', 'hide_old_endpoints'], 10, 2);
79
-        add_filter(
80
-            'rest_index',
81
-            ['EventEspresso\core\libraries\rest_api\controllers\model\Meta', 'filterEeMetadataIntoIndex']
82
-        );
83
-    }
84
-
85
-
86
-    /**
87
-     * @since   5.0.0.p
88
-     */
89
-    public static function loadCalculatedModelFields()
90
-    {
91
-        EED_Core_Rest_Api::$_field_calculator = LoaderFactory::getLoader()->load(
92
-            'EventEspresso\core\libraries\rest_api\CalculatedModelFields'
93
-        );
94
-        EED_Core_Rest_Api::invalidate_cached_route_data_on_version_change();
95
-    }
96
-
97
-
98
-    /**
99
-     * sets up hooks which only need to be included as part of REST API requests;
100
-     * other requests like to the frontend or admin etc don't need them
101
-     *
102
-     * @throws EE_Error
103
-     */
104
-    public static function set_hooks_rest_api()
105
-    {
106
-        // set hooks which account for changes made to the API
107
-        EED_Core_Rest_Api::_set_hooks_for_changes();
108
-    }
109
-
110
-
111
-    /**
112
-     * public wrapper of _set_hooks_for_changes.
113
-     * Loads all the hooks which make requests to old versions of the API
114
-     * appear the same as they always did
115
-     *
116
-     * @throws EE_Error
117
-     */
118
-    public static function set_hooks_for_changes()
119
-    {
120
-        EED_Core_Rest_Api::_set_hooks_for_changes();
121
-    }
122
-
123
-
124
-    /**
125
-     * Loads all the hooks which make requests to old versions of the API
126
-     * appear the same as they always did
127
-     *
128
-     * @throws EE_Error
129
-     */
130
-    protected static function _set_hooks_for_changes()
131
-    {
132
-        $folder_contents = EEH_File::get_contents_of_folders([EE_LIBRARIES . 'rest_api/changes'], false);
133
-        foreach ($folder_contents as $classname_in_namespace => $filepath) {
134
-            // ignore the base parent class
135
-            // and legacy named classes
136
-            if (
137
-                $classname_in_namespace === 'ChangesInBase'
138
-                || strpos($classname_in_namespace, 'Changes_In_') === 0
139
-            ) {
140
-                continue;
141
-            }
142
-            $full_classname = 'EventEspresso\core\libraries\rest_api\changes\\' . $classname_in_namespace;
143
-            if (class_exists($full_classname)) {
144
-                $instance_of_class = new $full_classname();
145
-                if ($instance_of_class instanceof ChangesInBase) {
146
-                    $instance_of_class->setHooks();
147
-                }
148
-            }
149
-        }
150
-    }
151
-
152
-
153
-    /**
154
-     * Filters the WP routes to add our EE-related ones. This takes a bit of time
155
-     * so we actually prefer to only do it when an EE plugin is activated or upgraded
156
-     *
157
-     * @throws EE_Error
158
-     * @throws ReflectionException
159
-     */
160
-    public static function register_routes()
161
-    {
162
-        foreach (EED_Core_Rest_Api::get_ee_route_data() as $namespace => $relative_routes) {
163
-            foreach ($relative_routes as $relative_route => $data_for_multiple_endpoints) {
164
-                /**
165
-                 * @var array     $data_for_multiple_endpoints numerically indexed array
166
-                 *                                         but can also contain route options like {
167
-                 * @type array    $schema                      {
168
-                 * @type callable $schema_callback
169
-                 * @type array    $callback_args               arguments that will be passed to the callback, after the
170
-                 * WP_REST_Request of course
171
-                 * }
172
-                 * }
173
-                 */
174
-                // when registering routes, register all the endpoints' data at the same time
175
-                $multiple_endpoint_args = [];
176
-                foreach ($data_for_multiple_endpoints as $endpoint_key => $data_for_single_endpoint) {
177
-                    /**
178
-                     * @var array     $data_for_single_endpoint {
179
-                     * @type callable $callback
180
-                     * @type string methods
181
-                     * @type array args
182
-                     * @type array _links
183
-                     * @type array    $callback_args            arguments that will be passed to the callback, after the
184
-                     * WP_REST_Request of course
185
-                     * }
186
-                     */
187
-                    // skip route options
188
-                    if (! is_numeric($endpoint_key)) {
189
-                        continue;
190
-                    }
191
-                    if (! isset($data_for_single_endpoint['callback'], $data_for_single_endpoint['methods'])) {
192
-                        throw new EE_Error(
193
-                            esc_html__(
194
-                            // @codingStandardsIgnoreStart
195
-                                'Endpoint configuration data needs to have entries "callback" (callable) and "methods" (comma-separated list of accepts HTTP methods).',
196
-                                // @codingStandardsIgnoreEnd
197
-                                'event_espresso'
198
-                            )
199
-                        );
200
-                    }
201
-                    $callback = $data_for_single_endpoint['callback'];
202
-                    $single_endpoint_args = [
203
-                        'methods' => $data_for_single_endpoint['methods'],
204
-                        'args'    => isset($data_for_single_endpoint['args']) ? $data_for_single_endpoint['args']
205
-                            : [],
206
-                    ];
207
-                    if (isset($data_for_single_endpoint['_links'])) {
208
-                        $single_endpoint_args['_links'] = $data_for_single_endpoint['_links'];
209
-                    }
210
-                    if (isset($data_for_single_endpoint['callback_args'])) {
211
-                        $callback_args = $data_for_single_endpoint['callback_args'];
212
-                        $single_endpoint_args['callback'] = static function (WP_REST_Request $request) use (
213
-                            $callback,
214
-                            $callback_args
215
-                        ) {
216
-                            array_unshift($callback_args, $request);
217
-                            return call_user_func_array(
218
-                                $callback,
219
-                                $callback_args
220
-                            );
221
-                        };
222
-                    } else {
223
-                        $single_endpoint_args['callback'] = $data_for_single_endpoint['callback'];
224
-                    }
225
-                    // As of WordPress 5.5, if a permission_callback is not provided,
226
-                    // the REST API will issue a _doing_it_wrong notice.
227
-                    // Since the EE REST API defers capabilities to the db model system,
228
-                    // we will just use the generic WP callback for public endpoints
229
-                    if (! isset($single_endpoint_args['permission_callback'])) {
230
-                        $single_endpoint_args['permission_callback'] = '__return_true';
231
-                    }
232
-                    $multiple_endpoint_args[] = $single_endpoint_args;
233
-                }
234
-                if (isset($data_for_multiple_endpoints['schema'])) {
235
-                    $schema_route_data = $data_for_multiple_endpoints['schema'];
236
-                    $schema_callback = $schema_route_data['schema_callback'];
237
-                    $callback_args = $schema_route_data['callback_args'];
238
-                    $multiple_endpoint_args['schema'] = static function () use ($schema_callback, $callback_args) {
239
-                        return call_user_func_array(
240
-                            $schema_callback,
241
-                            $callback_args
242
-                        );
243
-                    };
244
-                }
245
-                register_rest_route(
246
-                    $namespace,
247
-                    $relative_route,
248
-                    $multiple_endpoint_args
249
-                );
250
-            }
251
-        }
252
-    }
253
-
254
-
255
-    /**
256
-     * Checks if there was a version change or something that merits invalidating the cached
257
-     * route data. If so, invalidates the cached route data so that it gets refreshed
258
-     * next time the WP API is used
259
-     */
260
-    public static function invalidate_cached_route_data_on_version_change()
261
-    {
262
-        if (EE_System::instance()->detect_req_type() !== EE_System::req_type_normal) {
263
-            EED_Core_Rest_Api::invalidate_cached_route_data();
264
-        }
265
-        foreach (EE_Registry::instance()->addons as $addon) {
266
-            if ($addon instanceof EE_Addon && $addon->detect_req_type() !== EE_System::req_type_normal) {
267
-                EED_Core_Rest_Api::invalidate_cached_route_data();
268
-            }
269
-        }
270
-    }
271
-
272
-
273
-    /**
274
-     * Removes the cached route data so it will get refreshed next time the WP API is used
275
-     */
276
-    public static function invalidate_cached_route_data()
277
-    {
278
-        // delete the saved EE REST API routes
279
-        foreach (EED_Core_Rest_Api::versions_served() as $version => $hidden) {
280
-            delete_option(EED_Core_Rest_Api::saved_routes_option_names . $version);
281
-        }
282
-    }
283
-
284
-
285
-    /**
286
-     * Gets the EE route data
287
-     *
288
-     * @return array top-level key is the namespace, next-level key is the route and its value is array{
289
-     * @throws EE_Error
290
-     * @throws ReflectionException
291
-     * @type string|array $callback
292
-     * @type string       $methods
293
-     * @type boolean      $hidden_endpoint
294
-     * }
295
-     */
296
-    public static function get_ee_route_data()
297
-    {
298
-        $ee_routes = [];
299
-        foreach (EED_Core_Rest_Api::versions_served() as $version => $hidden_endpoints) {
300
-            $ee_routes[ EED_Core_Rest_Api::ee_api_namespace . $version ] = EED_Core_Rest_Api::_get_ee_route_data_for_version(
301
-                $version,
302
-                $hidden_endpoints
303
-            );
304
-        }
305
-        return $ee_routes;
306
-    }
307
-
308
-
309
-    /**
310
-     * Gets the EE route data from the wp options if it exists already,
311
-     * otherwise re-generates it and saves it to the option
312
-     *
313
-     * @param string  $version
314
-     * @param boolean $hidden_endpoints
315
-     * @return array
316
-     * @throws EE_Error
317
-     * @throws ReflectionException
318
-     */
319
-    protected static function _get_ee_route_data_for_version($version, $hidden_endpoints = false)
320
-    {
321
-        $ee_routes = get_option(EED_Core_Rest_Api::saved_routes_option_names . $version, null);
322
-        if (! $ee_routes || EED_Core_Rest_Api::debugMode()) {
323
-            $ee_routes = EED_Core_Rest_Api::_save_ee_route_data_for_version($version, $hidden_endpoints);
324
-        }
325
-        return $ee_routes;
326
-    }
327
-
328
-
329
-    /**
330
-     * Saves the EE REST API route data to a wp option and returns it
331
-     *
332
-     * @param string  $version
333
-     * @param boolean $hidden_endpoints
334
-     * @return mixed|null
335
-     * @throws EE_Error
336
-     * @throws ReflectionException
337
-     */
338
-    protected static function _save_ee_route_data_for_version($version, $hidden_endpoints = false)
339
-    {
340
-        $instance = EED_Core_Rest_Api::instance();
341
-        $routes = apply_filters(
342
-            'EED_Core_Rest_Api__save_ee_route_data_for_version__routes',
343
-            array_replace_recursive(
344
-                $instance->_get_config_route_data_for_version($version, $hidden_endpoints),
345
-                $instance->_get_meta_route_data_for_version($version, $hidden_endpoints),
346
-                $instance->_get_model_route_data_for_version($version, $hidden_endpoints),
347
-                $instance->_get_rpc_route_data_for_version($version, $hidden_endpoints)
348
-            )
349
-        );
350
-        $option_name = EED_Core_Rest_Api::saved_routes_option_names . $version;
351
-        if (get_option($option_name)) {
352
-            update_option($option_name, $routes, true);
353
-        } else {
354
-            add_option($option_name, $routes, null, 'no');
355
-        }
356
-        return $routes;
357
-    }
358
-
359
-
360
-    /**
361
-     * Calculates all the EE routes and saves it to a WordPress option so we don't
362
-     * need to calculate it on every request
363
-     *
364
-     * @return void
365
-     * @deprecated since version 4.9.1
366
-     */
367
-    public static function save_ee_routes()
368
-    {
369
-        if (EE_Maintenance_Mode::instance()->models_can_query()) {
370
-            $instance = EED_Core_Rest_Api::instance();
371
-            $routes = apply_filters(
372
-                'EED_Core_Rest_Api__save_ee_routes__routes',
373
-                array_replace_recursive(
374
-                    $instance->_register_config_routes(),
375
-                    $instance->_register_meta_routes(),
376
-                    $instance->_register_model_routes(),
377
-                    $instance->_register_rpc_routes()
378
-                )
379
-            );
380
-            update_option(EED_Core_Rest_Api::saved_routes_option_names, $routes, true);
381
-        }
382
-    }
383
-
384
-
385
-    /**
386
-     * Gets all the route information relating to EE models
387
-     *
388
-     * @return array @see get_ee_route_data
389
-     * @deprecated since version 4.9.1
390
-     */
391
-    protected function _register_model_routes()
392
-    {
393
-        $model_routes = [];
394
-        foreach (EED_Core_Rest_Api::versions_served() as $version => $hidden_endpoint) {
395
-            $model_routes[ EED_Core_Rest_Api::ee_api_namespace
396
-                           . $version ] = $this->_get_config_route_data_for_version($version, $hidden_endpoint);
397
-        }
398
-        return $model_routes;
399
-    }
400
-
401
-
402
-    /**
403
-     * Decides whether or not to add write endpoints for this model.
404
-     * Currently, this defaults to exclude all global tables and models
405
-     * which would allow inserting WP core data (we don't want to duplicate
406
-     * what WP API does, as it's unnecessary, extra work, and potentially extra bugs)
407
-     *
408
-     * @param EEM_Base $model
409
-     * @return bool
410
-     */
411
-    public static function should_have_write_endpoints(EEM_Base $model)
412
-    {
413
-        if ($model->is_wp_core_model()) {
414
-            return false;
415
-        }
416
-        foreach ($model->get_tables() as $table) {
417
-            if ($table->is_global()) {
418
-                return false;
419
-            }
420
-        }
421
-        return true;
422
-    }
423
-
424
-
425
-    /**
426
-     * Gets the names of all models which should have plural routes (eg `ee/v4.8.36/events`)
427
-     * in this versioned namespace of EE4
428
-     *
429
-     * @param $version
430
-     * @return array keys are model names (eg 'Event') and values ar either classnames (eg 'EEM_Event')
431
-     */
432
-    public static function model_names_with_plural_routes($version)
433
-    {
434
-        $model_version_info = new ModelVersionInfo($version);
435
-        $models_to_register = $model_version_info->modelsForRequestedVersion();
436
-        // let's not bother having endpoints for extra metas
437
-        unset(
438
-            $models_to_register['Extra_Meta'],
439
-            $models_to_register['Extra_Join'],
440
-            $models_to_register['Post_Meta']
441
-        );
442
-        return apply_filters(
443
-            'FHEE__EED_Core_REST_API___register_model_routes',
444
-            $models_to_register
445
-        );
446
-    }
447
-
448
-
449
-    /**
450
-     * Gets the route data for EE models in the specified version
451
-     *
452
-     * @param string  $version
453
-     * @param boolean $hidden_endpoint
454
-     * @return array
455
-     * @throws EE_Error
456
-     * @throws ReflectionException
457
-     */
458
-    protected function _get_model_route_data_for_version($version, $hidden_endpoint = false)
459
-    {
460
-        $model_routes = [];
461
-        $model_version_info = new ModelVersionInfo($version);
462
-        foreach (EED_Core_Rest_Api::model_names_with_plural_routes($version) as $model_name => $model_classname) {
463
-            $model = EE_Registry::instance()->load_model($model_name);
464
-            // if this isn't a valid model then let's skip iterate to the next item in the loop.
465
-            if (! $model instanceof EEM_Base) {
466
-                continue;
467
-            }
468
-            // yes we could just register one route for ALL models, but then they wouldn't show up in the index
469
-            $plural_model_route = EED_Core_Rest_Api::get_collection_route($model);
470
-            $singular_model_route = EED_Core_Rest_Api::get_entity_route($model, '(?P<id>[^\/]+)');
471
-            $model_routes[ $plural_model_route ] = [
472
-                [
473
-                    'callback'        => [
474
-                        'EventEspresso\core\libraries\rest_api\controllers\model\Read',
475
-                        'handleRequestGetAll',
476
-                    ],
477
-                    'callback_args'   => [$version, $model_name],
478
-                    'methods'         => WP_REST_Server::READABLE,
479
-                    'hidden_endpoint' => $hidden_endpoint,
480
-                    'args'            => $this->_get_read_query_params($model, $version),
481
-                    '_links'          => [
482
-                        'self' => rest_url(EED_Core_Rest_Api::ee_api_namespace . $version . $singular_model_route),
483
-                    ],
484
-                ],
485
-                'schema' => [
486
-                    'schema_callback' => [
487
-                        'EventEspresso\core\libraries\rest_api\controllers\model\Read',
488
-                        'handleSchemaRequest',
489
-                    ],
490
-                    'callback_args'   => [$version, $model_name],
491
-                ],
492
-            ];
493
-            $model_routes[ $singular_model_route ] = [
494
-                [
495
-                    'callback'        => [
496
-                        'EventEspresso\core\libraries\rest_api\controllers\model\Read',
497
-                        'handleRequestGetOne',
498
-                    ],
499
-                    'callback_args'   => [$version, $model_name],
500
-                    'methods'         => WP_REST_Server::READABLE,
501
-                    'hidden_endpoint' => $hidden_endpoint,
502
-                    'args'            => $this->_get_response_selection_query_params($model, $version, true),
503
-                ],
504
-            ];
505
-            if (
506
-                apply_filters(
507
-                    'FHEE__EED_Core_Rest_Api___get_model_route_data_for_version__add_write_endpoints',
508
-                    EED_Core_Rest_Api::should_have_write_endpoints($model),
509
-                    $model
510
-                )
511
-            ) {
512
-                $model_routes[ $plural_model_route ][] = [
513
-                    'callback'        => [
514
-                        'EventEspresso\core\libraries\rest_api\controllers\model\Write',
515
-                        'handleRequestInsert',
516
-                    ],
517
-                    'callback_args'   => [$version, $model_name],
518
-                    'methods'         => WP_REST_Server::CREATABLE,
519
-                    'hidden_endpoint' => $hidden_endpoint,
520
-                    'args'            => $this->_get_write_params($model_name, $model_version_info, true),
521
-                ];
522
-                $model_routes[ $singular_model_route ] = array_merge(
523
-                    $model_routes[ $singular_model_route ],
524
-                    [
525
-                        [
526
-                            'callback'        => [
527
-                                'EventEspresso\core\libraries\rest_api\controllers\model\Write',
528
-                                'handleRequestUpdate',
529
-                            ],
530
-                            'callback_args'   => [$version, $model_name],
531
-                            'methods'         => WP_REST_Server::EDITABLE,
532
-                            'hidden_endpoint' => $hidden_endpoint,
533
-                            'args'            => $this->_get_write_params($model_name, $model_version_info),
534
-                        ],
535
-                        [
536
-                            'callback'        => [
537
-                                'EventEspresso\core\libraries\rest_api\controllers\model\Write',
538
-                                'handleRequestDelete',
539
-                            ],
540
-                            'callback_args'   => [$version, $model_name],
541
-                            'methods'         => WP_REST_Server::DELETABLE,
542
-                            'hidden_endpoint' => $hidden_endpoint,
543
-                            'args'            => $this->_get_delete_query_params($model, $version),
544
-                        ],
545
-                    ]
546
-                );
547
-            }
548
-            foreach ($model->relation_settings() as $relation_name => $relation_obj) {
549
-                $related_route = EED_Core_Rest_Api::get_relation_route_via(
550
-                    $model,
551
-                    '(?P<id>[^\/]+)',
552
-                    $relation_obj
553
-                );
554
-                $model_routes[ $related_route ] = [
555
-                    [
556
-                        'callback'        => [
557
-                            'EventEspresso\core\libraries\rest_api\controllers\model\Read',
558
-                            'handleRequestGetRelated',
559
-                        ],
560
-                        'callback_args'   => [$version, $model_name, $relation_name],
561
-                        'methods'         => WP_REST_Server::READABLE,
562
-                        'hidden_endpoint' => $hidden_endpoint,
563
-                        'args'            => $this->_get_read_query_params($relation_obj->get_other_model(), $version),
564
-                    ],
565
-                ];
566
-
567
-                $related_write_route = $related_route . '/' . '(?P<related_id>[^\/]+)';
568
-                $model_routes[ $related_write_route ] = [
569
-                    [
570
-                        'callback'        => [
571
-                            'EventEspresso\core\libraries\rest_api\controllers\model\Write',
572
-                            'handleRequestAddRelation',
573
-                        ],
574
-                        'callback_args'   => [$version, $model_name, $relation_name],
575
-                        'methods'         => WP_REST_Server::EDITABLE,
576
-                        'hidden_endpoint' => $hidden_endpoint,
577
-                        'args'            => $this->_get_add_relation_query_params(
578
-                            $model,
579
-                            $relation_obj->get_other_model(),
580
-                            $version
581
-                        ),
582
-                    ],
583
-                    [
584
-                        'callback'        => [
585
-                            'EventEspresso\core\libraries\rest_api\controllers\model\Write',
586
-                            'handleRequestRemoveRelation',
587
-                        ],
588
-                        'callback_args'   => [$version, $model_name, $relation_name],
589
-                        'methods'         => WP_REST_Server::DELETABLE,
590
-                        'hidden_endpoint' => $hidden_endpoint,
591
-                        'args'            => [],
592
-                    ],
593
-                ];
594
-            }
595
-        }
596
-        return $model_routes;
597
-    }
598
-
599
-
600
-    /**
601
-     * Gets the relative URI to a model's REST API plural route, after the EE4 versioned namespace,
602
-     * excluding the preceding slash.
603
-     * Eg you pass get_plural_route_to('Event') = 'events'
604
-     *
605
-     * @param EEM_Base $model
606
-     * @return string
607
-     */
608
-    public static function get_collection_route(EEM_Base $model)
609
-    {
610
-        return EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
611
-    }
612
-
613
-
614
-    /**
615
-     * Gets the relative URI to a model's REST API singular route, after the EE4 versioned namespace,
616
-     * excluding the preceding slash.
617
-     * Eg you pass get_plural_route_to('Event', 12) = 'events/12'
618
-     *
619
-     * @param EEM_Base $model eg Event or Venue
620
-     * @param string   $id
621
-     * @return string
622
-     */
623
-    public static function get_entity_route($model, $id)
624
-    {
625
-        return EED_Core_Rest_Api::get_collection_route($model) . '/' . $id;
626
-    }
627
-
628
-
629
-    /**
630
-     * Gets the relative URI to a model's REST API singular route, after the EE4 versioned namespace,
631
-     * excluding the preceding slash.
632
-     * Eg you pass get_plural_route_to('Event', 12) = 'events/12'
633
-     *
634
-     * @param EEM_Base               $model eg Event or Venue
635
-     * @param string                 $id
636
-     * @param EE_Model_Relation_Base $relation_obj
637
-     * @return string
638
-     */
639
-    public static function get_relation_route_via(EEM_Base $model, $id, EE_Model_Relation_Base $relation_obj)
640
-    {
641
-        $related_model_name_endpoint_part = ModelRead::getRelatedEntityName(
642
-            $relation_obj->get_other_model()->get_this_model_name(),
643
-            $relation_obj
644
-        );
645
-        return EED_Core_Rest_Api::get_entity_route($model, $id) . '/' . $related_model_name_endpoint_part;
646
-    }
647
-
648
-
649
-    /**
650
-     * Adds onto the $relative_route the EE4 REST API versioned namespace.
651
-     * Eg if given '4.8.36' and 'events', will return 'ee/v4.8.36/events'
652
-     *
653
-     * @param string $relative_route
654
-     * @param string $version
655
-     * @return string
656
-     */
657
-    public static function get_versioned_route_to($relative_route, $version = '4.8.36')
658
-    {
659
-        return '/' . EED_Core_Rest_Api::ee_api_namespace . $version . '/' . $relative_route;
660
-    }
661
-
662
-
663
-    /**
664
-     * Adds all the RPC-style routes (remote procedure call-like routes, ie
665
-     * routes that don't conform to the traditional REST CRUD-style).
666
-     *
667
-     * @deprecated since 4.9.1
668
-     */
669
-    protected function _register_rpc_routes()
670
-    {
671
-        $routes = [];
672
-        foreach (EED_Core_Rest_Api::versions_served() as $version => $hidden_endpoint) {
673
-            $routes[ EED_Core_Rest_Api::ee_api_namespace . $version ] = $this->_get_rpc_route_data_for_version(
674
-                $version,
675
-                $hidden_endpoint
676
-            );
677
-        }
678
-        return $routes;
679
-    }
680
-
681
-
682
-    /**
683
-     * @param string  $version
684
-     * @param boolean $hidden_endpoint
685
-     * @return array
686
-     */
687
-    protected function _get_rpc_route_data_for_version($version, $hidden_endpoint = false)
688
-    {
689
-        $this_versions_routes = [];
690
-        // checkin endpoint
691
-        $this_versions_routes['registrations/(?P<REG_ID>\d+)/toggle_checkin_for_datetime/(?P<DTT_ID>\d+)'] = [
692
-            [
693
-                'callback'        => [
694
-                    'EventEspresso\core\libraries\rest_api\controllers\rpc\Checkin',
695
-                    'handleRequestToggleCheckin',
696
-                ],
697
-                'methods'         => WP_REST_Server::CREATABLE,
698
-                'hidden_endpoint' => $hidden_endpoint,
699
-                'args'            => [
700
-                    'force' => [
701
-                        'required'    => false,
702
-                        'default'     => false,
703
-                        'description' => esc_html__(
704
-                        // @codingStandardsIgnoreStart
705
-                            'Whether to force toggle checkin, or to verify the registration status and allowed ticket uses',
706
-                            // @codingStandardsIgnoreEnd
707
-                            'event_espresso'
708
-                        ),
709
-                    ],
710
-                ],
711
-                'callback_args'   => [$version],
712
-            ],
713
-        ];
714
-        return apply_filters(
715
-            'FHEE__EED_Core_Rest_Api___register_rpc_routes__this_versions_routes',
716
-            $this_versions_routes,
717
-            $version,
718
-            $hidden_endpoint
719
-        );
720
-    }
721
-
722
-
723
-    /**
724
-     * Gets the query params that can be used when request one or many
725
-     *
726
-     * @param EEM_Base $model
727
-     * @param string   $version
728
-     * @return array
729
-     */
730
-    protected function _get_response_selection_query_params(EEM_Base $model, $version, $single_only = false)
731
-    {
732
-        EED_Core_Rest_Api::loadCalculatedModelFields();
733
-        $query_params = [
734
-            'include'   => [
735
-                'required' => false,
736
-                'default'  => '*',
737
-                'type'     => 'string',
738
-            ],
739
-            'calculate' => [
740
-                'required'          => false,
741
-                'default'           => '',
742
-                'enum'              => EED_Core_Rest_Api::$_field_calculator->retrieveCalculatedFieldsForModel($model),
743
-                'type'              => 'string',
744
-                // because we accept a CSV list of the enumerated strings, WP core validation and sanitization
745
-                // freaks out. We'll just validate this argument while handling the request
746
-                'validate_callback' => null,
747
-                'sanitize_callback' => null,
748
-            ],
749
-            'password'  => [
750
-                'required' => false,
751
-                'default'  => '',
752
-                'type'     => 'string',
753
-            ],
754
-        ];
755
-        return apply_filters(
756
-            'FHEE__EED_Core_Rest_Api___get_response_selection_query_params',
757
-            $query_params,
758
-            $model,
759
-            $version
760
-        );
761
-    }
762
-
763
-
764
-    /**
765
-     * Gets the parameters acceptable for delete requests
766
-     *
767
-     * @param EEM_Base $model
768
-     * @param string   $version
769
-     * @return array
770
-     */
771
-    protected function _get_delete_query_params(EEM_Base $model, $version)
772
-    {
773
-        $params_for_delete = [
774
-            'allow_blocking' => [
775
-                'required' => false,
776
-                'default'  => true,
777
-                'type'     => 'boolean',
778
-            ],
779
-        ];
780
-        $params_for_delete['force'] = [
781
-            'required' => false,
782
-            'default'  => false,
783
-            'type'     => 'boolean',
784
-        ];
785
-        return apply_filters(
786
-            'FHEE__EED_Core_Rest_Api___get_delete_query_params',
787
-            $params_for_delete,
788
-            $model,
789
-            $version
790
-        );
791
-    }
792
-
793
-
794
-    /**
795
-     * @param EEM_Base $source_model
796
-     * @param EEM_Base $related_model
797
-     * @param          $version
798
-     * @return array
799
-     * @throws EE_Error
800
-     * @since 5.0.0.p
801
-     */
802
-    protected function _get_add_relation_query_params(EEM_Base $source_model, EEM_Base $related_model, $version)
803
-    {
804
-        // if they're related through a HABTM relation, check for any non-FKs
805
-        $all_relation_settings = $source_model->relation_settings();
806
-        $relation_settings = $all_relation_settings[ $related_model->get_this_model_name() ];
807
-        $params = [];
808
-        if ($relation_settings instanceof EE_HABTM_Relation && $relation_settings->hasNonKeyFields()) {
809
-            foreach ($relation_settings->getNonKeyFields() as $field) {
810
-                /* @var $field EE_Model_Field_Base */
811
-                $params[ $field->get_name() ] = [
812
-                    'required'          => ! $field->is_nullable(),
813
-                    'default'           => ModelDataTranslator::prepareFieldValueForJson(
814
-                        $field,
815
-                        $field->get_default_value(),
816
-                        $version
817
-                    ),
818
-                    'type'              => $field->getSchemaType(),
819
-                    'validate_callback' => null,
820
-                    'sanitize_callback' => null,
821
-                ];
822
-            }
823
-        }
824
-        return $params;
825
-    }
826
-
827
-
828
-    /**
829
-     * Gets info about reading query params that are acceptable
830
-     *
831
-     * @param EEM_Base $model eg 'Event' or 'Venue'
832
-     * @param string   $version
833
-     * @return array    describing the args acceptable when querying this model
834
-     * @throws EE_Error
835
-     */
836
-    protected function _get_read_query_params(EEM_Base $model, $version)
837
-    {
838
-        $default_orderby = [];
839
-        foreach ($model->get_combined_primary_key_fields() as $key_field) {
840
-            $default_orderby[ $key_field->get_name() ] = 'ASC';
841
-        }
842
-        return array_merge(
843
-            $this->_get_response_selection_query_params($model, $version),
844
-            [
845
-                'where'    => [
846
-                    'required'          => false,
847
-                    'default'           => [],
848
-                    'type'              => 'object',
849
-                    // because we accept an almost infinite list of possible where conditions, WP
850
-                    // core validation and sanitization freaks out. We'll just validate this argument
851
-                    // while handling the request
852
-                    'validate_callback' => null,
853
-                    'sanitize_callback' => null,
854
-                ],
855
-                'limit'    => [
856
-                    'required'          => false,
857
-                    'default'           => EED_Core_Rest_Api::get_default_query_limit(),
858
-                    'type'              => [
859
-                        'array',
860
-                        'string',
861
-                        'integer',
862
-                    ],
863
-                    // because we accept a variety of types, WP core validation and sanitization
864
-                    // freaks out. We'll just validate this argument while handling the request
865
-                    'validate_callback' => null,
866
-                    'sanitize_callback' => null,
867
-                ],
868
-                'order_by' => [
869
-                    'required'          => false,
870
-                    'default'           => $default_orderby,
871
-                    'type'              => [
872
-                        'object',
873
-                        'string',
874
-                    ],// because we accept a variety of types, WP core validation and sanitization
875
-                    // freaks out. We'll just validate this argument while handling the request
876
-                    'validate_callback' => null,
877
-                    'sanitize_callback' => null,
878
-                ],
879
-                'group_by' => [
880
-                    'required'          => false,
881
-                    'default'           => null,
882
-                    'type'              => [
883
-                        'object',
884
-                        'string',
885
-                    ],
886
-                    // because we accept  an almost infinite list of possible groupings,
887
-                    // WP core validation and sanitization
888
-                    // freaks out. We'll just validate this argument while handling the request
889
-                    'validate_callback' => null,
890
-                    'sanitize_callback' => null,
891
-                ],
892
-                'having'   => [
893
-                    'required'          => false,
894
-                    'default'           => null,
895
-                    'type'              => 'object',
896
-                    // because we accept an almost infinite list of possible where conditions, WP
897
-                    // core validation and sanitization freaks out. We'll just validate this argument
898
-                    // while handling the request
899
-                    'validate_callback' => null,
900
-                    'sanitize_callback' => null,
901
-                ],
902
-                'caps'     => [
903
-                    'required' => false,
904
-                    'default'  => EEM_Base::caps_read,
905
-                    'type'     => 'string',
906
-                    'enum'     => [
907
-                        EEM_Base::caps_read,
908
-                        EEM_Base::caps_read_admin,
909
-                        EEM_Base::caps_edit,
910
-                        EEM_Base::caps_delete,
911
-                    ],
912
-                ],
913
-            ]
914
-        );
915
-    }
916
-
917
-
918
-    /**
919
-     * Gets parameter information for a model regarding writing data
920
-     *
921
-     * @param string           $model_name
922
-     * @param ModelVersionInfo $model_version_info
923
-     * @param boolean          $create                                       whether this is for request to create (in
924
-     *                                                                       which case we need all required params) or
925
-     *                                                                       just to update (in which case we don't
926
-     *                                                                       need those on every request)
927
-     * @return array
928
-     * @throws EE_Error
929
-     * @throws ReflectionException
930
-     */
931
-    protected function _get_write_params(
932
-        $model_name,
933
-        ModelVersionInfo $model_version_info,
934
-        $create = false
935
-    ) {
936
-        $model = EE_Registry::instance()->load_model($model_name);
937
-        $fields = $model_version_info->fieldsOnModelInThisVersion($model);
938
-
939
-        // we do our own validation and sanitization within the controller
940
-        $sanitize_callback = function_exists('rest_validate_value_from_schema')
941
-            ? ['EED_Core_Rest_Api', 'default_sanitize_callback']
942
-            : null;
943
-        $args_info = [];
944
-        foreach ($fields as $field_name => $field_obj) {
945
-            if ($field_obj->is_auto_increment()) {
946
-                // totally ignore auto increment IDs
947
-                continue;
948
-            }
949
-            $arg_info = $field_obj->getSchema();
950
-            $required = $create && ! $field_obj->is_nullable() && $field_obj->get_default_value() === null;
951
-            $arg_info['required'] = $required;
952
-            // remove the read-only flag. If it were read-only we wouldn't list it as an argument while writing, right?
953
-            unset($arg_info['readonly']);
954
-            $schema_properties = $field_obj->getSchemaProperties();
955
-            if (
956
-                isset($schema_properties['raw'])
957
-                && $field_obj->getSchemaType() === 'object'
958
-            ) {
959
-                // if there's a "raw" form of this argument, use those properties instead
960
-                $arg_info = array_replace(
961
-                    $arg_info,
962
-                    $schema_properties['raw']
963
-                );
964
-            }
965
-            $arg_info['default'] = ModelDataTranslator::prepareFieldValueForJson(
966
-                $field_obj,
967
-                $field_obj->get_default_value(),
968
-                $model_version_info->requestedVersion()
969
-            );
970
-            $arg_info['sanitize_callback'] = $sanitize_callback;
971
-            $args_info[ $field_name ] = $arg_info;
972
-            if ($field_obj instanceof EE_Datetime_Field) {
973
-                $gmt_arg_info = $arg_info;
974
-                $gmt_arg_info['description'] = sprintf(
975
-                    esc_html__(
976
-                        '%1$s - the value for this field in UTC. Ignored if %2$s is provided.',
977
-                        'event_espresso'
978
-                    ),
979
-                    $field_obj->get_nicename(),
980
-                    $field_name
981
-                );
982
-                $args_info[ $field_name . '_gmt' ] = $gmt_arg_info;
983
-            }
984
-        }
985
-        return $args_info;
986
-    }
987
-
988
-
989
-    /**
990
-     * Replacement for WP API's 'rest_parse_request_arg'.
991
-     * If the value is blank but not required, don't bother validating it.
992
-     * Also, it uses our email validation instead of WP API's default.
993
-     *
994
-     * @param                 $value
995
-     * @param WP_REST_Request $request
996
-     * @param                 $param
997
-     * @return bool|true|WP_Error
998
-     * @throws InvalidArgumentException
999
-     * @throws InvalidInterfaceException
1000
-     * @throws InvalidDataTypeException
1001
-     */
1002
-    public static function default_sanitize_callback($value, WP_REST_Request $request, $param)
1003
-    {
1004
-        $attributes = $request->get_attributes();
1005
-        if (
1006
-            ! isset($attributes['args'][ $param ])
1007
-            || ! is_array($attributes['args'][ $param ])
1008
-        ) {
1009
-            $validation_result = true;
1010
-        } else {
1011
-            $args = $attributes['args'][ $param ];
1012
-            if (
1013
-                (
1014
-                    $value === ''
1015
-                    || $value === null
1016
-                )
1017
-                && (! isset($args['required'])
1018
-                    || $args['required'] === false
1019
-                )
1020
-            ) {
1021
-                // not required and not provided? that's cool
1022
-                $validation_result = true;
1023
-            } elseif (
1024
-                isset($args['format'])
1025
-                      && $args['format'] === 'email'
1026
-            ) {
1027
-                $validation_result = true;
1028
-                if (! EED_Core_Rest_Api::_validate_email($value)) {
1029
-                    $validation_result = new WP_Error(
1030
-                        'rest_invalid_param',
1031
-                        esc_html__(
1032
-                            'The email address is not valid or does not exist.',
1033
-                            'event_espresso'
1034
-                        )
1035
-                    );
1036
-                }
1037
-            } else {
1038
-                $validation_result = rest_validate_value_from_schema($value, $args, $param);
1039
-            }
1040
-        }
1041
-        if (is_wp_error($validation_result)) {
1042
-            return $validation_result;
1043
-        }
1044
-        return rest_sanitize_request_arg($value, $request, $param);
1045
-    }
1046
-
1047
-
1048
-    /**
1049
-     * Returns whether or not this email address is valid. Copied from EE_Email_Validation_Strategy::_validate_email()
1050
-     *
1051
-     * @param $email
1052
-     * @return bool
1053
-     * @throws InvalidArgumentException
1054
-     * @throws InvalidInterfaceException
1055
-     * @throws InvalidDataTypeException
1056
-     */
1057
-    protected static function _validate_email($email)
1058
-    {
1059
-        try {
1060
-            EmailAddressFactory::create($email);
1061
-            return true;
1062
-        } catch (EmailValidationException $e) {
1063
-            return false;
1064
-        }
1065
-    }
1066
-
1067
-
1068
-    /**
1069
-     * Gets routes for the config
1070
-     *
1071
-     * @return array @see _register_model_routes
1072
-     * @deprecated since version 4.9.1
1073
-     */
1074
-    protected function _register_config_routes()
1075
-    {
1076
-        $config_routes = [];
1077
-        foreach (EED_Core_Rest_Api::versions_served() as $version => $hidden_endpoint) {
1078
-            $config_routes[ EED_Core_Rest_Api::ee_api_namespace . $version ] = $this->_get_config_route_data_for_version(
1079
-                $version,
1080
-                $hidden_endpoint
1081
-            );
1082
-        }
1083
-        return $config_routes;
1084
-    }
1085
-
1086
-
1087
-    /**
1088
-     * Gets routes for the config for the specified version
1089
-     *
1090
-     * @param string  $version
1091
-     * @param boolean $hidden_endpoint
1092
-     * @return array
1093
-     */
1094
-    protected function _get_config_route_data_for_version($version, $hidden_endpoint)
1095
-    {
1096
-        return [
1097
-            'config'    => [
1098
-                [
1099
-                    'callback'        => [
1100
-                        'EventEspresso\core\libraries\rest_api\controllers\config\Read',
1101
-                        'handleRequest',
1102
-                    ],
1103
-                    'methods'         => WP_REST_Server::READABLE,
1104
-                    'hidden_endpoint' => $hidden_endpoint,
1105
-                    'callback_args'   => [$version],
1106
-                ],
1107
-            ],
1108
-            'site_info' => [
1109
-                [
1110
-                    'callback'        => [
1111
-                        'EventEspresso\core\libraries\rest_api\controllers\config\Read',
1112
-                        'handleRequestSiteInfo',
1113
-                    ],
1114
-                    'methods'         => WP_REST_Server::READABLE,
1115
-                    'hidden_endpoint' => $hidden_endpoint,
1116
-                    'callback_args'   => [$version],
1117
-                ],
1118
-            ],
1119
-        ];
1120
-    }
1121
-
1122
-
1123
-    /**
1124
-     * Gets the meta info routes
1125
-     *
1126
-     * @return array @see _register_model_routes
1127
-     * @deprecated since version 4.9.1
1128
-     */
1129
-    protected function _register_meta_routes()
1130
-    {
1131
-        $meta_routes = [];
1132
-        foreach (EED_Core_Rest_Api::versions_served() as $version => $hidden_endpoint) {
1133
-            $meta_routes[ EED_Core_Rest_Api::ee_api_namespace . $version ] = $this->_get_meta_route_data_for_version(
1134
-                $version,
1135
-                $hidden_endpoint
1136
-            );
1137
-        }
1138
-        return $meta_routes;
1139
-    }
1140
-
1141
-
1142
-    /**
1143
-     * @param string  $version
1144
-     * @param boolean $hidden_endpoint
1145
-     * @return array
1146
-     */
1147
-    protected function _get_meta_route_data_for_version($version, $hidden_endpoint = false)
1148
-    {
1149
-        return [
1150
-            'resources' => [
1151
-                [
1152
-                    'callback'        => [
1153
-                        'EventEspresso\core\libraries\rest_api\controllers\model\Meta',
1154
-                        'handleRequestModelsMeta',
1155
-                    ],
1156
-                    'methods'         => WP_REST_Server::READABLE,
1157
-                    'hidden_endpoint' => $hidden_endpoint,
1158
-                    'callback_args'   => [$version],
1159
-                ],
1160
-            ],
1161
-        ];
1162
-    }
1163
-
1164
-
1165
-    /**
1166
-     * Tries to hide old 4.6 endpoints from the
1167
-     *
1168
-     * @param array $route_data
1169
-     * @return array
1170
-     * @throws EE_Error
1171
-     * @throws ReflectionException
1172
-     */
1173
-    public static function hide_old_endpoints($route_data)
1174
-    {
1175
-        // allow API clients to override which endpoints get hidden, in case
1176
-        // they want to discover particular endpoints
1177
-        // also, we don't have access to the request so we have to just grab it from the superglobal
1178
-        $force_show_ee_namespace = ltrim(
1179
-            EED_Core_Rest_Api::getRequest()->getRequestParam('force_show_ee_namespace'),
1180
-            '/'
1181
-        );
1182
-        foreach (EED_Core_Rest_Api::get_ee_route_data() as $namespace => $relative_urls) {
1183
-            foreach ($relative_urls as $resource_name => $endpoints) {
1184
-                foreach ($endpoints as $key => $endpoint) {
1185
-                    // skip schema and other route options
1186
-                    if (! is_numeric($key)) {
1187
-                        continue;
1188
-                    }
1189
-                    // by default, hide "hidden_endpoint"s, unless the request indicates
1190
-                    // to $force_show_ee_namespace, in which case only show that one
1191
-                    // namespace's endpoints (and hide all others)
1192
-                    if (
1193
-                        ($force_show_ee_namespace !== '' && $force_show_ee_namespace !== $namespace)
1194
-                        || ($endpoint['hidden_endpoint'] && $force_show_ee_namespace === '')
1195
-                    ) {
1196
-                        $full_route = '/' . ltrim($namespace, '/');
1197
-                        $full_route .= '/' . ltrim($resource_name, '/');
1198
-                        unset($route_data[ $full_route ]);
1199
-                    }
1200
-                }
1201
-            }
1202
-        }
1203
-        return $route_data;
1204
-    }
1205
-
1206
-
1207
-    /**
1208
-     * Returns an array describing which versions of core support serving requests for.
1209
-     * Keys are core versions' major and minor version, and values are the
1210
-     * LOWEST requested version they can serve. Eg, 4.7 can serve requests for 4.6-like
1211
-     * data by just removing a few models and fields from the responses. However, 4.15 might remove
1212
-     * the answers table entirely, in which case it would be very difficult for
1213
-     * it to serve 4.6-style responses.
1214
-     * Versions of core that are missing from this array are unknowns.
1215
-     * previous ver
1216
-     *
1217
-     * @return array
1218
-     */
1219
-    public static function version_compatibilities()
1220
-    {
1221
-        return apply_filters(
1222
-            'FHEE__EED_Core_REST_API__version_compatibilities',
1223
-            [
1224
-                '4.8.29' => '4.8.29',
1225
-                '4.8.33' => '4.8.29',
1226
-                '4.8.34' => '4.8.29',
1227
-                '4.8.36' => '4.8.29',
1228
-            ]
1229
-        );
1230
-    }
1231
-
1232
-
1233
-    /**
1234
-     * Gets the latest API version served. Eg if there
1235
-     * are two versions served of the API, 4.8.29 and 4.8.32, and
1236
-     * we are on core version 4.8.34, it will return the string "4.8.32"
1237
-     *
1238
-     * @return string
1239
-     */
1240
-    public static function latest_rest_api_version()
1241
-    {
1242
-        $versions_served = EED_Core_Rest_Api::versions_served();
1243
-        $versions_served_keys = array_keys($versions_served);
1244
-        return end($versions_served_keys);
1245
-    }
1246
-
1247
-
1248
-    /**
1249
-     * Using EED_Core_Rest_Api::version_compatibilities(), determines what version of
1250
-     * EE the API can serve requests for. Eg, if we are on 4.15 of core, and
1251
-     * we can serve requests from 4.12 or later, this will return array( '4.12', '4.13', '4.14', '4.15' ).
1252
-     * We also indicate whether or not this version should be put in the index or not
1253
-     *
1254
-     * @return array keys are API version numbers (just major and minor numbers), and values
1255
-     * are whether or not they should be hidden
1256
-     */
1257
-    public static function versions_served()
1258
-    {
1259
-        $versions_served = [];
1260
-        $possibly_served_versions = EED_Core_Rest_Api::version_compatibilities();
1261
-        $lowest_compatible_version = end($possibly_served_versions);
1262
-        reset($possibly_served_versions);
1263
-        $versions_served_historically = array_keys($possibly_served_versions);
1264
-        $latest_version = end($versions_served_historically);
1265
-        reset($versions_served_historically);
1266
-        // for each version of core we have ever served:
1267
-        foreach ($versions_served_historically as $key_versioned_endpoint) {
1268
-            // if it's not above the current core version, and it's compatible with the current version of core
1269
-
1270
-            if ($key_versioned_endpoint === $latest_version) {
1271
-                // don't hide the latest version in the index
1272
-                $versions_served[ $key_versioned_endpoint ] = false;
1273
-            } elseif (
1274
-                version_compare($key_versioned_endpoint, $lowest_compatible_version, '>=')
1275
-                && version_compare($key_versioned_endpoint, EED_Core_Rest_Api::core_version(), '<')
1276
-            ) {
1277
-                // include, but hide, previous versions which are still supported
1278
-                $versions_served[ $key_versioned_endpoint ] = true;
1279
-            } elseif (
1280
-                apply_filters(
1281
-                    'FHEE__EED_Core_Rest_Api__versions_served__include_incompatible_versions',
1282
-                    false,
1283
-                    $possibly_served_versions
1284
-                )
1285
-            ) {
1286
-                // if a version is no longer supported, don't include it in index or list of versions served
1287
-                $versions_served[ $key_versioned_endpoint ] = true;
1288
-            }
1289
-        }
1290
-        return $versions_served;
1291
-    }
1292
-
1293
-
1294
-    /**
1295
-     * Gets the major and minor version of EE core's version string
1296
-     *
1297
-     * @return string
1298
-     */
1299
-    public static function core_version()
1300
-    {
1301
-        return apply_filters(
1302
-            'FHEE__EED_Core_REST_API__core_version',
1303
-            implode(
1304
-                '.',
1305
-                array_slice(
1306
-                    explode(
1307
-                        '.',
1308
-                        espresso_version()
1309
-                    ),
1310
-                    0,
1311
-                    3
1312
-                )
1313
-            )
1314
-        );
1315
-    }
1316
-
1317
-
1318
-    /**
1319
-     * Gets the default limit that should be used when querying for resources
1320
-     *
1321
-     * @return int
1322
-     */
1323
-    public static function get_default_query_limit()
1324
-    {
1325
-        // we actually don't use a const because we want folks to always use
1326
-        // this method, not the const directly
1327
-        return apply_filters(
1328
-            'FHEE__EED_Core_Rest_Api__get_default_query_limit',
1329
-            50
1330
-        );
1331
-    }
1332
-
1333
-
1334
-    /**
1335
-     * @param string $version api version string (i.e. '4.8.36')
1336
-     * @return array
1337
-     */
1338
-    public static function getCollectionRoutesIndexedByModelName($version = '')
1339
-    {
1340
-        $version = empty($version) ? EED_Core_Rest_Api::latest_rest_api_version() : $version;
1341
-        $model_names = EED_Core_Rest_Api::model_names_with_plural_routes($version);
1342
-        $collection_routes = [];
1343
-        foreach ($model_names as $model_name => $model_class_name) {
1344
-            $collection_routes[ strtolower($model_name) ] = '/' . EED_Core_Rest_Api::ee_api_namespace . $version . '/'
1345
-                                                            . EEH_Inflector::pluralize_and_lower($model_name);
1346
-        }
1347
-        return $collection_routes;
1348
-    }
1349
-
1350
-
1351
-    /**
1352
-     * Returns an array of primary key names indexed by model names.
1353
-     *
1354
-     * @param string $version
1355
-     * @return array
1356
-     */
1357
-    public static function getPrimaryKeyNamesIndexedByModelName($version = '')
1358
-    {
1359
-        $version = empty($version) ? EED_Core_Rest_Api::latest_rest_api_version() : $version;
1360
-        $model_names = EED_Core_Rest_Api::model_names_with_plural_routes($version);
1361
-        $primary_key_items = [];
1362
-        foreach ($model_names as $model_name => $model_class_name) {
1363
-            $primary_keys = $model_class_name::instance()->get_combined_primary_key_fields();
1364
-            foreach ($primary_keys as $primary_key_name => $primary_key_field) {
1365
-                if (count($primary_keys) > 1) {
1366
-                    $primary_key_items[ strtolower($model_name) ][] = $primary_key_name;
1367
-                } else {
1368
-                    $primary_key_items[ strtolower($model_name) ] = $primary_key_name;
1369
-                }
1370
-            }
1371
-        }
1372
-        return $primary_key_items;
1373
-    }
1374
-
1375
-
1376
-    /**
1377
-     * Determines the EE REST API debug mode is activated, or not.
1378
-     *
1379
-     * @return bool
1380
-     * @since 4.9.76.p
1381
-     */
1382
-    public static function debugMode()
1383
-    {
1384
-        static $debug_mode = null; // could be class prop
1385
-        if ($debug_mode === null) {
1386
-            $debug_mode = defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE;
1387
-        }
1388
-        return $debug_mode;
1389
-    }
1390
-
1391
-
1392
-    /**
1393
-     *    run - initial module setup
1394
-     *
1395
-     * @access    public
1396
-     * @param WP $WP
1397
-     * @return    void
1398
-     */
1399
-    public function run($WP)
1400
-    {
1401
-    }
24
+	const ee_api_namespace = Domain::API_NAMESPACE;
25
+
26
+	const ee_api_namespace_for_regex = 'ee\/v([^/]*)\/';
27
+
28
+	const saved_routes_option_names = 'ee_core_routes';
29
+
30
+	/**
31
+	 * string used in _links response bodies to make them globally unique.
32
+	 *
33
+	 * @see http://v2.wp-api.org/extending/linking/
34
+	 */
35
+	const ee_api_link_namespace = 'https://api.eventespresso.com/';
36
+
37
+	/**
38
+	 * @var CalculatedModelFields
39
+	 */
40
+	protected static $_field_calculator;
41
+
42
+
43
+	/**
44
+	 * @return EED_Core_Rest_Api|EED_Module
45
+	 */
46
+	public static function instance()
47
+	{
48
+		return parent::get_instance(EED_Core_Rest_Api::class);
49
+	}
50
+
51
+
52
+	/**
53
+	 *    set_hooks - for hooking into EE Core, other modules, etc
54
+	 *
55
+	 * @access    public
56
+	 * @return    void
57
+	 */
58
+	public static function set_hooks()
59
+	{
60
+	}
61
+
62
+
63
+	/**
64
+	 *    set_hooks_admin - for hooking into EE Admin Core, other modules, etc
65
+	 *
66
+	 * @access    public
67
+	 * @return    void
68
+	 */
69
+	public static function set_hooks_admin()
70
+	{
71
+	}
72
+
73
+
74
+	public static function set_hooks_both()
75
+	{
76
+		add_action('rest_api_init', ['EED_Core_Rest_Api', 'set_hooks_rest_api'], 5);
77
+		add_action('rest_api_init', ['EED_Core_Rest_Api', 'register_routes'], 10);
78
+		add_filter('rest_route_data', ['EED_Core_Rest_Api', 'hide_old_endpoints'], 10, 2);
79
+		add_filter(
80
+			'rest_index',
81
+			['EventEspresso\core\libraries\rest_api\controllers\model\Meta', 'filterEeMetadataIntoIndex']
82
+		);
83
+	}
84
+
85
+
86
+	/**
87
+	 * @since   5.0.0.p
88
+	 */
89
+	public static function loadCalculatedModelFields()
90
+	{
91
+		EED_Core_Rest_Api::$_field_calculator = LoaderFactory::getLoader()->load(
92
+			'EventEspresso\core\libraries\rest_api\CalculatedModelFields'
93
+		);
94
+		EED_Core_Rest_Api::invalidate_cached_route_data_on_version_change();
95
+	}
96
+
97
+
98
+	/**
99
+	 * sets up hooks which only need to be included as part of REST API requests;
100
+	 * other requests like to the frontend or admin etc don't need them
101
+	 *
102
+	 * @throws EE_Error
103
+	 */
104
+	public static function set_hooks_rest_api()
105
+	{
106
+		// set hooks which account for changes made to the API
107
+		EED_Core_Rest_Api::_set_hooks_for_changes();
108
+	}
109
+
110
+
111
+	/**
112
+	 * public wrapper of _set_hooks_for_changes.
113
+	 * Loads all the hooks which make requests to old versions of the API
114
+	 * appear the same as they always did
115
+	 *
116
+	 * @throws EE_Error
117
+	 */
118
+	public static function set_hooks_for_changes()
119
+	{
120
+		EED_Core_Rest_Api::_set_hooks_for_changes();
121
+	}
122
+
123
+
124
+	/**
125
+	 * Loads all the hooks which make requests to old versions of the API
126
+	 * appear the same as they always did
127
+	 *
128
+	 * @throws EE_Error
129
+	 */
130
+	protected static function _set_hooks_for_changes()
131
+	{
132
+		$folder_contents = EEH_File::get_contents_of_folders([EE_LIBRARIES . 'rest_api/changes'], false);
133
+		foreach ($folder_contents as $classname_in_namespace => $filepath) {
134
+			// ignore the base parent class
135
+			// and legacy named classes
136
+			if (
137
+				$classname_in_namespace === 'ChangesInBase'
138
+				|| strpos($classname_in_namespace, 'Changes_In_') === 0
139
+			) {
140
+				continue;
141
+			}
142
+			$full_classname = 'EventEspresso\core\libraries\rest_api\changes\\' . $classname_in_namespace;
143
+			if (class_exists($full_classname)) {
144
+				$instance_of_class = new $full_classname();
145
+				if ($instance_of_class instanceof ChangesInBase) {
146
+					$instance_of_class->setHooks();
147
+				}
148
+			}
149
+		}
150
+	}
151
+
152
+
153
+	/**
154
+	 * Filters the WP routes to add our EE-related ones. This takes a bit of time
155
+	 * so we actually prefer to only do it when an EE plugin is activated or upgraded
156
+	 *
157
+	 * @throws EE_Error
158
+	 * @throws ReflectionException
159
+	 */
160
+	public static function register_routes()
161
+	{
162
+		foreach (EED_Core_Rest_Api::get_ee_route_data() as $namespace => $relative_routes) {
163
+			foreach ($relative_routes as $relative_route => $data_for_multiple_endpoints) {
164
+				/**
165
+				 * @var array     $data_for_multiple_endpoints numerically indexed array
166
+				 *                                         but can also contain route options like {
167
+				 * @type array    $schema                      {
168
+				 * @type callable $schema_callback
169
+				 * @type array    $callback_args               arguments that will be passed to the callback, after the
170
+				 * WP_REST_Request of course
171
+				 * }
172
+				 * }
173
+				 */
174
+				// when registering routes, register all the endpoints' data at the same time
175
+				$multiple_endpoint_args = [];
176
+				foreach ($data_for_multiple_endpoints as $endpoint_key => $data_for_single_endpoint) {
177
+					/**
178
+					 * @var array     $data_for_single_endpoint {
179
+					 * @type callable $callback
180
+					 * @type string methods
181
+					 * @type array args
182
+					 * @type array _links
183
+					 * @type array    $callback_args            arguments that will be passed to the callback, after the
184
+					 * WP_REST_Request of course
185
+					 * }
186
+					 */
187
+					// skip route options
188
+					if (! is_numeric($endpoint_key)) {
189
+						continue;
190
+					}
191
+					if (! isset($data_for_single_endpoint['callback'], $data_for_single_endpoint['methods'])) {
192
+						throw new EE_Error(
193
+							esc_html__(
194
+							// @codingStandardsIgnoreStart
195
+								'Endpoint configuration data needs to have entries "callback" (callable) and "methods" (comma-separated list of accepts HTTP methods).',
196
+								// @codingStandardsIgnoreEnd
197
+								'event_espresso'
198
+							)
199
+						);
200
+					}
201
+					$callback = $data_for_single_endpoint['callback'];
202
+					$single_endpoint_args = [
203
+						'methods' => $data_for_single_endpoint['methods'],
204
+						'args'    => isset($data_for_single_endpoint['args']) ? $data_for_single_endpoint['args']
205
+							: [],
206
+					];
207
+					if (isset($data_for_single_endpoint['_links'])) {
208
+						$single_endpoint_args['_links'] = $data_for_single_endpoint['_links'];
209
+					}
210
+					if (isset($data_for_single_endpoint['callback_args'])) {
211
+						$callback_args = $data_for_single_endpoint['callback_args'];
212
+						$single_endpoint_args['callback'] = static function (WP_REST_Request $request) use (
213
+							$callback,
214
+							$callback_args
215
+						) {
216
+							array_unshift($callback_args, $request);
217
+							return call_user_func_array(
218
+								$callback,
219
+								$callback_args
220
+							);
221
+						};
222
+					} else {
223
+						$single_endpoint_args['callback'] = $data_for_single_endpoint['callback'];
224
+					}
225
+					// As of WordPress 5.5, if a permission_callback is not provided,
226
+					// the REST API will issue a _doing_it_wrong notice.
227
+					// Since the EE REST API defers capabilities to the db model system,
228
+					// we will just use the generic WP callback for public endpoints
229
+					if (! isset($single_endpoint_args['permission_callback'])) {
230
+						$single_endpoint_args['permission_callback'] = '__return_true';
231
+					}
232
+					$multiple_endpoint_args[] = $single_endpoint_args;
233
+				}
234
+				if (isset($data_for_multiple_endpoints['schema'])) {
235
+					$schema_route_data = $data_for_multiple_endpoints['schema'];
236
+					$schema_callback = $schema_route_data['schema_callback'];
237
+					$callback_args = $schema_route_data['callback_args'];
238
+					$multiple_endpoint_args['schema'] = static function () use ($schema_callback, $callback_args) {
239
+						return call_user_func_array(
240
+							$schema_callback,
241
+							$callback_args
242
+						);
243
+					};
244
+				}
245
+				register_rest_route(
246
+					$namespace,
247
+					$relative_route,
248
+					$multiple_endpoint_args
249
+				);
250
+			}
251
+		}
252
+	}
253
+
254
+
255
+	/**
256
+	 * Checks if there was a version change or something that merits invalidating the cached
257
+	 * route data. If so, invalidates the cached route data so that it gets refreshed
258
+	 * next time the WP API is used
259
+	 */
260
+	public static function invalidate_cached_route_data_on_version_change()
261
+	{
262
+		if (EE_System::instance()->detect_req_type() !== EE_System::req_type_normal) {
263
+			EED_Core_Rest_Api::invalidate_cached_route_data();
264
+		}
265
+		foreach (EE_Registry::instance()->addons as $addon) {
266
+			if ($addon instanceof EE_Addon && $addon->detect_req_type() !== EE_System::req_type_normal) {
267
+				EED_Core_Rest_Api::invalidate_cached_route_data();
268
+			}
269
+		}
270
+	}
271
+
272
+
273
+	/**
274
+	 * Removes the cached route data so it will get refreshed next time the WP API is used
275
+	 */
276
+	public static function invalidate_cached_route_data()
277
+	{
278
+		// delete the saved EE REST API routes
279
+		foreach (EED_Core_Rest_Api::versions_served() as $version => $hidden) {
280
+			delete_option(EED_Core_Rest_Api::saved_routes_option_names . $version);
281
+		}
282
+	}
283
+
284
+
285
+	/**
286
+	 * Gets the EE route data
287
+	 *
288
+	 * @return array top-level key is the namespace, next-level key is the route and its value is array{
289
+	 * @throws EE_Error
290
+	 * @throws ReflectionException
291
+	 * @type string|array $callback
292
+	 * @type string       $methods
293
+	 * @type boolean      $hidden_endpoint
294
+	 * }
295
+	 */
296
+	public static function get_ee_route_data()
297
+	{
298
+		$ee_routes = [];
299
+		foreach (EED_Core_Rest_Api::versions_served() as $version => $hidden_endpoints) {
300
+			$ee_routes[ EED_Core_Rest_Api::ee_api_namespace . $version ] = EED_Core_Rest_Api::_get_ee_route_data_for_version(
301
+				$version,
302
+				$hidden_endpoints
303
+			);
304
+		}
305
+		return $ee_routes;
306
+	}
307
+
308
+
309
+	/**
310
+	 * Gets the EE route data from the wp options if it exists already,
311
+	 * otherwise re-generates it and saves it to the option
312
+	 *
313
+	 * @param string  $version
314
+	 * @param boolean $hidden_endpoints
315
+	 * @return array
316
+	 * @throws EE_Error
317
+	 * @throws ReflectionException
318
+	 */
319
+	protected static function _get_ee_route_data_for_version($version, $hidden_endpoints = false)
320
+	{
321
+		$ee_routes = get_option(EED_Core_Rest_Api::saved_routes_option_names . $version, null);
322
+		if (! $ee_routes || EED_Core_Rest_Api::debugMode()) {
323
+			$ee_routes = EED_Core_Rest_Api::_save_ee_route_data_for_version($version, $hidden_endpoints);
324
+		}
325
+		return $ee_routes;
326
+	}
327
+
328
+
329
+	/**
330
+	 * Saves the EE REST API route data to a wp option and returns it
331
+	 *
332
+	 * @param string  $version
333
+	 * @param boolean $hidden_endpoints
334
+	 * @return mixed|null
335
+	 * @throws EE_Error
336
+	 * @throws ReflectionException
337
+	 */
338
+	protected static function _save_ee_route_data_for_version($version, $hidden_endpoints = false)
339
+	{
340
+		$instance = EED_Core_Rest_Api::instance();
341
+		$routes = apply_filters(
342
+			'EED_Core_Rest_Api__save_ee_route_data_for_version__routes',
343
+			array_replace_recursive(
344
+				$instance->_get_config_route_data_for_version($version, $hidden_endpoints),
345
+				$instance->_get_meta_route_data_for_version($version, $hidden_endpoints),
346
+				$instance->_get_model_route_data_for_version($version, $hidden_endpoints),
347
+				$instance->_get_rpc_route_data_for_version($version, $hidden_endpoints)
348
+			)
349
+		);
350
+		$option_name = EED_Core_Rest_Api::saved_routes_option_names . $version;
351
+		if (get_option($option_name)) {
352
+			update_option($option_name, $routes, true);
353
+		} else {
354
+			add_option($option_name, $routes, null, 'no');
355
+		}
356
+		return $routes;
357
+	}
358
+
359
+
360
+	/**
361
+	 * Calculates all the EE routes and saves it to a WordPress option so we don't
362
+	 * need to calculate it on every request
363
+	 *
364
+	 * @return void
365
+	 * @deprecated since version 4.9.1
366
+	 */
367
+	public static function save_ee_routes()
368
+	{
369
+		if (EE_Maintenance_Mode::instance()->models_can_query()) {
370
+			$instance = EED_Core_Rest_Api::instance();
371
+			$routes = apply_filters(
372
+				'EED_Core_Rest_Api__save_ee_routes__routes',
373
+				array_replace_recursive(
374
+					$instance->_register_config_routes(),
375
+					$instance->_register_meta_routes(),
376
+					$instance->_register_model_routes(),
377
+					$instance->_register_rpc_routes()
378
+				)
379
+			);
380
+			update_option(EED_Core_Rest_Api::saved_routes_option_names, $routes, true);
381
+		}
382
+	}
383
+
384
+
385
+	/**
386
+	 * Gets all the route information relating to EE models
387
+	 *
388
+	 * @return array @see get_ee_route_data
389
+	 * @deprecated since version 4.9.1
390
+	 */
391
+	protected function _register_model_routes()
392
+	{
393
+		$model_routes = [];
394
+		foreach (EED_Core_Rest_Api::versions_served() as $version => $hidden_endpoint) {
395
+			$model_routes[ EED_Core_Rest_Api::ee_api_namespace
396
+						   . $version ] = $this->_get_config_route_data_for_version($version, $hidden_endpoint);
397
+		}
398
+		return $model_routes;
399
+	}
400
+
401
+
402
+	/**
403
+	 * Decides whether or not to add write endpoints for this model.
404
+	 * Currently, this defaults to exclude all global tables and models
405
+	 * which would allow inserting WP core data (we don't want to duplicate
406
+	 * what WP API does, as it's unnecessary, extra work, and potentially extra bugs)
407
+	 *
408
+	 * @param EEM_Base $model
409
+	 * @return bool
410
+	 */
411
+	public static function should_have_write_endpoints(EEM_Base $model)
412
+	{
413
+		if ($model->is_wp_core_model()) {
414
+			return false;
415
+		}
416
+		foreach ($model->get_tables() as $table) {
417
+			if ($table->is_global()) {
418
+				return false;
419
+			}
420
+		}
421
+		return true;
422
+	}
423
+
424
+
425
+	/**
426
+	 * Gets the names of all models which should have plural routes (eg `ee/v4.8.36/events`)
427
+	 * in this versioned namespace of EE4
428
+	 *
429
+	 * @param $version
430
+	 * @return array keys are model names (eg 'Event') and values ar either classnames (eg 'EEM_Event')
431
+	 */
432
+	public static function model_names_with_plural_routes($version)
433
+	{
434
+		$model_version_info = new ModelVersionInfo($version);
435
+		$models_to_register = $model_version_info->modelsForRequestedVersion();
436
+		// let's not bother having endpoints for extra metas
437
+		unset(
438
+			$models_to_register['Extra_Meta'],
439
+			$models_to_register['Extra_Join'],
440
+			$models_to_register['Post_Meta']
441
+		);
442
+		return apply_filters(
443
+			'FHEE__EED_Core_REST_API___register_model_routes',
444
+			$models_to_register
445
+		);
446
+	}
447
+
448
+
449
+	/**
450
+	 * Gets the route data for EE models in the specified version
451
+	 *
452
+	 * @param string  $version
453
+	 * @param boolean $hidden_endpoint
454
+	 * @return array
455
+	 * @throws EE_Error
456
+	 * @throws ReflectionException
457
+	 */
458
+	protected function _get_model_route_data_for_version($version, $hidden_endpoint = false)
459
+	{
460
+		$model_routes = [];
461
+		$model_version_info = new ModelVersionInfo($version);
462
+		foreach (EED_Core_Rest_Api::model_names_with_plural_routes($version) as $model_name => $model_classname) {
463
+			$model = EE_Registry::instance()->load_model($model_name);
464
+			// if this isn't a valid model then let's skip iterate to the next item in the loop.
465
+			if (! $model instanceof EEM_Base) {
466
+				continue;
467
+			}
468
+			// yes we could just register one route for ALL models, but then they wouldn't show up in the index
469
+			$plural_model_route = EED_Core_Rest_Api::get_collection_route($model);
470
+			$singular_model_route = EED_Core_Rest_Api::get_entity_route($model, '(?P<id>[^\/]+)');
471
+			$model_routes[ $plural_model_route ] = [
472
+				[
473
+					'callback'        => [
474
+						'EventEspresso\core\libraries\rest_api\controllers\model\Read',
475
+						'handleRequestGetAll',
476
+					],
477
+					'callback_args'   => [$version, $model_name],
478
+					'methods'         => WP_REST_Server::READABLE,
479
+					'hidden_endpoint' => $hidden_endpoint,
480
+					'args'            => $this->_get_read_query_params($model, $version),
481
+					'_links'          => [
482
+						'self' => rest_url(EED_Core_Rest_Api::ee_api_namespace . $version . $singular_model_route),
483
+					],
484
+				],
485
+				'schema' => [
486
+					'schema_callback' => [
487
+						'EventEspresso\core\libraries\rest_api\controllers\model\Read',
488
+						'handleSchemaRequest',
489
+					],
490
+					'callback_args'   => [$version, $model_name],
491
+				],
492
+			];
493
+			$model_routes[ $singular_model_route ] = [
494
+				[
495
+					'callback'        => [
496
+						'EventEspresso\core\libraries\rest_api\controllers\model\Read',
497
+						'handleRequestGetOne',
498
+					],
499
+					'callback_args'   => [$version, $model_name],
500
+					'methods'         => WP_REST_Server::READABLE,
501
+					'hidden_endpoint' => $hidden_endpoint,
502
+					'args'            => $this->_get_response_selection_query_params($model, $version, true),
503
+				],
504
+			];
505
+			if (
506
+				apply_filters(
507
+					'FHEE__EED_Core_Rest_Api___get_model_route_data_for_version__add_write_endpoints',
508
+					EED_Core_Rest_Api::should_have_write_endpoints($model),
509
+					$model
510
+				)
511
+			) {
512
+				$model_routes[ $plural_model_route ][] = [
513
+					'callback'        => [
514
+						'EventEspresso\core\libraries\rest_api\controllers\model\Write',
515
+						'handleRequestInsert',
516
+					],
517
+					'callback_args'   => [$version, $model_name],
518
+					'methods'         => WP_REST_Server::CREATABLE,
519
+					'hidden_endpoint' => $hidden_endpoint,
520
+					'args'            => $this->_get_write_params($model_name, $model_version_info, true),
521
+				];
522
+				$model_routes[ $singular_model_route ] = array_merge(
523
+					$model_routes[ $singular_model_route ],
524
+					[
525
+						[
526
+							'callback'        => [
527
+								'EventEspresso\core\libraries\rest_api\controllers\model\Write',
528
+								'handleRequestUpdate',
529
+							],
530
+							'callback_args'   => [$version, $model_name],
531
+							'methods'         => WP_REST_Server::EDITABLE,
532
+							'hidden_endpoint' => $hidden_endpoint,
533
+							'args'            => $this->_get_write_params($model_name, $model_version_info),
534
+						],
535
+						[
536
+							'callback'        => [
537
+								'EventEspresso\core\libraries\rest_api\controllers\model\Write',
538
+								'handleRequestDelete',
539
+							],
540
+							'callback_args'   => [$version, $model_name],
541
+							'methods'         => WP_REST_Server::DELETABLE,
542
+							'hidden_endpoint' => $hidden_endpoint,
543
+							'args'            => $this->_get_delete_query_params($model, $version),
544
+						],
545
+					]
546
+				);
547
+			}
548
+			foreach ($model->relation_settings() as $relation_name => $relation_obj) {
549
+				$related_route = EED_Core_Rest_Api::get_relation_route_via(
550
+					$model,
551
+					'(?P<id>[^\/]+)',
552
+					$relation_obj
553
+				);
554
+				$model_routes[ $related_route ] = [
555
+					[
556
+						'callback'        => [
557
+							'EventEspresso\core\libraries\rest_api\controllers\model\Read',
558
+							'handleRequestGetRelated',
559
+						],
560
+						'callback_args'   => [$version, $model_name, $relation_name],
561
+						'methods'         => WP_REST_Server::READABLE,
562
+						'hidden_endpoint' => $hidden_endpoint,
563
+						'args'            => $this->_get_read_query_params($relation_obj->get_other_model(), $version),
564
+					],
565
+				];
566
+
567
+				$related_write_route = $related_route . '/' . '(?P<related_id>[^\/]+)';
568
+				$model_routes[ $related_write_route ] = [
569
+					[
570
+						'callback'        => [
571
+							'EventEspresso\core\libraries\rest_api\controllers\model\Write',
572
+							'handleRequestAddRelation',
573
+						],
574
+						'callback_args'   => [$version, $model_name, $relation_name],
575
+						'methods'         => WP_REST_Server::EDITABLE,
576
+						'hidden_endpoint' => $hidden_endpoint,
577
+						'args'            => $this->_get_add_relation_query_params(
578
+							$model,
579
+							$relation_obj->get_other_model(),
580
+							$version
581
+						),
582
+					],
583
+					[
584
+						'callback'        => [
585
+							'EventEspresso\core\libraries\rest_api\controllers\model\Write',
586
+							'handleRequestRemoveRelation',
587
+						],
588
+						'callback_args'   => [$version, $model_name, $relation_name],
589
+						'methods'         => WP_REST_Server::DELETABLE,
590
+						'hidden_endpoint' => $hidden_endpoint,
591
+						'args'            => [],
592
+					],
593
+				];
594
+			}
595
+		}
596
+		return $model_routes;
597
+	}
598
+
599
+
600
+	/**
601
+	 * Gets the relative URI to a model's REST API plural route, after the EE4 versioned namespace,
602
+	 * excluding the preceding slash.
603
+	 * Eg you pass get_plural_route_to('Event') = 'events'
604
+	 *
605
+	 * @param EEM_Base $model
606
+	 * @return string
607
+	 */
608
+	public static function get_collection_route(EEM_Base $model)
609
+	{
610
+		return EEH_Inflector::pluralize_and_lower($model->get_this_model_name());
611
+	}
612
+
613
+
614
+	/**
615
+	 * Gets the relative URI to a model's REST API singular route, after the EE4 versioned namespace,
616
+	 * excluding the preceding slash.
617
+	 * Eg you pass get_plural_route_to('Event', 12) = 'events/12'
618
+	 *
619
+	 * @param EEM_Base $model eg Event or Venue
620
+	 * @param string   $id
621
+	 * @return string
622
+	 */
623
+	public static function get_entity_route($model, $id)
624
+	{
625
+		return EED_Core_Rest_Api::get_collection_route($model) . '/' . $id;
626
+	}
627
+
628
+
629
+	/**
630
+	 * Gets the relative URI to a model's REST API singular route, after the EE4 versioned namespace,
631
+	 * excluding the preceding slash.
632
+	 * Eg you pass get_plural_route_to('Event', 12) = 'events/12'
633
+	 *
634
+	 * @param EEM_Base               $model eg Event or Venue
635
+	 * @param string                 $id
636
+	 * @param EE_Model_Relation_Base $relation_obj
637
+	 * @return string
638
+	 */
639
+	public static function get_relation_route_via(EEM_Base $model, $id, EE_Model_Relation_Base $relation_obj)
640
+	{
641
+		$related_model_name_endpoint_part = ModelRead::getRelatedEntityName(
642
+			$relation_obj->get_other_model()->get_this_model_name(),
643
+			$relation_obj
644
+		);
645
+		return EED_Core_Rest_Api::get_entity_route($model, $id) . '/' . $related_model_name_endpoint_part;
646
+	}
647
+
648
+
649
+	/**
650
+	 * Adds onto the $relative_route the EE4 REST API versioned namespace.
651
+	 * Eg if given '4.8.36' and 'events', will return 'ee/v4.8.36/events'
652
+	 *
653
+	 * @param string $relative_route
654
+	 * @param string $version
655
+	 * @return string
656
+	 */
657
+	public static function get_versioned_route_to($relative_route, $version = '4.8.36')
658
+	{
659
+		return '/' . EED_Core_Rest_Api::ee_api_namespace . $version . '/' . $relative_route;
660
+	}
661
+
662
+
663
+	/**
664
+	 * Adds all the RPC-style routes (remote procedure call-like routes, ie
665
+	 * routes that don't conform to the traditional REST CRUD-style).
666
+	 *
667
+	 * @deprecated since 4.9.1
668
+	 */
669
+	protected function _register_rpc_routes()
670
+	{
671
+		$routes = [];
672
+		foreach (EED_Core_Rest_Api::versions_served() as $version => $hidden_endpoint) {
673
+			$routes[ EED_Core_Rest_Api::ee_api_namespace . $version ] = $this->_get_rpc_route_data_for_version(
674
+				$version,
675
+				$hidden_endpoint
676
+			);
677
+		}
678
+		return $routes;
679
+	}
680
+
681
+
682
+	/**
683
+	 * @param string  $version
684
+	 * @param boolean $hidden_endpoint
685
+	 * @return array
686
+	 */
687
+	protected function _get_rpc_route_data_for_version($version, $hidden_endpoint = false)
688
+	{
689
+		$this_versions_routes = [];
690
+		// checkin endpoint
691
+		$this_versions_routes['registrations/(?P<REG_ID>\d+)/toggle_checkin_for_datetime/(?P<DTT_ID>\d+)'] = [
692
+			[
693
+				'callback'        => [
694
+					'EventEspresso\core\libraries\rest_api\controllers\rpc\Checkin',
695
+					'handleRequestToggleCheckin',
696
+				],
697
+				'methods'         => WP_REST_Server::CREATABLE,
698
+				'hidden_endpoint' => $hidden_endpoint,
699
+				'args'            => [
700
+					'force' => [
701
+						'required'    => false,
702
+						'default'     => false,
703
+						'description' => esc_html__(
704
+						// @codingStandardsIgnoreStart
705
+							'Whether to force toggle checkin, or to verify the registration status and allowed ticket uses',
706
+							// @codingStandardsIgnoreEnd
707
+							'event_espresso'
708
+						),
709
+					],
710
+				],
711
+				'callback_args'   => [$version],
712
+			],
713
+		];
714
+		return apply_filters(
715
+			'FHEE__EED_Core_Rest_Api___register_rpc_routes__this_versions_routes',
716
+			$this_versions_routes,
717
+			$version,
718
+			$hidden_endpoint
719
+		);
720
+	}
721
+
722
+
723
+	/**
724
+	 * Gets the query params that can be used when request one or many
725
+	 *
726
+	 * @param EEM_Base $model
727
+	 * @param string   $version
728
+	 * @return array
729
+	 */
730
+	protected function _get_response_selection_query_params(EEM_Base $model, $version, $single_only = false)
731
+	{
732
+		EED_Core_Rest_Api::loadCalculatedModelFields();
733
+		$query_params = [
734
+			'include'   => [
735
+				'required' => false,
736
+				'default'  => '*',
737
+				'type'     => 'string',
738
+			],
739
+			'calculate' => [
740
+				'required'          => false,
741
+				'default'           => '',
742
+				'enum'              => EED_Core_Rest_Api::$_field_calculator->retrieveCalculatedFieldsForModel($model),
743
+				'type'              => 'string',
744
+				// because we accept a CSV list of the enumerated strings, WP core validation and sanitization
745
+				// freaks out. We'll just validate this argument while handling the request
746
+				'validate_callback' => null,
747
+				'sanitize_callback' => null,
748
+			],
749
+			'password'  => [
750
+				'required' => false,
751
+				'default'  => '',
752
+				'type'     => 'string',
753
+			],
754
+		];
755
+		return apply_filters(
756
+			'FHEE__EED_Core_Rest_Api___get_response_selection_query_params',
757
+			$query_params,
758
+			$model,
759
+			$version
760
+		);
761
+	}
762
+
763
+
764
+	/**
765
+	 * Gets the parameters acceptable for delete requests
766
+	 *
767
+	 * @param EEM_Base $model
768
+	 * @param string   $version
769
+	 * @return array
770
+	 */
771
+	protected function _get_delete_query_params(EEM_Base $model, $version)
772
+	{
773
+		$params_for_delete = [
774
+			'allow_blocking' => [
775
+				'required' => false,
776
+				'default'  => true,
777
+				'type'     => 'boolean',
778
+			],
779
+		];
780
+		$params_for_delete['force'] = [
781
+			'required' => false,
782
+			'default'  => false,
783
+			'type'     => 'boolean',
784
+		];
785
+		return apply_filters(
786
+			'FHEE__EED_Core_Rest_Api___get_delete_query_params',
787
+			$params_for_delete,
788
+			$model,
789
+			$version
790
+		);
791
+	}
792
+
793
+
794
+	/**
795
+	 * @param EEM_Base $source_model
796
+	 * @param EEM_Base $related_model
797
+	 * @param          $version
798
+	 * @return array
799
+	 * @throws EE_Error
800
+	 * @since 5.0.0.p
801
+	 */
802
+	protected function _get_add_relation_query_params(EEM_Base $source_model, EEM_Base $related_model, $version)
803
+	{
804
+		// if they're related through a HABTM relation, check for any non-FKs
805
+		$all_relation_settings = $source_model->relation_settings();
806
+		$relation_settings = $all_relation_settings[ $related_model->get_this_model_name() ];
807
+		$params = [];
808
+		if ($relation_settings instanceof EE_HABTM_Relation && $relation_settings->hasNonKeyFields()) {
809
+			foreach ($relation_settings->getNonKeyFields() as $field) {
810
+				/* @var $field EE_Model_Field_Base */
811
+				$params[ $field->get_name() ] = [
812
+					'required'          => ! $field->is_nullable(),
813
+					'default'           => ModelDataTranslator::prepareFieldValueForJson(
814
+						$field,
815
+						$field->get_default_value(),
816
+						$version
817
+					),
818
+					'type'              => $field->getSchemaType(),
819
+					'validate_callback' => null,
820
+					'sanitize_callback' => null,
821
+				];
822
+			}
823
+		}
824
+		return $params;
825
+	}
826
+
827
+
828
+	/**
829
+	 * Gets info about reading query params that are acceptable
830
+	 *
831
+	 * @param EEM_Base $model eg 'Event' or 'Venue'
832
+	 * @param string   $version
833
+	 * @return array    describing the args acceptable when querying this model
834
+	 * @throws EE_Error
835
+	 */
836
+	protected function _get_read_query_params(EEM_Base $model, $version)
837
+	{
838
+		$default_orderby = [];
839
+		foreach ($model->get_combined_primary_key_fields() as $key_field) {
840
+			$default_orderby[ $key_field->get_name() ] = 'ASC';
841
+		}
842
+		return array_merge(
843
+			$this->_get_response_selection_query_params($model, $version),
844
+			[
845
+				'where'    => [
846
+					'required'          => false,
847
+					'default'           => [],
848
+					'type'              => 'object',
849
+					// because we accept an almost infinite list of possible where conditions, WP
850
+					// core validation and sanitization freaks out. We'll just validate this argument
851
+					// while handling the request
852
+					'validate_callback' => null,
853
+					'sanitize_callback' => null,
854
+				],
855
+				'limit'    => [
856
+					'required'          => false,
857
+					'default'           => EED_Core_Rest_Api::get_default_query_limit(),
858
+					'type'              => [
859
+						'array',
860
+						'string',
861
+						'integer',
862
+					],
863
+					// because we accept a variety of types, WP core validation and sanitization
864
+					// freaks out. We'll just validate this argument while handling the request
865
+					'validate_callback' => null,
866
+					'sanitize_callback' => null,
867
+				],
868
+				'order_by' => [
869
+					'required'          => false,
870
+					'default'           => $default_orderby,
871
+					'type'              => [
872
+						'object',
873
+						'string',
874
+					],// because we accept a variety of types, WP core validation and sanitization
875
+					// freaks out. We'll just validate this argument while handling the request
876
+					'validate_callback' => null,
877
+					'sanitize_callback' => null,
878
+				],
879
+				'group_by' => [
880
+					'required'          => false,
881
+					'default'           => null,
882
+					'type'              => [
883
+						'object',
884
+						'string',
885
+					],
886
+					// because we accept  an almost infinite list of possible groupings,
887
+					// WP core validation and sanitization
888
+					// freaks out. We'll just validate this argument while handling the request
889
+					'validate_callback' => null,
890
+					'sanitize_callback' => null,
891
+				],
892
+				'having'   => [
893
+					'required'          => false,
894
+					'default'           => null,
895
+					'type'              => 'object',
896
+					// because we accept an almost infinite list of possible where conditions, WP
897
+					// core validation and sanitization freaks out. We'll just validate this argument
898
+					// while handling the request
899
+					'validate_callback' => null,
900
+					'sanitize_callback' => null,
901
+				],
902
+				'caps'     => [
903
+					'required' => false,
904
+					'default'  => EEM_Base::caps_read,
905
+					'type'     => 'string',
906
+					'enum'     => [
907
+						EEM_Base::caps_read,
908
+						EEM_Base::caps_read_admin,
909
+						EEM_Base::caps_edit,
910
+						EEM_Base::caps_delete,
911
+					],
912
+				],
913
+			]
914
+		);
915
+	}
916
+
917
+
918
+	/**
919
+	 * Gets parameter information for a model regarding writing data
920
+	 *
921
+	 * @param string           $model_name
922
+	 * @param ModelVersionInfo $model_version_info
923
+	 * @param boolean          $create                                       whether this is for request to create (in
924
+	 *                                                                       which case we need all required params) or
925
+	 *                                                                       just to update (in which case we don't
926
+	 *                                                                       need those on every request)
927
+	 * @return array
928
+	 * @throws EE_Error
929
+	 * @throws ReflectionException
930
+	 */
931
+	protected function _get_write_params(
932
+		$model_name,
933
+		ModelVersionInfo $model_version_info,
934
+		$create = false
935
+	) {
936
+		$model = EE_Registry::instance()->load_model($model_name);
937
+		$fields = $model_version_info->fieldsOnModelInThisVersion($model);
938
+
939
+		// we do our own validation and sanitization within the controller
940
+		$sanitize_callback = function_exists('rest_validate_value_from_schema')
941
+			? ['EED_Core_Rest_Api', 'default_sanitize_callback']
942
+			: null;
943
+		$args_info = [];
944
+		foreach ($fields as $field_name => $field_obj) {
945
+			if ($field_obj->is_auto_increment()) {
946
+				// totally ignore auto increment IDs
947
+				continue;
948
+			}
949
+			$arg_info = $field_obj->getSchema();
950
+			$required = $create && ! $field_obj->is_nullable() && $field_obj->get_default_value() === null;
951
+			$arg_info['required'] = $required;
952
+			// remove the read-only flag. If it were read-only we wouldn't list it as an argument while writing, right?
953
+			unset($arg_info['readonly']);
954
+			$schema_properties = $field_obj->getSchemaProperties();
955
+			if (
956
+				isset($schema_properties['raw'])
957
+				&& $field_obj->getSchemaType() === 'object'
958
+			) {
959
+				// if there's a "raw" form of this argument, use those properties instead
960
+				$arg_info = array_replace(
961
+					$arg_info,
962
+					$schema_properties['raw']
963
+				);
964
+			}
965
+			$arg_info['default'] = ModelDataTranslator::prepareFieldValueForJson(
966
+				$field_obj,
967
+				$field_obj->get_default_value(),
968
+				$model_version_info->requestedVersion()
969
+			);
970
+			$arg_info['sanitize_callback'] = $sanitize_callback;
971
+			$args_info[ $field_name ] = $arg_info;
972
+			if ($field_obj instanceof EE_Datetime_Field) {
973
+				$gmt_arg_info = $arg_info;
974
+				$gmt_arg_info['description'] = sprintf(
975
+					esc_html__(
976
+						'%1$s - the value for this field in UTC. Ignored if %2$s is provided.',
977
+						'event_espresso'
978
+					),
979
+					$field_obj->get_nicename(),
980
+					$field_name
981
+				);
982
+				$args_info[ $field_name . '_gmt' ] = $gmt_arg_info;
983
+			}
984
+		}
985
+		return $args_info;
986
+	}
987
+
988
+
989
+	/**
990
+	 * Replacement for WP API's 'rest_parse_request_arg'.
991
+	 * If the value is blank but not required, don't bother validating it.
992
+	 * Also, it uses our email validation instead of WP API's default.
993
+	 *
994
+	 * @param                 $value
995
+	 * @param WP_REST_Request $request
996
+	 * @param                 $param
997
+	 * @return bool|true|WP_Error
998
+	 * @throws InvalidArgumentException
999
+	 * @throws InvalidInterfaceException
1000
+	 * @throws InvalidDataTypeException
1001
+	 */
1002
+	public static function default_sanitize_callback($value, WP_REST_Request $request, $param)
1003
+	{
1004
+		$attributes = $request->get_attributes();
1005
+		if (
1006
+			! isset($attributes['args'][ $param ])
1007
+			|| ! is_array($attributes['args'][ $param ])
1008
+		) {
1009
+			$validation_result = true;
1010
+		} else {
1011
+			$args = $attributes['args'][ $param ];
1012
+			if (
1013
+				(
1014
+					$value === ''
1015
+					|| $value === null
1016
+				)
1017
+				&& (! isset($args['required'])
1018
+					|| $args['required'] === false
1019
+				)
1020
+			) {
1021
+				// not required and not provided? that's cool
1022
+				$validation_result = true;
1023
+			} elseif (
1024
+				isset($args['format'])
1025
+					  && $args['format'] === 'email'
1026
+			) {
1027
+				$validation_result = true;
1028
+				if (! EED_Core_Rest_Api::_validate_email($value)) {
1029
+					$validation_result = new WP_Error(
1030
+						'rest_invalid_param',
1031
+						esc_html__(
1032
+							'The email address is not valid or does not exist.',
1033
+							'event_espresso'
1034
+						)
1035
+					);
1036
+				}
1037
+			} else {
1038
+				$validation_result = rest_validate_value_from_schema($value, $args, $param);
1039
+			}
1040
+		}
1041
+		if (is_wp_error($validation_result)) {
1042
+			return $validation_result;
1043
+		}
1044
+		return rest_sanitize_request_arg($value, $request, $param);
1045
+	}
1046
+
1047
+
1048
+	/**
1049
+	 * Returns whether or not this email address is valid. Copied from EE_Email_Validation_Strategy::_validate_email()
1050
+	 *
1051
+	 * @param $email
1052
+	 * @return bool
1053
+	 * @throws InvalidArgumentException
1054
+	 * @throws InvalidInterfaceException
1055
+	 * @throws InvalidDataTypeException
1056
+	 */
1057
+	protected static function _validate_email($email)
1058
+	{
1059
+		try {
1060
+			EmailAddressFactory::create($email);
1061
+			return true;
1062
+		} catch (EmailValidationException $e) {
1063
+			return false;
1064
+		}
1065
+	}
1066
+
1067
+
1068
+	/**
1069
+	 * Gets routes for the config
1070
+	 *
1071
+	 * @return array @see _register_model_routes
1072
+	 * @deprecated since version 4.9.1
1073
+	 */
1074
+	protected function _register_config_routes()
1075
+	{
1076
+		$config_routes = [];
1077
+		foreach (EED_Core_Rest_Api::versions_served() as $version => $hidden_endpoint) {
1078
+			$config_routes[ EED_Core_Rest_Api::ee_api_namespace . $version ] = $this->_get_config_route_data_for_version(
1079
+				$version,
1080
+				$hidden_endpoint
1081
+			);
1082
+		}
1083
+		return $config_routes;
1084
+	}
1085
+
1086
+
1087
+	/**
1088
+	 * Gets routes for the config for the specified version
1089
+	 *
1090
+	 * @param string  $version
1091
+	 * @param boolean $hidden_endpoint
1092
+	 * @return array
1093
+	 */
1094
+	protected function _get_config_route_data_for_version($version, $hidden_endpoint)
1095
+	{
1096
+		return [
1097
+			'config'    => [
1098
+				[
1099
+					'callback'        => [
1100
+						'EventEspresso\core\libraries\rest_api\controllers\config\Read',
1101
+						'handleRequest',
1102
+					],
1103
+					'methods'         => WP_REST_Server::READABLE,
1104
+					'hidden_endpoint' => $hidden_endpoint,
1105
+					'callback_args'   => [$version],
1106
+				],
1107
+			],
1108
+			'site_info' => [
1109
+				[
1110
+					'callback'        => [
1111
+						'EventEspresso\core\libraries\rest_api\controllers\config\Read',
1112
+						'handleRequestSiteInfo',
1113
+					],
1114
+					'methods'         => WP_REST_Server::READABLE,
1115
+					'hidden_endpoint' => $hidden_endpoint,
1116
+					'callback_args'   => [$version],
1117
+				],
1118
+			],
1119
+		];
1120
+	}
1121
+
1122
+
1123
+	/**
1124
+	 * Gets the meta info routes
1125
+	 *
1126
+	 * @return array @see _register_model_routes
1127
+	 * @deprecated since version 4.9.1
1128
+	 */
1129
+	protected function _register_meta_routes()
1130
+	{
1131
+		$meta_routes = [];
1132
+		foreach (EED_Core_Rest_Api::versions_served() as $version => $hidden_endpoint) {
1133
+			$meta_routes[ EED_Core_Rest_Api::ee_api_namespace . $version ] = $this->_get_meta_route_data_for_version(
1134
+				$version,
1135
+				$hidden_endpoint
1136
+			);
1137
+		}
1138
+		return $meta_routes;
1139
+	}
1140
+
1141
+
1142
+	/**
1143
+	 * @param string  $version
1144
+	 * @param boolean $hidden_endpoint
1145
+	 * @return array
1146
+	 */
1147
+	protected function _get_meta_route_data_for_version($version, $hidden_endpoint = false)
1148
+	{
1149
+		return [
1150
+			'resources' => [
1151
+				[
1152
+					'callback'        => [
1153
+						'EventEspresso\core\libraries\rest_api\controllers\model\Meta',
1154
+						'handleRequestModelsMeta',
1155
+					],
1156
+					'methods'         => WP_REST_Server::READABLE,
1157
+					'hidden_endpoint' => $hidden_endpoint,
1158
+					'callback_args'   => [$version],
1159
+				],
1160
+			],
1161
+		];
1162
+	}
1163
+
1164
+
1165
+	/**
1166
+	 * Tries to hide old 4.6 endpoints from the
1167
+	 *
1168
+	 * @param array $route_data
1169
+	 * @return array
1170
+	 * @throws EE_Error
1171
+	 * @throws ReflectionException
1172
+	 */
1173
+	public static function hide_old_endpoints($route_data)
1174
+	{
1175
+		// allow API clients to override which endpoints get hidden, in case
1176
+		// they want to discover particular endpoints
1177
+		// also, we don't have access to the request so we have to just grab it from the superglobal
1178
+		$force_show_ee_namespace = ltrim(
1179
+			EED_Core_Rest_Api::getRequest()->getRequestParam('force_show_ee_namespace'),
1180
+			'/'
1181
+		);
1182
+		foreach (EED_Core_Rest_Api::get_ee_route_data() as $namespace => $relative_urls) {
1183
+			foreach ($relative_urls as $resource_name => $endpoints) {
1184
+				foreach ($endpoints as $key => $endpoint) {
1185
+					// skip schema and other route options
1186
+					if (! is_numeric($key)) {
1187
+						continue;
1188
+					}
1189
+					// by default, hide "hidden_endpoint"s, unless the request indicates
1190
+					// to $force_show_ee_namespace, in which case only show that one
1191
+					// namespace's endpoints (and hide all others)
1192
+					if (
1193
+						($force_show_ee_namespace !== '' && $force_show_ee_namespace !== $namespace)
1194
+						|| ($endpoint['hidden_endpoint'] && $force_show_ee_namespace === '')
1195
+					) {
1196
+						$full_route = '/' . ltrim($namespace, '/');
1197
+						$full_route .= '/' . ltrim($resource_name, '/');
1198
+						unset($route_data[ $full_route ]);
1199
+					}
1200
+				}
1201
+			}
1202
+		}
1203
+		return $route_data;
1204
+	}
1205
+
1206
+
1207
+	/**
1208
+	 * Returns an array describing which versions of core support serving requests for.
1209
+	 * Keys are core versions' major and minor version, and values are the
1210
+	 * LOWEST requested version they can serve. Eg, 4.7 can serve requests for 4.6-like
1211
+	 * data by just removing a few models and fields from the responses. However, 4.15 might remove
1212
+	 * the answers table entirely, in which case it would be very difficult for
1213
+	 * it to serve 4.6-style responses.
1214
+	 * Versions of core that are missing from this array are unknowns.
1215
+	 * previous ver
1216
+	 *
1217
+	 * @return array
1218
+	 */
1219
+	public static function version_compatibilities()
1220
+	{
1221
+		return apply_filters(
1222
+			'FHEE__EED_Core_REST_API__version_compatibilities',
1223
+			[
1224
+				'4.8.29' => '4.8.29',
1225
+				'4.8.33' => '4.8.29',
1226
+				'4.8.34' => '4.8.29',
1227
+				'4.8.36' => '4.8.29',
1228
+			]
1229
+		);
1230
+	}
1231
+
1232
+
1233
+	/**
1234
+	 * Gets the latest API version served. Eg if there
1235
+	 * are two versions served of the API, 4.8.29 and 4.8.32, and
1236
+	 * we are on core version 4.8.34, it will return the string "4.8.32"
1237
+	 *
1238
+	 * @return string
1239
+	 */
1240
+	public static function latest_rest_api_version()
1241
+	{
1242
+		$versions_served = EED_Core_Rest_Api::versions_served();
1243
+		$versions_served_keys = array_keys($versions_served);
1244
+		return end($versions_served_keys);
1245
+	}
1246
+
1247
+
1248
+	/**
1249
+	 * Using EED_Core_Rest_Api::version_compatibilities(), determines what version of
1250
+	 * EE the API can serve requests for. Eg, if we are on 4.15 of core, and
1251
+	 * we can serve requests from 4.12 or later, this will return array( '4.12', '4.13', '4.14', '4.15' ).
1252
+	 * We also indicate whether or not this version should be put in the index or not
1253
+	 *
1254
+	 * @return array keys are API version numbers (just major and minor numbers), and values
1255
+	 * are whether or not they should be hidden
1256
+	 */
1257
+	public static function versions_served()
1258
+	{
1259
+		$versions_served = [];
1260
+		$possibly_served_versions = EED_Core_Rest_Api::version_compatibilities();
1261
+		$lowest_compatible_version = end($possibly_served_versions);
1262
+		reset($possibly_served_versions);
1263
+		$versions_served_historically = array_keys($possibly_served_versions);
1264
+		$latest_version = end($versions_served_historically);
1265
+		reset($versions_served_historically);
1266
+		// for each version of core we have ever served:
1267
+		foreach ($versions_served_historically as $key_versioned_endpoint) {
1268
+			// if it's not above the current core version, and it's compatible with the current version of core
1269
+
1270
+			if ($key_versioned_endpoint === $latest_version) {
1271
+				// don't hide the latest version in the index
1272
+				$versions_served[ $key_versioned_endpoint ] = false;
1273
+			} elseif (
1274
+				version_compare($key_versioned_endpoint, $lowest_compatible_version, '>=')
1275
+				&& version_compare($key_versioned_endpoint, EED_Core_Rest_Api::core_version(), '<')
1276
+			) {
1277
+				// include, but hide, previous versions which are still supported
1278
+				$versions_served[ $key_versioned_endpoint ] = true;
1279
+			} elseif (
1280
+				apply_filters(
1281
+					'FHEE__EED_Core_Rest_Api__versions_served__include_incompatible_versions',
1282
+					false,
1283
+					$possibly_served_versions
1284
+				)
1285
+			) {
1286
+				// if a version is no longer supported, don't include it in index or list of versions served
1287
+				$versions_served[ $key_versioned_endpoint ] = true;
1288
+			}
1289
+		}
1290
+		return $versions_served;
1291
+	}
1292
+
1293
+
1294
+	/**
1295
+	 * Gets the major and minor version of EE core's version string
1296
+	 *
1297
+	 * @return string
1298
+	 */
1299
+	public static function core_version()
1300
+	{
1301
+		return apply_filters(
1302
+			'FHEE__EED_Core_REST_API__core_version',
1303
+			implode(
1304
+				'.',
1305
+				array_slice(
1306
+					explode(
1307
+						'.',
1308
+						espresso_version()
1309
+					),
1310
+					0,
1311
+					3
1312
+				)
1313
+			)
1314
+		);
1315
+	}
1316
+
1317
+
1318
+	/**
1319
+	 * Gets the default limit that should be used when querying for resources
1320
+	 *
1321
+	 * @return int
1322
+	 */
1323
+	public static function get_default_query_limit()
1324
+	{
1325
+		// we actually don't use a const because we want folks to always use
1326
+		// this method, not the const directly
1327
+		return apply_filters(
1328
+			'FHEE__EED_Core_Rest_Api__get_default_query_limit',
1329
+			50
1330
+		);
1331
+	}
1332
+
1333
+
1334
+	/**
1335
+	 * @param string $version api version string (i.e. '4.8.36')
1336
+	 * @return array
1337
+	 */
1338
+	public static function getCollectionRoutesIndexedByModelName($version = '')
1339
+	{
1340
+		$version = empty($version) ? EED_Core_Rest_Api::latest_rest_api_version() : $version;
1341
+		$model_names = EED_Core_Rest_Api::model_names_with_plural_routes($version);
1342
+		$collection_routes = [];
1343
+		foreach ($model_names as $model_name => $model_class_name) {
1344
+			$collection_routes[ strtolower($model_name) ] = '/' . EED_Core_Rest_Api::ee_api_namespace . $version . '/'
1345
+															. EEH_Inflector::pluralize_and_lower($model_name);
1346
+		}
1347
+		return $collection_routes;
1348
+	}
1349
+
1350
+
1351
+	/**
1352
+	 * Returns an array of primary key names indexed by model names.
1353
+	 *
1354
+	 * @param string $version
1355
+	 * @return array
1356
+	 */
1357
+	public static function getPrimaryKeyNamesIndexedByModelName($version = '')
1358
+	{
1359
+		$version = empty($version) ? EED_Core_Rest_Api::latest_rest_api_version() : $version;
1360
+		$model_names = EED_Core_Rest_Api::model_names_with_plural_routes($version);
1361
+		$primary_key_items = [];
1362
+		foreach ($model_names as $model_name => $model_class_name) {
1363
+			$primary_keys = $model_class_name::instance()->get_combined_primary_key_fields();
1364
+			foreach ($primary_keys as $primary_key_name => $primary_key_field) {
1365
+				if (count($primary_keys) > 1) {
1366
+					$primary_key_items[ strtolower($model_name) ][] = $primary_key_name;
1367
+				} else {
1368
+					$primary_key_items[ strtolower($model_name) ] = $primary_key_name;
1369
+				}
1370
+			}
1371
+		}
1372
+		return $primary_key_items;
1373
+	}
1374
+
1375
+
1376
+	/**
1377
+	 * Determines the EE REST API debug mode is activated, or not.
1378
+	 *
1379
+	 * @return bool
1380
+	 * @since 4.9.76.p
1381
+	 */
1382
+	public static function debugMode()
1383
+	{
1384
+		static $debug_mode = null; // could be class prop
1385
+		if ($debug_mode === null) {
1386
+			$debug_mode = defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE;
1387
+		}
1388
+		return $debug_mode;
1389
+	}
1390
+
1391
+
1392
+	/**
1393
+	 *    run - initial module setup
1394
+	 *
1395
+	 * @access    public
1396
+	 * @param WP $WP
1397
+	 * @return    void
1398
+	 */
1399
+	public function run($WP)
1400
+	{
1401
+	}
1402 1402
 }
Please login to merge, or discard this patch.