Completed
Branch master (24c3eb)
by
unknown
34:49 queued 28:57
created
admin/extend/events/templates/event_registration_options.template.php 2 patches
Indentation   +16 added lines, -16 removed lines patch added patch discarded remove patch
@@ -19,12 +19,12 @@  discard block
 block discarded – undo
19 19
 
20 20
 <?php
21 21
 $settings_array                = [
22
-    'max_registrants'                 => '<p>
22
+	'max_registrants'                 => '<p>
23 23
         <label for="max-registrants">
24 24
         ' . esc_html__(
25
-        'Maximum number of tickets allowed per order for this event: ',
26
-        'event_espresso'
27
-    ) . '
25
+		'Maximum number of tickets allowed per order for this event: ',
26
+		'event_espresso'
27
+	) . '
28 28
         </label>
29 29
         <input class="ee-numeric ee-input-width--small"
30 30
                 type="text" 
@@ -34,31 +34,31 @@  discard block
 block discarded – undo
34 34
                 size="4" 
35 35
                 />
36 36
         </p>',
37
-    'additional_registration_options' => $additional_registration_options,
38
-    'display_ticket_selector'         => '<p>
37
+	'additional_registration_options' => $additional_registration_options,
38
+	'display_ticket_selector'         => '<p>
39 39
             <label>' . esc_html__('Display Ticket Selector', 'event_espresso') . '</label>'
40
-            . $display_ticket_selector // already escaped
41
-            . '</p>',
42
-    'alternative_registration_page'   => '<p>
40
+			. $display_ticket_selector // already escaped
41
+			. '</p>',
42
+	'alternative_registration_page'   => '<p>
43 43
             <label>' . esc_html__('Alternative Registration Page', 'event_espresso') . '</label>
44 44
             <input name="externalURL" class="ee-input-width--big" size="20" type="text" value="' . esc_url_raw($_event->external_url()) . '"> 
45 45
             </p>',
46
-    'event_phone_number'              => '<p>
46
+	'event_phone_number'              => '<p>
47 47
             <label>' . esc_html__('Event Phone Number', 'event_espresso') . '</label>
48 48
             <input name="event_phone" class="ee-input-width--reg" size="20" type="text" value="' . esc_attr($_event->phone()) . '">
49 49
             </p>',
50
-    'default_registration_status'     => '<p>
50
+	'default_registration_status'     => '<p>
51 51
             <label>
52 52
             ' . esc_html__('Default Registration Status', 'event_espresso')
53
-             . EEH_Template::get_help_tab_link('event_editor_event_registration_options_help_tab')
54
-            . '</label>'
55
-             . $EVT_default_registration_status // already escaped
56
-             . '</p>',
53
+			 . EEH_Template::get_help_tab_link('event_editor_event_registration_options_help_tab')
54
+			. '</label>'
55
+			 . $EVT_default_registration_status // already escaped
56
+			 . '</p>',
57 57
 ];
58 58
 // filter
59 59
 $settings_array = apply_filters('FHEE__caffeinated_event_registration_options__template__settings', $settings_array);
60 60
 
61 61
 // echo
62 62
 foreach ($settings_array as $item) {
63
-    echo wp_kses($item, AllowedTags::getWithFormTags());
63
+	echo wp_kses($item, AllowedTags::getWithFormTags());
64 64
 }
Please login to merge, or discard this patch.
Spacing   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -18,34 +18,34 @@
 block discarded – undo
18 18
     </p>
19 19
 
20 20
 <?php
21
-$settings_array                = [
21
+$settings_array = [
22 22
     'max_registrants'                 => '<p>
23 23
         <label for="max-registrants">
24 24
         ' . esc_html__(
25 25
         'Maximum number of tickets allowed per order for this event: ',
26 26
         'event_espresso'
27
-    ) . '
27
+    ).'
28 28
         </label>
29 29
         <input class="ee-numeric ee-input-width--small"
30 30
                 type="text" 
31 31
                 id="max-registrants" 
32 32
                 name="additional_limit" 
33
-                value="' . esc_attr($additional_limit) . '"
33
+                value="' . esc_attr($additional_limit).'"
34 34
                 size="4" 
35 35
                 />
36 36
         </p>',
37 37
     'additional_registration_options' => $additional_registration_options,
38 38
     'display_ticket_selector'         => '<p>
39
-            <label>' . esc_html__('Display Ticket Selector', 'event_espresso') . '</label>'
39
+            <label>' . esc_html__('Display Ticket Selector', 'event_espresso').'</label>'
40 40
             . $display_ticket_selector // already escaped
41 41
             . '</p>',
42 42
     'alternative_registration_page'   => '<p>
43
-            <label>' . esc_html__('Alternative Registration Page', 'event_espresso') . '</label>
44
-            <input name="externalURL" class="ee-input-width--big" size="20" type="text" value="' . esc_url_raw($_event->external_url()) . '"> 
43
+            <label>' . esc_html__('Alternative Registration Page', 'event_espresso').'</label>
44
+            <input name="externalURL" class="ee-input-width--big" size="20" type="text" value="' . esc_url_raw($_event->external_url()).'"> 
45 45
             </p>',
46 46
     'event_phone_number'              => '<p>
47
-            <label>' . esc_html__('Event Phone Number', 'event_espresso') . '</label>
48
-            <input name="event_phone" class="ee-input-width--reg" size="20" type="text" value="' . esc_attr($_event->phone()) . '">
47
+            <label>' . esc_html__('Event Phone Number', 'event_espresso').'</label>
48
+            <input name="event_phone" class="ee-input-width--reg" size="20" type="text" value="' . esc_attr($_event->phone()).'">
49 49
             </p>',
50 50
     'default_registration_status'     => '<p>
51 51
             <label>
Please login to merge, or discard this patch.
caffeinated/admin/extend/events/Extend_Events_Admin_Page.core.php 1 patch
Indentation   +1296 added lines, -1296 removed lines patch added patch discarded remove patch
@@ -19,1306 +19,1306 @@
 block discarded – undo
19 19
  */
20 20
 class Extend_Events_Admin_Page extends Events_Admin_Page
21 21
 {
22
-    /**
23
-     * Extend_Events_Admin_Page constructor.
24
-     *
25
-     * @param bool $routing
26
-     * @throws ReflectionException
27
-     */
28
-    public function __construct($routing = true)
29
-    {
30
-        if (! defined('EVENTS_CAF_TEMPLATE_PATH')) {
31
-            define('EVENTS_CAF_TEMPLATE_PATH', EE_CORE_CAF_ADMIN_EXTEND . 'events/templates/');
32
-            define('EVENTS_CAF_ASSETS', EE_CORE_CAF_ADMIN_EXTEND . 'events/assets/');
33
-            define('EVENTS_CAF_ASSETS_URL', EE_CORE_CAF_ADMIN_EXTEND_URL . 'events/assets/');
34
-        }
35
-        parent::__construct($routing);
36
-        $this->admin_config = $this->loader->getShared('EE_Admin_Config');
37
-    }
38
-
39
-
40
-    protected function _set_page_config()
41
-    {
42
-        parent::_set_page_config();
43
-
44
-        $this->_admin_base_path = EE_CORE_CAF_ADMIN_EXTEND . 'events';
45
-        // is there an evt_id in the request?
46
-        $EVT_ID                                          = $this->request->getRequestParam('EVT_ID', 0, 'int');
47
-        $EVT_ID                                          = $this->request->getRequestParam('post', $EVT_ID, 'int');
48
-        $TKT_ID                                          = $this->request->getRequestParam('TKT_ID', 0, 'int');
49
-        $new_page_routes                                 = [
50
-            'duplicate_event'          => [
51
-                'func'       => '_duplicate_event',
52
-                'capability' => 'ee_edit_event',
53
-                'obj_id'     => $EVT_ID,
54
-                'noheader'   => true,
55
-            ],
56
-            'import_page'              => [
57
-                'func'       => '_import_page',
58
-                'capability' => 'import',
59
-            ],
60
-            'import'                   => [
61
-                'func'       => '_import_events',
62
-                'capability' => 'import',
63
-                'noheader'   => true,
64
-            ],
65
-            'import_events'            => [
66
-                'func'       => '_import_events',
67
-                'capability' => 'import',
68
-                'noheader'   => true,
69
-            ],
70
-            'export_events'            => [
71
-                'func'       => '_events_export',
72
-                'capability' => 'export',
73
-                'noheader'   => true,
74
-            ],
75
-            'export_categories'        => [
76
-                'func'       => '_categories_export',
77
-                'capability' => 'export',
78
-                'noheader'   => true,
79
-            ],
80
-            'sample_export_file'       => [
81
-                'func'       => '_sample_export_file',
82
-                'capability' => 'export',
83
-                'noheader'   => true,
84
-            ],
85
-            'update_template_settings' => [
86
-                'func'       => '_update_template_settings',
87
-                'capability' => 'manage_options',
88
-                'noheader'   => true,
89
-            ],
90
-            'ticket_list_table'        => [
91
-                'func'       => '_tickets_overview_list_table',
92
-                'capability' => 'ee_read_default_tickets',
93
-            ],
94
-        ];
95
-        $this->_page_config['create_new']['metaboxes'][] = '_premium_event_editor_meta_boxes';
96
-        $this->_page_config['edit']['metaboxes'][]       = '_premium_event_editor_meta_boxes';
97
-        // don't load these meta boxes if using the advanced editor
98
-        if (
99
-            ! $this->admin_config->useAdvancedEditor()
100
-            || ! $this->feature->allowed('use_default_ticket_manager')
101
-        ) {
102
-            $this->_page_config['create_new']['qtips'][] = 'EE_Event_Editor_Tips';
103
-            $this->_page_config['edit']['qtips'][]       = 'EE_Event_Editor_Tips';
104
-
105
-            $legacy_editor_page_routes = [
106
-                'trash_ticket'    => [
107
-                    'func'       => '_trash_or_restore_ticket',
108
-                    'capability' => 'ee_delete_default_ticket',
109
-                    'obj_id'     => $TKT_ID,
110
-                    'noheader'   => true,
111
-                    'args'       => ['trash' => true],
112
-                ],
113
-                'trash_tickets'   => [
114
-                    'func'       => '_trash_or_restore_ticket',
115
-                    'capability' => 'ee_delete_default_tickets',
116
-                    'noheader'   => true,
117
-                    'args'       => ['trash' => true],
118
-                ],
119
-                'restore_ticket'  => [
120
-                    'func'       => '_trash_or_restore_ticket',
121
-                    'capability' => 'ee_delete_default_ticket',
122
-                    'obj_id'     => $TKT_ID,
123
-                    'noheader'   => true,
124
-                ],
125
-                'restore_tickets' => [
126
-                    'func'       => '_trash_or_restore_ticket',
127
-                    'capability' => 'ee_delete_default_tickets',
128
-                    'noheader'   => true,
129
-                ],
130
-                'delete_ticket'   => [
131
-                    'func'       => '_delete_ticket',
132
-                    'capability' => 'ee_delete_default_ticket',
133
-                    'obj_id'     => $TKT_ID,
134
-                    'noheader'   => true,
135
-                ],
136
-                'delete_tickets'  => [
137
-                    'func'       => '_delete_ticket',
138
-                    'capability' => 'ee_delete_default_tickets',
139
-                    'noheader'   => true,
140
-                ],
141
-            ];
142
-            $new_page_routes           = array_merge($new_page_routes, $legacy_editor_page_routes);
143
-        }
144
-
145
-        $this->_page_routes = array_merge($this->_page_routes, $new_page_routes);
146
-        // partial route/config override
147
-        $this->_page_config['import_events']['metaboxes'] = $this->_default_espresso_metaboxes;
148
-        $this->_page_config['default']['list_table']      = 'Extend_Events_Admin_List_Table';
149
-
150
-        // add default tickets tab and template settings nav tabs (note union at end)
151
-        $this->_page_config = [
152
-                                  'ticket_list_table' => [
153
-                                      'nav'           => [
154
-                                          'label' => esc_html__('Default Tickets', 'event_espresso'),
155
-                                          'icon'  => 'dashicons-tickets-alt',
156
-                                          'order' => 60,
157
-                                      ],
158
-                                      'list_table'    => 'Tickets_List_Table',
159
-                                      'require_nonce' => false,
160
-                                  ],
161
-                                  'template_settings' => [
162
-                                      'nav'           => [
163
-                                          'label' => esc_html__('Templates', 'event_espresso'),
164
-                                          'icon'  => 'dashicons-layout',
165
-                                          'order' => 30,
166
-                                      ],
167
-                                      'metaboxes'     => array_merge(
168
-                                          ['_publish_post_box'],
169
-                                          $this->_default_espresso_metaboxes
170
-                                      ),
171
-                                      'help_tabs'     => [
172
-                                          'general_settings_templates_help_tab' => [
173
-                                              'title'    => esc_html__('Templates', 'event_espresso'),
174
-                                              'filename' => 'general_settings_templates',
175
-                                          ],
176
-                                      ],
177
-                                      'require_nonce' => false,
178
-                                  ],
179
-                              ] + $this->_page_config;
180
-
181
-        // add filters and actions
182
-        // modifying _views
183
-        add_filter(
184
-            'FHEE_event_datetime_metabox_add_additional_date_time_template',
185
-            [$this, 'add_additional_datetime_button'],
186
-            10,
187
-            2
188
-        );
189
-        add_filter(
190
-            'FHEE_event_datetime_metabox_clone_button_template',
191
-            [$this, 'add_datetime_clone_button'],
192
-            10,
193
-            2
194
-        );
195
-        add_filter(
196
-            'FHEE_event_datetime_metabox_timezones_template',
197
-            [$this, 'datetime_timezones_template'],
198
-            10,
199
-            2
200
-        );
201
-        // filters for event list table
202
-        add_filter(
203
-            'FHEE__Events_Admin_List_Table__column_actions__action_links',
204
-            [$this, 'extra_list_table_actions'],
205
-            10,
206
-            2
207
-        );
208
-        // legend item
209
-        add_filter('FHEE__Events_Admin_Page___event_legend_items__items', [$this, 'additional_legend_items']);
210
-        add_action('admin_init', [$this, 'admin_init']);
211
-        // this is a filter that allows the addition of extra html after the permalink field on the wp post edit-form
212
-        // add_filter('get_sample_permalink_html', [DuplicateEventButton::class, 'addButton'], 8, 2);
213
-        DuplicateEventButton::addEventEditorPermalinkButton(8);
214
-    }
215
-
216
-
217
-    /**
218
-     * admin_init
219
-     */
220
-    public function admin_init()
221
-    {
222
-        EE_Registry::$i18n_js_strings['image_confirm']          = esc_html__(
223
-            'Do you really want to delete this image? Please remember to update your event to complete the removal.',
224
-            'event_espresso'
225
-        );
226
-        EE_Registry::$i18n_js_strings['event_starts_on']        = esc_html__('Event Starts on', 'event_espresso');
227
-        EE_Registry::$i18n_js_strings['event_ends_on']          = esc_html__('Event Ends on', 'event_espresso');
228
-        EE_Registry::$i18n_js_strings['event_datetime_actions'] = esc_html__('Actions', 'event_espresso');
229
-        EE_Registry::$i18n_js_strings['event_clone_dt_msg']     = esc_html__(
230
-            'Clone this Event Date and Time',
231
-            'event_espresso'
232
-        );
233
-        EE_Registry::$i18n_js_strings['remove_event_dt_msg']    = esc_html__(
234
-            'Remove this Event Time',
235
-            'event_espresso'
236
-        );
237
-    }
238
-
239
-
240
-    /**
241
-     * Add per page screen options to the default ticket list table view.
242
-     *
243
-     * @throws InvalidArgumentException
244
-     * @throws InvalidDataTypeException
245
-     * @throws InvalidInterfaceException
246
-     */
247
-    protected function _add_screen_options_ticket_list_table()
248
-    {
249
-        $this->_per_page_screen_option();
250
-    }
251
-
252
-
253
-    /**
254
-     * @param string      $return    the current html
255
-     * @param int         $id        the post id for the page
256
-     * @param string|null $new_title What the title is
257
-     * @param string|null $new_slug  what the slug is
258
-     * @return string
259
-     * @deprecated 5.0.0.p
260
-     */
261
-    public function extra_permalink_field_buttons(
262
-        string $return,
263
-        int $id,
264
-        ?string $new_title,
265
-        ?string $new_slug
266
-    ): string {
267
-        $return = DuplicateEventButton::addButton($return, $id, $new_title, $new_slug);
268
-        return TicketSelectorShortcodeButton::addButton($return, $id, $new_title, $new_slug);
269
-    }
270
-
271
-
272
-    /**
273
-     * Set the list table views for the default ticket list table view.
274
-     */
275
-    public function _set_list_table_views_ticket_list_table()
276
-    {
277
-        $this->_views = [
278
-            'all'     => [
279
-                'slug'        => 'all',
280
-                'label'       => esc_html__('All', 'event_espresso'),
281
-                'count'       => 0,
282
-                'bulk_action' => [
283
-                    'trash_tickets' => esc_html__('Move to Trash', 'event_espresso'),
284
-                ],
285
-            ],
286
-            'trashed' => [
287
-                'slug'        => 'trashed',
288
-                'label'       => esc_html__('Trash', 'event_espresso'),
289
-                'count'       => 0,
290
-                'bulk_action' => [
291
-                    'restore_tickets' => esc_html__('Restore from Trash', 'event_espresso'),
292
-                    'delete_tickets'  => esc_html__('Delete Permanently', 'event_espresso'),
293
-                ],
294
-            ],
295
-        ];
296
-    }
297
-
298
-
299
-    /**
300
-     * Enqueue scripts and styles for the event editor.
301
-     */
302
-    public function load_scripts_styles_edit()
303
-    {
304
-        if (! $this->admin_config->useAdvancedEditor()) {
305
-            wp_register_script(
306
-                'ee-event-editor-heartbeat',
307
-                EVENTS_CAF_ASSETS_URL . 'event-editor-heartbeat.js',
308
-                ['ee_admin_js', 'heartbeat'],
309
-                EVENT_ESPRESSO_VERSION,
310
-                true
311
-            );
312
-            wp_enqueue_script('ee-accounting');
313
-            wp_enqueue_script('ee-event-editor-heartbeat');
314
-        }
315
-        wp_enqueue_script('event_editor_js');
316
-        wp_register_style(
317
-            'event-editor-css',
318
-            EVENTS_ASSETS_URL . 'event-editor.css',
319
-            ['ee-admin-css'],
320
-            EVENT_ESPRESSO_VERSION
321
-        );
322
-        wp_enqueue_style('event-editor-css');
323
-        // styles
324
-        wp_enqueue_style('espresso-ui-theme');
325
-    }
326
-
327
-
328
-    /**
329
-     * Sets the views for the default list table view.
330
-     *
331
-     * @throws EE_Error
332
-     * @throws ReflectionException
333
-     */
334
-    protected function _set_list_table_views_default()
335
-    {
336
-        parent::_set_list_table_views_default();
337
-        $new_views    = [
338
-            'today' => [
339
-                'slug'        => 'today',
340
-                'label'       => esc_html__('Today', 'event_espresso'),
341
-                'count'       => $this->total_events_today(),
342
-                'bulk_action' => [
343
-                    'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
344
-                ],
345
-            ],
346
-            'month' => [
347
-                'slug'        => 'month',
348
-                'label'       => esc_html__('This Month', 'event_espresso'),
349
-                'count'       => $this->total_events_this_month(),
350
-                'bulk_action' => [
351
-                    'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
352
-                ],
353
-            ],
354
-        ];
355
-        $this->_views = array_merge($this->_views, $new_views);
356
-    }
357
-
358
-
359
-    /**
360
-     * Returns the extra action links for the default list table view.
361
-     *
362
-     * @param array    $action_links
363
-     * @param EE_Event $event
364
-     * @return array
365
-     * @throws EE_Error
366
-     * @throws ReflectionException
367
-     */
368
-    public function extra_list_table_actions(array $action_links, EE_Event $event): array
369
-    {
370
-        if (
371
-            EE_Registry::instance()->CAP->current_user_can(
372
-                'ee_read_registrations',
373
-                'espresso_registrations_reports',
374
-                $event->ID()
375
-            )
376
-        ) {
377
-            $reports_link = EE_Admin_Page::add_query_args_and_nonce(
378
-                [
379
-                    'action' => 'reports',
380
-                    'EVT_ID' => $event->ID(),
381
-                ],
382
-                REG_ADMIN_URL
383
-            );
384
-
385
-            $action_links[] = '
22
+	/**
23
+	 * Extend_Events_Admin_Page constructor.
24
+	 *
25
+	 * @param bool $routing
26
+	 * @throws ReflectionException
27
+	 */
28
+	public function __construct($routing = true)
29
+	{
30
+		if (! defined('EVENTS_CAF_TEMPLATE_PATH')) {
31
+			define('EVENTS_CAF_TEMPLATE_PATH', EE_CORE_CAF_ADMIN_EXTEND . 'events/templates/');
32
+			define('EVENTS_CAF_ASSETS', EE_CORE_CAF_ADMIN_EXTEND . 'events/assets/');
33
+			define('EVENTS_CAF_ASSETS_URL', EE_CORE_CAF_ADMIN_EXTEND_URL . 'events/assets/');
34
+		}
35
+		parent::__construct($routing);
36
+		$this->admin_config = $this->loader->getShared('EE_Admin_Config');
37
+	}
38
+
39
+
40
+	protected function _set_page_config()
41
+	{
42
+		parent::_set_page_config();
43
+
44
+		$this->_admin_base_path = EE_CORE_CAF_ADMIN_EXTEND . 'events';
45
+		// is there an evt_id in the request?
46
+		$EVT_ID                                          = $this->request->getRequestParam('EVT_ID', 0, 'int');
47
+		$EVT_ID                                          = $this->request->getRequestParam('post', $EVT_ID, 'int');
48
+		$TKT_ID                                          = $this->request->getRequestParam('TKT_ID', 0, 'int');
49
+		$new_page_routes                                 = [
50
+			'duplicate_event'          => [
51
+				'func'       => '_duplicate_event',
52
+				'capability' => 'ee_edit_event',
53
+				'obj_id'     => $EVT_ID,
54
+				'noheader'   => true,
55
+			],
56
+			'import_page'              => [
57
+				'func'       => '_import_page',
58
+				'capability' => 'import',
59
+			],
60
+			'import'                   => [
61
+				'func'       => '_import_events',
62
+				'capability' => 'import',
63
+				'noheader'   => true,
64
+			],
65
+			'import_events'            => [
66
+				'func'       => '_import_events',
67
+				'capability' => 'import',
68
+				'noheader'   => true,
69
+			],
70
+			'export_events'            => [
71
+				'func'       => '_events_export',
72
+				'capability' => 'export',
73
+				'noheader'   => true,
74
+			],
75
+			'export_categories'        => [
76
+				'func'       => '_categories_export',
77
+				'capability' => 'export',
78
+				'noheader'   => true,
79
+			],
80
+			'sample_export_file'       => [
81
+				'func'       => '_sample_export_file',
82
+				'capability' => 'export',
83
+				'noheader'   => true,
84
+			],
85
+			'update_template_settings' => [
86
+				'func'       => '_update_template_settings',
87
+				'capability' => 'manage_options',
88
+				'noheader'   => true,
89
+			],
90
+			'ticket_list_table'        => [
91
+				'func'       => '_tickets_overview_list_table',
92
+				'capability' => 'ee_read_default_tickets',
93
+			],
94
+		];
95
+		$this->_page_config['create_new']['metaboxes'][] = '_premium_event_editor_meta_boxes';
96
+		$this->_page_config['edit']['metaboxes'][]       = '_premium_event_editor_meta_boxes';
97
+		// don't load these meta boxes if using the advanced editor
98
+		if (
99
+			! $this->admin_config->useAdvancedEditor()
100
+			|| ! $this->feature->allowed('use_default_ticket_manager')
101
+		) {
102
+			$this->_page_config['create_new']['qtips'][] = 'EE_Event_Editor_Tips';
103
+			$this->_page_config['edit']['qtips'][]       = 'EE_Event_Editor_Tips';
104
+
105
+			$legacy_editor_page_routes = [
106
+				'trash_ticket'    => [
107
+					'func'       => '_trash_or_restore_ticket',
108
+					'capability' => 'ee_delete_default_ticket',
109
+					'obj_id'     => $TKT_ID,
110
+					'noheader'   => true,
111
+					'args'       => ['trash' => true],
112
+				],
113
+				'trash_tickets'   => [
114
+					'func'       => '_trash_or_restore_ticket',
115
+					'capability' => 'ee_delete_default_tickets',
116
+					'noheader'   => true,
117
+					'args'       => ['trash' => true],
118
+				],
119
+				'restore_ticket'  => [
120
+					'func'       => '_trash_or_restore_ticket',
121
+					'capability' => 'ee_delete_default_ticket',
122
+					'obj_id'     => $TKT_ID,
123
+					'noheader'   => true,
124
+				],
125
+				'restore_tickets' => [
126
+					'func'       => '_trash_or_restore_ticket',
127
+					'capability' => 'ee_delete_default_tickets',
128
+					'noheader'   => true,
129
+				],
130
+				'delete_ticket'   => [
131
+					'func'       => '_delete_ticket',
132
+					'capability' => 'ee_delete_default_ticket',
133
+					'obj_id'     => $TKT_ID,
134
+					'noheader'   => true,
135
+				],
136
+				'delete_tickets'  => [
137
+					'func'       => '_delete_ticket',
138
+					'capability' => 'ee_delete_default_tickets',
139
+					'noheader'   => true,
140
+				],
141
+			];
142
+			$new_page_routes           = array_merge($new_page_routes, $legacy_editor_page_routes);
143
+		}
144
+
145
+		$this->_page_routes = array_merge($this->_page_routes, $new_page_routes);
146
+		// partial route/config override
147
+		$this->_page_config['import_events']['metaboxes'] = $this->_default_espresso_metaboxes;
148
+		$this->_page_config['default']['list_table']      = 'Extend_Events_Admin_List_Table';
149
+
150
+		// add default tickets tab and template settings nav tabs (note union at end)
151
+		$this->_page_config = [
152
+								  'ticket_list_table' => [
153
+									  'nav'           => [
154
+										  'label' => esc_html__('Default Tickets', 'event_espresso'),
155
+										  'icon'  => 'dashicons-tickets-alt',
156
+										  'order' => 60,
157
+									  ],
158
+									  'list_table'    => 'Tickets_List_Table',
159
+									  'require_nonce' => false,
160
+								  ],
161
+								  'template_settings' => [
162
+									  'nav'           => [
163
+										  'label' => esc_html__('Templates', 'event_espresso'),
164
+										  'icon'  => 'dashicons-layout',
165
+										  'order' => 30,
166
+									  ],
167
+									  'metaboxes'     => array_merge(
168
+										  ['_publish_post_box'],
169
+										  $this->_default_espresso_metaboxes
170
+									  ),
171
+									  'help_tabs'     => [
172
+										  'general_settings_templates_help_tab' => [
173
+											  'title'    => esc_html__('Templates', 'event_espresso'),
174
+											  'filename' => 'general_settings_templates',
175
+										  ],
176
+									  ],
177
+									  'require_nonce' => false,
178
+								  ],
179
+							  ] + $this->_page_config;
180
+
181
+		// add filters and actions
182
+		// modifying _views
183
+		add_filter(
184
+			'FHEE_event_datetime_metabox_add_additional_date_time_template',
185
+			[$this, 'add_additional_datetime_button'],
186
+			10,
187
+			2
188
+		);
189
+		add_filter(
190
+			'FHEE_event_datetime_metabox_clone_button_template',
191
+			[$this, 'add_datetime_clone_button'],
192
+			10,
193
+			2
194
+		);
195
+		add_filter(
196
+			'FHEE_event_datetime_metabox_timezones_template',
197
+			[$this, 'datetime_timezones_template'],
198
+			10,
199
+			2
200
+		);
201
+		// filters for event list table
202
+		add_filter(
203
+			'FHEE__Events_Admin_List_Table__column_actions__action_links',
204
+			[$this, 'extra_list_table_actions'],
205
+			10,
206
+			2
207
+		);
208
+		// legend item
209
+		add_filter('FHEE__Events_Admin_Page___event_legend_items__items', [$this, 'additional_legend_items']);
210
+		add_action('admin_init', [$this, 'admin_init']);
211
+		// this is a filter that allows the addition of extra html after the permalink field on the wp post edit-form
212
+		// add_filter('get_sample_permalink_html', [DuplicateEventButton::class, 'addButton'], 8, 2);
213
+		DuplicateEventButton::addEventEditorPermalinkButton(8);
214
+	}
215
+
216
+
217
+	/**
218
+	 * admin_init
219
+	 */
220
+	public function admin_init()
221
+	{
222
+		EE_Registry::$i18n_js_strings['image_confirm']          = esc_html__(
223
+			'Do you really want to delete this image? Please remember to update your event to complete the removal.',
224
+			'event_espresso'
225
+		);
226
+		EE_Registry::$i18n_js_strings['event_starts_on']        = esc_html__('Event Starts on', 'event_espresso');
227
+		EE_Registry::$i18n_js_strings['event_ends_on']          = esc_html__('Event Ends on', 'event_espresso');
228
+		EE_Registry::$i18n_js_strings['event_datetime_actions'] = esc_html__('Actions', 'event_espresso');
229
+		EE_Registry::$i18n_js_strings['event_clone_dt_msg']     = esc_html__(
230
+			'Clone this Event Date and Time',
231
+			'event_espresso'
232
+		);
233
+		EE_Registry::$i18n_js_strings['remove_event_dt_msg']    = esc_html__(
234
+			'Remove this Event Time',
235
+			'event_espresso'
236
+		);
237
+	}
238
+
239
+
240
+	/**
241
+	 * Add per page screen options to the default ticket list table view.
242
+	 *
243
+	 * @throws InvalidArgumentException
244
+	 * @throws InvalidDataTypeException
245
+	 * @throws InvalidInterfaceException
246
+	 */
247
+	protected function _add_screen_options_ticket_list_table()
248
+	{
249
+		$this->_per_page_screen_option();
250
+	}
251
+
252
+
253
+	/**
254
+	 * @param string      $return    the current html
255
+	 * @param int         $id        the post id for the page
256
+	 * @param string|null $new_title What the title is
257
+	 * @param string|null $new_slug  what the slug is
258
+	 * @return string
259
+	 * @deprecated 5.0.0.p
260
+	 */
261
+	public function extra_permalink_field_buttons(
262
+		string $return,
263
+		int $id,
264
+		?string $new_title,
265
+		?string $new_slug
266
+	): string {
267
+		$return = DuplicateEventButton::addButton($return, $id, $new_title, $new_slug);
268
+		return TicketSelectorShortcodeButton::addButton($return, $id, $new_title, $new_slug);
269
+	}
270
+
271
+
272
+	/**
273
+	 * Set the list table views for the default ticket list table view.
274
+	 */
275
+	public function _set_list_table_views_ticket_list_table()
276
+	{
277
+		$this->_views = [
278
+			'all'     => [
279
+				'slug'        => 'all',
280
+				'label'       => esc_html__('All', 'event_espresso'),
281
+				'count'       => 0,
282
+				'bulk_action' => [
283
+					'trash_tickets' => esc_html__('Move to Trash', 'event_espresso'),
284
+				],
285
+			],
286
+			'trashed' => [
287
+				'slug'        => 'trashed',
288
+				'label'       => esc_html__('Trash', 'event_espresso'),
289
+				'count'       => 0,
290
+				'bulk_action' => [
291
+					'restore_tickets' => esc_html__('Restore from Trash', 'event_espresso'),
292
+					'delete_tickets'  => esc_html__('Delete Permanently', 'event_espresso'),
293
+				],
294
+			],
295
+		];
296
+	}
297
+
298
+
299
+	/**
300
+	 * Enqueue scripts and styles for the event editor.
301
+	 */
302
+	public function load_scripts_styles_edit()
303
+	{
304
+		if (! $this->admin_config->useAdvancedEditor()) {
305
+			wp_register_script(
306
+				'ee-event-editor-heartbeat',
307
+				EVENTS_CAF_ASSETS_URL . 'event-editor-heartbeat.js',
308
+				['ee_admin_js', 'heartbeat'],
309
+				EVENT_ESPRESSO_VERSION,
310
+				true
311
+			);
312
+			wp_enqueue_script('ee-accounting');
313
+			wp_enqueue_script('ee-event-editor-heartbeat');
314
+		}
315
+		wp_enqueue_script('event_editor_js');
316
+		wp_register_style(
317
+			'event-editor-css',
318
+			EVENTS_ASSETS_URL . 'event-editor.css',
319
+			['ee-admin-css'],
320
+			EVENT_ESPRESSO_VERSION
321
+		);
322
+		wp_enqueue_style('event-editor-css');
323
+		// styles
324
+		wp_enqueue_style('espresso-ui-theme');
325
+	}
326
+
327
+
328
+	/**
329
+	 * Sets the views for the default list table view.
330
+	 *
331
+	 * @throws EE_Error
332
+	 * @throws ReflectionException
333
+	 */
334
+	protected function _set_list_table_views_default()
335
+	{
336
+		parent::_set_list_table_views_default();
337
+		$new_views    = [
338
+			'today' => [
339
+				'slug'        => 'today',
340
+				'label'       => esc_html__('Today', 'event_espresso'),
341
+				'count'       => $this->total_events_today(),
342
+				'bulk_action' => [
343
+					'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
344
+				],
345
+			],
346
+			'month' => [
347
+				'slug'        => 'month',
348
+				'label'       => esc_html__('This Month', 'event_espresso'),
349
+				'count'       => $this->total_events_this_month(),
350
+				'bulk_action' => [
351
+					'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
352
+				],
353
+			],
354
+		];
355
+		$this->_views = array_merge($this->_views, $new_views);
356
+	}
357
+
358
+
359
+	/**
360
+	 * Returns the extra action links for the default list table view.
361
+	 *
362
+	 * @param array    $action_links
363
+	 * @param EE_Event $event
364
+	 * @return array
365
+	 * @throws EE_Error
366
+	 * @throws ReflectionException
367
+	 */
368
+	public function extra_list_table_actions(array $action_links, EE_Event $event): array
369
+	{
370
+		if (
371
+			EE_Registry::instance()->CAP->current_user_can(
372
+				'ee_read_registrations',
373
+				'espresso_registrations_reports',
374
+				$event->ID()
375
+			)
376
+		) {
377
+			$reports_link = EE_Admin_Page::add_query_args_and_nonce(
378
+				[
379
+					'action' => 'reports',
380
+					'EVT_ID' => $event->ID(),
381
+				],
382
+				REG_ADMIN_URL
383
+			);
384
+
385
+			$action_links[] = '
386 386
                 <a href="' . $reports_link . '"
387 387
                     aria-label="' . esc_attr__('View Report', 'event_espresso') . '"
388 388
                     class="ee-aria-tooltip button button--icon-only"
389 389
                 >
390 390
                     <span class="dashicons dashicons-chart-bar"></span>
391 391
                 </a>';
392
-        }
393
-        if (EE_Registry::instance()->CAP->current_user_can('ee_read_global_messages', 'view_filtered_messages')) {
394
-            EE_Registry::instance()->load_helper('MSG_Template');
395
-            $action_links[] = EEH_MSG_Template::get_message_action_link(
396
-                'see_notifications_for',
397
-                null,
398
-                ['EVT_ID' => $event->ID()]
399
-            );
400
-        }
401
-        return $action_links;
402
-    }
403
-
404
-
405
-    /**
406
-     * @param $items
407
-     * @return mixed
408
-     */
409
-    public function additional_legend_items($items)
410
-    {
411
-        if (
412
-            EE_Registry::instance()->CAP->current_user_can(
413
-                'ee_read_registrations',
414
-                'espresso_registrations_reports'
415
-            )
416
-        ) {
417
-            $items['reports'] = [
418
-                'class' => 'dashicons dashicons-chart-bar',
419
-                'desc'  => esc_html__('Event Reports', 'event_espresso'),
420
-            ];
421
-        }
422
-        if (EE_Registry::instance()->CAP->current_user_can('ee_read_global_messages', 'view_filtered_messages')) {
423
-            $related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
424
-            // $related_for_icon can sometimes be a string so 'css_class' would be an illegal offset
425
-            // (can only use numeric offsets when treating strings as arrays)
426
-            if (is_array($related_for_icon) && isset($related_for_icon['css_class'], $related_for_icon['label'])) {
427
-                $items['view_related_messages'] = [
428
-                    'class' => $related_for_icon['css_class'],
429
-                    'desc'  => $related_for_icon['label'],
430
-                ];
431
-            }
432
-        }
433
-        return $items;
434
-    }
435
-
436
-
437
-    /**
438
-     * This is the callback method for the duplicate event route
439
-     * Method looks for 'EVT_ID' in the request and retrieves that event and its details and duplicates them
440
-     * into a new event.  We add a hook so that any plugins that add extra event details can hook into this
441
-     * action.  Note that the dupe will have **DUPLICATE** as its title and slug.
442
-     * After duplication the redirect is to the new event edit page.
443
-     *
444
-     * @return void
445
-     * @throws EE_Error If EE_Event is not available with given ID
446
-     * @throws ReflectionException
447
-     * @access protected
448
-     */
449
-    protected function _duplicate_event()
450
-    {
451
-        // first make sure the ID for the event is in the request.
452
-        //  If it isn't then we need to bail and redirect back to overview list table (cause how did we get here?)
453
-        $EVT_ID = $this->request->getRequestParam('EVT_ID', 0, 'int');
454
-        if (! $EVT_ID) {
455
-            EE_Error::add_error(
456
-                esc_html__(
457
-                    'In order to duplicate an event an Event ID is required.  None was given.',
458
-                    'event_espresso'
459
-                ),
460
-                __FILE__,
461
-                __FUNCTION__,
462
-                __LINE__
463
-            );
464
-            $this->_redirect_after_action(false, '', '', [], true);
465
-            return;
466
-        }
467
-        // k we've got EVT_ID so let's use that to get the event we'll duplicate
468
-        $orig_event = EEM_Event::instance()->get_one_by_ID($EVT_ID);
469
-        if (! $orig_event instanceof EE_Event) {
470
-            throw new EE_Error(
471
-                sprintf(
472
-                    esc_html__('An EE_Event object could not be retrieved for the given ID (%s)', 'event_espresso'),
473
-                    $EVT_ID
474
-                )
475
-            );
476
-        }
477
-        // k now let's clone the $orig_event before getting relations
478
-        $new_event = clone $orig_event;
479
-        // original datetimes
480
-        $orig_datetimes = $orig_event->get_many_related('Datetime');
481
-        // other original relations
482
-        $orig_ven = $orig_event->get_many_related('Venue');
483
-        // reset the ID and modify other details to make it clear this is a dupe
484
-        $new_event->set('EVT_ID', 0);
485
-        $new_name = $new_event->name() . ' ' . esc_html__('**DUPLICATE**', 'event_espresso');
486
-        $new_event->set('EVT_name', $new_name);
487
-        $new_event->set(
488
-            'EVT_slug',
489
-            wp_unique_post_slug(
490
-                sanitize_title($orig_event->name()),
491
-                0,
492
-                'publish',
493
-                EspressoPostType::EVENTS,
494
-                0
495
-            )
496
-        );
497
-        $new_event->set('status', 'draft');
498
-        // duplicate discussion settings
499
-        $new_event->set('comment_status', $orig_event->get('comment_status'));
500
-        $new_event->set('ping_status', $orig_event->get('ping_status'));
501
-        // save the new event
502
-        $new_event->save();
503
-        // venues
504
-        foreach ($orig_ven as $ven) {
505
-            $new_event->_add_relation_to($ven, 'Venue');
506
-        }
507
-        $new_event->save();
508
-        // now we need to get the question group relations and handle that
509
-        // first primary question groups
510
-        $orig_primary_qgs = $orig_event->get_many_related(
511
-            'Question_Group',
512
-            [['Event_Question_Group.EQG_primary' => true]]
513
-        );
514
-        if (! empty($orig_primary_qgs)) {
515
-            foreach ($orig_primary_qgs as $obj) {
516
-                if ($obj instanceof EE_Question_Group) {
517
-                    $new_event->_add_relation_to($obj, 'Question_Group', ['EQG_primary' => true]);
518
-                }
519
-            }
520
-        }
521
-        // next additional attendee question groups
522
-        $orig_additional_qgs = $orig_event->get_many_related(
523
-            'Question_Group',
524
-            [['Event_Question_Group.EQG_additional' => true]]
525
-        );
526
-        if (! empty($orig_additional_qgs)) {
527
-            foreach ($orig_additional_qgs as $obj) {
528
-                if ($obj instanceof EE_Question_Group) {
529
-                    $new_event->_add_relation_to($obj, 'Question_Group', ['EQG_additional' => true]);
530
-                }
531
-            }
532
-        }
533
-
534
-        $new_event->save();
535
-
536
-        // k now that we have the new event saved we can loop through the datetimes and start adding relations.
537
-        $cloned_tickets = [];
538
-        foreach ($orig_datetimes as $orig_dtt) {
539
-            if (! $orig_dtt instanceof EE_Datetime) {
540
-                continue;
541
-            }
542
-            $new_dtt      = clone $orig_dtt;
543
-            $orig_tickets = $orig_dtt->tickets();
544
-            // save new dtt then add to event
545
-            $new_dtt->set('DTT_ID', 0);
546
-            $new_dtt->set('DTT_sold', 0);
547
-            $new_dtt->set_reserved(0);
548
-            $new_dtt->save();
549
-            $new_event->_add_relation_to($new_dtt, 'Datetime');
550
-            $new_event->save();
551
-            // now let's get the ticket relations setup.
552
-            foreach ((array) $orig_tickets as $orig_ticket) {
553
-                // it's possible a datetime will have no tickets so let's verify we HAVE a ticket first.
554
-                if (! $orig_ticket instanceof EE_Ticket) {
555
-                    continue;
556
-                }
557
-                // is this ticket archived?  If it is then let's skip
558
-                if ($orig_ticket->get('TKT_deleted')) {
559
-                    continue;
560
-                }
561
-                // does this original ticket already exist in the clone_tickets cache?
562
-                //  If so we'll just use the new ticket from it.
563
-                if (isset($cloned_tickets[ $orig_ticket->ID() ])) {
564
-                    $new_ticket = $cloned_tickets[ $orig_ticket->ID() ];
565
-                } else {
566
-                    $new_ticket = clone $orig_ticket;
567
-                    // get relations on the $orig_ticket that we need to set up.
568
-                    $orig_prices = $orig_ticket->prices();
569
-                    $new_ticket->set('TKT_ID', 0);
570
-                    $new_ticket->set('TKT_sold', 0);
571
-                    $new_ticket->set('TKT_reserved', 0);
572
-                    // make sure new ticket has ID.
573
-                    $new_ticket->save();
574
-                    // price relations on new ticket need to be setup.
575
-                    foreach ($orig_prices as $orig_price) {
576
-                        // don't clone default prices, just add a relation
577
-                        if ($orig_price->is_default()) {
578
-                            $new_ticket->_add_relation_to($orig_price, 'Price');
579
-                            $new_ticket->save();
580
-                            continue;
581
-                        }
582
-                        $new_price = clone $orig_price;
583
-                        $new_price->set('PRC_ID', 0);
584
-                        $new_price->save();
585
-                        $new_ticket->_add_relation_to($new_price, 'Price');
586
-                    }
587
-                    $new_ticket->save();
588
-
589
-                    do_action(
590
-                        'AHEE__Extend_Events_Admin_Page___duplicate_event__duplicate_ticket__after',
591
-                        $orig_ticket,
592
-                        $new_ticket,
593
-                        $orig_prices,
594
-                        $orig_event,
595
-                        $orig_dtt,
596
-                        $new_dtt
597
-                    );
598
-                    $cloned_tickets[ $orig_ticket->ID() ] = $new_ticket;
599
-                }
600
-                // k now we can add the new ticket as a relation to the new datetime
601
-                // and make sure it's added to our cached $cloned_tickets array
602
-                // for use with later datetimes that have the same ticket.
603
-                $new_dtt->_add_relation_to($new_ticket, 'Ticket');
604
-            }
605
-            $new_dtt->save();
606
-        }
607
-        // clone taxonomy information
608
-        $taxonomies_to_clone_with = apply_filters(
609
-            'FHEE__Extend_Events_Admin_Page___duplicate_event__taxonomies_to_clone',
610
-            ['espresso_event_categories', 'espresso_event_type', 'post_tag']
611
-        );
612
-        // get terms for original event (notice)
613
-        $orig_terms = wp_get_object_terms($orig_event->ID(), $taxonomies_to_clone_with);
614
-        // loop through terms and add them to new event.
615
-        foreach ($orig_terms as $term) {
616
-            wp_set_object_terms($new_event->ID(), $term->term_id, $term->taxonomy, true);
617
-        }
618
-
619
-        // duplicate other core WP_Post items for this event.
620
-        // post thumbnail (feature image).
621
-        $feature_image_id = get_post_thumbnail_id($orig_event->ID());
622
-        if ($feature_image_id) {
623
-            update_post_meta($new_event->ID(), '_thumbnail_id', $feature_image_id);
624
-        }
625
-
626
-        // duplicate page_template setting
627
-        $page_template = get_post_meta($orig_event->ID(), '_wp_page_template', true);
628
-        if ($page_template) {
629
-            update_post_meta($new_event->ID(), '_wp_page_template', $page_template);
630
-        }
631
-
632
-        do_action('AHEE__Extend_Events_Admin_Page___duplicate_event__after', $new_event, $orig_event);
633
-        // now let's redirect to the edit page for this duplicated event if we have a new event id.
634
-        if ($new_event->ID()) {
635
-            $redirect_args = [
636
-                'post'   => $new_event->ID(),
637
-                'action' => 'edit',
638
-            ];
639
-            EE_Error::add_success(
640
-                esc_html__(
641
-                    'Event successfully duplicated.  Please review the details below and make any necessary edits',
642
-                    'event_espresso'
643
-                )
644
-            );
645
-        } else {
646
-            $redirect_args = [
647
-                'action' => 'default',
648
-            ];
649
-            EE_Error::add_error(
650
-                esc_html__('Not able to duplicate event.  Something went wrong.', 'event_espresso'),
651
-                __FILE__,
652
-                __FUNCTION__,
653
-                __LINE__
654
-            );
655
-        }
656
-        $this->_redirect_after_action(false, '', '', $redirect_args, true);
657
-    }
658
-
659
-
660
-    /**
661
-     * Generates output for the import page.
662
-     *
663
-     * @throws EE_Error
664
-     */
665
-    protected function _import_page()
666
-    {
667
-        $title = esc_html__('Import', 'event_espresso');
668
-        $intro = esc_html__(
669
-            'If you have a previously exported Event Espresso 4 information in a Comma Separated Value (CSV) file format, you can upload the file here: ',
670
-            'event_espresso'
671
-        );
672
-
673
-        $form_url = EVENTS_ADMIN_URL;
674
-        $action   = 'import_events';
675
-        $type     = 'csv';
676
-
677
-        $this->_template_args['form'] = EE_Import::instance()->upload_form(
678
-            $title,
679
-            $intro,
680
-            $form_url,
681
-            $action,
682
-            $type
683
-        );
684
-
685
-        $this->_template_args['sample_file_link']   = EE_Admin_Page::add_query_args_and_nonce(
686
-            ['action' => 'sample_export_file'],
687
-            $this->_admin_base_url
688
-        );
689
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
690
-            EVENTS_CAF_TEMPLATE_PATH . 'import_page.template.php',
691
-            $this->_template_args,
692
-            true
693
-        );
694
-        $this->display_admin_page_with_sidebar();
695
-    }
696
-
697
-
698
-    /**
699
-     * _import_events
700
-     * This handles displaying the screen and running imports for importing events.
701
-     *
702
-     * @return void
703
-     * @throws EE_Error
704
-     */
705
-    protected function _import_events()
706
-    {
707
-        require_once(EE_CLASSES . 'EE_Import.class.php');
708
-        $success = EE_Import::instance()->import();
709
-        $this->_redirect_after_action(
710
-            $success,
711
-            esc_html__('Import File', 'event_espresso'),
712
-            'ran',
713
-            ['action' => 'import_page'],
714
-            true
715
-        );
716
-    }
717
-
718
-
719
-    /**
720
-     * _events_export
721
-     * Will export all (or just the given event) to a Excel compatible file.
722
-     *
723
-     * @access protected
724
-     * @return void
725
-     */
726
-    protected function _events_export()
727
-    {
728
-        $EVT_ID = $this->request->getRequestParam('EVT_ID', 0, 'int');
729
-        $EVT_ID = $this->request->getRequestParam('EVT_IDs', $EVT_ID, 'int');
730
-        $this->request->mergeRequestParams(
731
-            [
732
-                'export' => 'report',
733
-                'action' => 'all_event_data',
734
-                'EVT_ID' => $EVT_ID,
735
-            ]
736
-        );
737
-        if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
738
-            require_once(EE_CLASSES . 'EE_Export.class.php');
739
-            $EE_Export = EE_Export::instance($this->request->requestParams());
740
-            $EE_Export->export();
741
-        }
742
-    }
743
-
744
-
745
-    /**
746
-     * handle category exports()
747
-     *
748
-     * @return void
749
-     */
750
-    protected function _categories_export()
751
-    {
752
-        $EVT_ID = $this->request->getRequestParam('EVT_CAT_ID', 0, 'int');
753
-        $this->request->mergeRequestParams(
754
-            [
755
-                'export' => 'report',
756
-                'action' => 'categories',
757
-                'EVT_ID' => $EVT_ID,
758
-            ]
759
-        );
760
-        if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
761
-            require_once(EE_CLASSES . 'EE_Export.class.php');
762
-            $EE_Export = EE_Export::instance($this->request->requestParams());
763
-            $EE_Export->export();
764
-        }
765
-    }
766
-
767
-
768
-    /**
769
-     * Creates a sample CSV file for importing
770
-     */
771
-    protected function _sample_export_file()
772
-    {
773
-        $EE_Export = EE_Export::instance();
774
-        if ($EE_Export instanceof EE_Export) {
775
-            $EE_Export->export();
776
-        }
777
-    }
778
-
779
-
780
-    /*************        Template Settings        *************/
781
-    /**
782
-     * Generates template settings page output
783
-     *
784
-     * @throws DomainException
785
-     * @throws EE_Error
786
-     * @throws InvalidArgumentException
787
-     * @throws InvalidDataTypeException
788
-     * @throws InvalidInterfaceException
789
-     */
790
-    protected function _template_settings()
791
-    {
792
-        new TemplateCacheAdmin(EE_Registry::instance()->CFG->template_settings, $this->request);
793
-        $this->_template_args['values'] = $this->_yes_no_values;
794
-        /**
795
-         * Note leaving this filter in for backward compatibility this was moved in 4.6.x
796
-         * from General_Settings_Admin_Page to here.
797
-         */
798
-        $this->_template_args = apply_filters(
799
-            'FHEE__General_Settings_Admin_Page__template_settings__template_args',
800
-            $this->_template_args
801
-        );
802
-        $this->_set_add_edit_form_tags('update_template_settings');
803
-        $this->_set_publish_post_box_vars();
804
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
805
-            EVENTS_CAF_TEMPLATE_PATH . 'template_settings.template.php',
806
-            $this->_template_args,
807
-            true
808
-        );
809
-        $this->display_admin_page_with_sidebar();
810
-    }
811
-
812
-
813
-    /**
814
-     * Handler for updating template settings.
815
-     *
816
-     * @throws EE_Error
817
-     */
818
-    protected function _update_template_settings()
819
-    {
820
-        new TemplateCacheAdmin(EE_Registry::instance()->CFG->template_settings, $this->request);
821
-        /**
822
-         * Note leaving this filter in for backward compatibility this was moved in 4.6.x
823
-         * from General_Settings_Admin_Page to here.
824
-         */
825
-        EE_Registry::instance()->CFG->template_settings = apply_filters(
826
-            'FHEE__General_Settings_Admin_Page__update_template_settings__data',
827
-            EE_Registry::instance()->CFG->template_settings,
828
-            $this->request->requestParams()
829
-        );
830
-        // update custom post type slugs and detect if we need to flush rewrite rules
831
-        $old_slug = EE_Registry::instance()->CFG->core->event_cpt_slug;
832
-
833
-        $event_cpt_slug = $this->request->getRequestParam('event_cpt_slug');
834
-
835
-        EE_Registry::instance()->CFG->core->event_cpt_slug = $event_cpt_slug
836
-            ? EEH_URL::slugify($event_cpt_slug, 'events')
837
-            : EE_Registry::instance()->CFG->core->event_cpt_slug;
838
-
839
-        $what    = esc_html__('Template Settings', 'event_espresso');
840
-        $success = $this->_update_espresso_configuration(
841
-            $what,
842
-            EE_Registry::instance()->CFG->template_settings,
843
-            __FILE__,
844
-            __FUNCTION__,
845
-            __LINE__
846
-        );
847
-        if (EE_Registry::instance()->CFG->core->event_cpt_slug !== $old_slug) {
848
-            /** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
849
-            $rewrite_rules = LoaderFactory::getLoader()->getShared(
850
-                'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
851
-            );
852
-            $rewrite_rules->flush();
853
-        }
854
-        do_action(
855
-            'AHEE__General_Settings_Admin_Page__update_template_settings__after_update',
856
-            EE_Registry::instance()->CFG->template_settings,
857
-            $this->request->requestParams(),
858
-            $success
859
-        );
860
-        $this->_redirect_after_action($success, $what, 'updated', ['action' => 'template_settings']);
861
-    }
862
-
863
-
864
-    /**
865
-     * _premium_event_editor_meta_boxes
866
-     * add all metaboxes related to the event_editor
867
-     *
868
-     * @access protected
869
-     * @return void
870
-     * @throws EE_Error
871
-     * @throws ReflectionException
872
-     */
873
-    protected function _premium_event_editor_meta_boxes()
874
-    {
875
-        $this->verify_cpt_object();
876
-        // check if the new EDTR reg options meta box is being used, and if so, don't load the legacy version
877
-        if (
878
-            ! $this->admin_config->useAdvancedEditor()
879
-            || ! $this->feature->allowed('use_reg_options_meta_box')
880
-        ) {
881
-            $this->addMetaBox(
882
-                'espresso_event_editor_event_options',
883
-                esc_html__('Event Registration Options', 'event_espresso'),
884
-                [$this, 'registration_options_meta_box'],
885
-                $this->page_slug,
886
-                'side',
887
-                'core'
888
-            );
889
-        }
890
-    }
891
-
892
-
893
-    /**
894
-     * override caf metabox
895
-     *
896
-     * @return void
897
-     * @throws EE_Error
898
-     * @throws ReflectionException
899
-     */
900
-    public function registration_options_meta_box()
901
-    {
902
-        $yes_no_values = [
903
-            ['id' => true, 'text' => esc_html__('Yes', 'event_espresso')],
904
-            ['id' => false, 'text' => esc_html__('No', 'event_espresso')],
905
-        ];
906
-
907
-        $default_reg_status_values = EEM_Registration::reg_status_array(
908
-            [
909
-                RegStatus::CANCELLED,
910
-                RegStatus::DECLINED,
911
-                RegStatus::INCOMPLETE,
912
-                RegStatus::WAIT_LIST,
913
-            ],
914
-            true
915
-        );
916
-
917
-        $template_args['active_status']    = $this->_cpt_model_obj->pretty_active_status(false);
918
-        $template_args['_event']           = $this->_cpt_model_obj;
919
-        $template_args['additional_limit'] = $this->_cpt_model_obj->additional_limit();
920
-
921
-        $template_args['default_registration_status']     = EEH_Form_Fields::select_input(
922
-            'default_reg_status',
923
-            $default_reg_status_values,
924
-            $this->_cpt_model_obj->default_registration_status(),
925
-            '',
926
-            'ee-input-width--reg',
927
-            false
928
-        );
929
-        $template_args['display_description']             = EEH_Form_Fields::select_input(
930
-            'display_desc',
931
-            $yes_no_values,
932
-            $this->_cpt_model_obj->display_description()
933
-        );
934
-        $template_args['display_ticket_selector']         = EEH_Form_Fields::select_input(
935
-            'display_ticket_selector',
936
-            $yes_no_values,
937
-            $this->_cpt_model_obj->display_ticket_selector(),
938
-            '',
939
-            'ee-input-width--small',
940
-            false
941
-        );
942
-        $template_args['EVT_default_registration_status'] = EEH_Form_Fields::select_input(
943
-            'EVT_default_registration_status',
944
-            $default_reg_status_values,
945
-            $this->_cpt_model_obj->default_registration_status(),
946
-            '',
947
-            'ee-input-width--reg',
948
-            false
949
-        );
950
-        $template_args['additional_registration_options'] = apply_filters(
951
-            'FHEE__Events_Admin_Page__registration_options_meta_box__additional_registration_options',
952
-            '',
953
-            $template_args,
954
-            $yes_no_values,
955
-            $default_reg_status_values
956
-        );
957
-        EEH_Template::display_template(
958
-            EVENTS_CAF_TEMPLATE_PATH . 'event_registration_options.template.php',
959
-            $template_args
960
-        );
961
-    }
962
-
963
-
964
-
965
-    /**
966
-     * wp_list_table_mods for caf
967
-     * ============================
968
-     */
969
-
970
-
971
-    /**
972
-     * espresso_event_months_dropdown
973
-     *
974
-     * @deprecatd 5.0.0.p
975
-     * @access public
976
-     * @return string                dropdown listing month/year selections for events.
977
-     * @throws EE_Error
978
-     */
979
-    public function espresso_event_months_dropdown(): string
980
-    {
981
-        // what we need to do is get all PRIMARY datetimes for all events to filter on.
982
-        // Note we need to include any other filters that are set!
983
-        return EEH_Form_Fields::generate_event_months_dropdown(
984
-            $this->request->getRequestParam('month_range', ''),
985
-            $this->request->getRequestParam('status', ''),
986
-            $this->request->getRequestParam('EVT_CAT', 0, 'int'),
987
-            $this->request->getRequestParam('active_status', '')
988
-        );
989
-    }
990
-
991
-
992
-    /**
993
-     * returns a list of "active" statuses on the event
994
-     *
995
-     * @deprecatd 5.0.0.p
996
-     * @param string $current_value whatever the current active status is
997
-     * @return string
998
-     */
999
-    public function active_status_dropdown(string $current_value = ''): string
1000
-    {
1001
-        $select_name = 'active_status';
1002
-        $values      = [
1003
-            'none'     => esc_html__('Show Active/Inactive', 'event_espresso'),
1004
-            'active'   => esc_html__('Active', 'event_espresso'),
1005
-            'upcoming' => esc_html__('Upcoming', 'event_espresso'),
1006
-            'expired'  => esc_html__('Expired', 'event_espresso'),
1007
-            'inactive' => esc_html__('Inactive', 'event_espresso'),
1008
-        ];
1009
-
1010
-        return EEH_Form_Fields::select_input($select_name, $values, $current_value);
1011
-    }
1012
-
1013
-
1014
-    /**
1015
-     * returns a list of "venues"
1016
-     *
1017
-     * @deprecatd 5.0.0.p
1018
-     * @param string $current_value whatever the current active status is
1019
-     * @return string
1020
-     * @throws EE_Error
1021
-     * @throws ReflectionException
1022
-     */
1023
-    protected function venuesDropdown(string $current_value = ''): string
1024
-    {
1025
-        $values = ['' => esc_html__('All Venues', 'event_espresso')];
1026
-        // populate the list of venues.
1027
-        $venues = EEM_Venue::instance()->get_all(['order_by' => ['VNU_name' => 'ASC']]);
1028
-
1029
-        foreach ($venues as $venue) {
1030
-            $values[ $venue->ID() ] = $venue->name();
1031
-        }
1032
-
1033
-        return EEH_Form_Fields::select_input('venue', $values, $current_value);
1034
-    }
1035
-
1036
-
1037
-    /**
1038
-     * output a dropdown of the categories for the category filter on the event admin list table
1039
-     *
1040
-     * @deprecatd 5.0.0.p
1041
-     * @access  public
1042
-     * @return string html
1043
-     * @throws EE_Error
1044
-     * @throws ReflectionException
1045
-     */
1046
-    public function category_dropdown(): string
1047
-    {
1048
-        return EEH_Form_Fields::generate_event_category_dropdown(
1049
-            $this->request->getRequestParam('EVT_CAT', -1, 'int')
1050
-        );
1051
-    }
1052
-
1053
-
1054
-    /**
1055
-     * get total number of events today
1056
-     *
1057
-     * @access public
1058
-     * @return int
1059
-     * @throws EE_Error
1060
-     * @throws InvalidArgumentException
1061
-     * @throws InvalidDataTypeException
1062
-     * @throws InvalidInterfaceException
1063
-     * @throws ReflectionException
1064
-     */
1065
-    public function total_events_today(): int
1066
-    {
1067
-        $start = EEM_Datetime::instance()->convert_datetime_for_query(
1068
-            'DTT_EVT_start',
1069
-            date('Y-m-d') . ' 00:00:00',
1070
-            'Y-m-d H:i:s',
1071
-            'UTC'
1072
-        );
1073
-        $end   = EEM_Datetime::instance()->convert_datetime_for_query(
1074
-            'DTT_EVT_start',
1075
-            date('Y-m-d') . ' 23:59:59',
1076
-            'Y-m-d H:i:s',
1077
-            'UTC'
1078
-        );
1079
-        $where = [
1080
-            'Datetime.DTT_EVT_start' => ['BETWEEN', [$start, $end]],
1081
-        ];
1082
-        return EEM_Event::instance()->count([$where, 'caps' => 'read_admin'], 'EVT_ID', true);
1083
-    }
1084
-
1085
-
1086
-    /**
1087
-     * get total number of events this month
1088
-     *
1089
-     * @access public
1090
-     * @return int
1091
-     * @throws EE_Error
1092
-     * @throws InvalidArgumentException
1093
-     * @throws InvalidDataTypeException
1094
-     * @throws InvalidInterfaceException
1095
-     * @throws ReflectionException
1096
-     */
1097
-    public function total_events_this_month(): int
1098
-    {
1099
-        // Dates
1100
-        $this_year_r     = date('Y');
1101
-        $this_month_r    = date('m');
1102
-        $days_this_month = date('t');
1103
-        $start           = EEM_Datetime::instance()->convert_datetime_for_query(
1104
-            'DTT_EVT_start',
1105
-            $this_year_r . '-' . $this_month_r . '-01 00:00:00',
1106
-            'Y-m-d H:i:s',
1107
-            'UTC'
1108
-        );
1109
-        $end             = EEM_Datetime::instance()->convert_datetime_for_query(
1110
-            'DTT_EVT_start',
1111
-            $this_year_r . '-' . $this_month_r . '-' . $days_this_month . ' 23:59:59',
1112
-            'Y-m-d H:i:s',
1113
-            'UTC'
1114
-        );
1115
-        $where           = [
1116
-            'Datetime.DTT_EVT_start' => ['BETWEEN', [$start, $end]],
1117
-        ];
1118
-        return EEM_Event::instance()->count([$where, 'caps' => 'read_admin'], 'EVT_ID', true);
1119
-    }
1120
-
1121
-
1122
-    /** DEFAULT TICKETS STUFF **/
1123
-
1124
-    /**
1125
-     * Output default tickets list table view.
1126
-     *
1127
-     * @throws EE_Error
1128
-     */
1129
-    public function _tickets_overview_list_table()
1130
-    {
1131
-        if (
1132
-            $this->admin_config->useAdvancedEditor()
1133
-            && $this->feature->allowed('use_default_ticket_manager')
1134
-        ) {
1135
-            // check if the new EDTR reg options meta box is being used, and if so, don't load the legacy version
1136
-            $this->_template_args['admin_page_content'] = EEH_Template::display_template(
1137
-                EVENTS_CAF_TEMPLATE_PATH . 'default_tickets_moved_notice.template.php',
1138
-                [],
1139
-                true
1140
-            );
1141
-            $this->display_admin_page_with_no_sidebar();
1142
-        } else {
1143
-            $this->_search_btn_label = esc_html__('Tickets', 'event_espresso');
1144
-            $this->display_admin_list_table_page_with_no_sidebar();
1145
-        }
1146
-    }
1147
-
1148
-
1149
-    /**
1150
-     * @param int  $per_page
1151
-     * @param bool $count
1152
-     * @param bool $trashed
1153
-     * @return EE_Soft_Delete_Base_Class[]|int
1154
-     * @throws EE_Error
1155
-     * @throws ReflectionException
1156
-     */
1157
-    public function get_default_tickets(int $per_page = 10, bool $count = false, bool $trashed = false)
1158
-    {
1159
-        $orderby = $this->request->getRequestParam('orderby', 'TKT_name');
1160
-        $order   = $this->request->getRequestParam('order', 'ASC');
1161
-        switch ($orderby) {
1162
-            case 'TKT_name':
1163
-                $orderby = ['TKT_name' => $order];
1164
-                break;
1165
-            case 'TKT_price':
1166
-                $orderby = ['TKT_price' => $order];
1167
-                break;
1168
-            case 'TKT_uses':
1169
-                $orderby = ['TKT_uses' => $order];
1170
-                break;
1171
-            case 'TKT_min':
1172
-                $orderby = ['TKT_min' => $order];
1173
-                break;
1174
-            case 'TKT_max':
1175
-                $orderby = ['TKT_max' => $order];
1176
-                break;
1177
-            case 'TKT_qty':
1178
-                $orderby = ['TKT_qty' => $order];
1179
-                break;
1180
-        }
1181
-
1182
-        $current_page = $this->request->getRequestParam('paged', 1, 'int');
1183
-        $per_page     = $this->request->getRequestParam('perpage', $per_page, 'int');
1184
-        $offset       = ($current_page - 1) * $per_page;
1185
-
1186
-        $where = [
1187
-            'TKT_is_default' => 1,
1188
-            'TKT_deleted'    => $trashed,
1189
-        ];
1190
-
1191
-        $search_term = $this->request->getRequestParam('s');
1192
-        if ($search_term) {
1193
-            $search_term = '%' . $search_term . '%';
1194
-            $where['OR'] = [
1195
-                'TKT_name'        => ['LIKE', $search_term],
1196
-                'TKT_description' => ['LIKE', $search_term],
1197
-            ];
1198
-        }
1199
-
1200
-        return $count
1201
-            ? EEM_Ticket::instance()->count_deleted_and_undeleted([$where])
1202
-            : EEM_Ticket::instance()->get_all_deleted_and_undeleted(
1203
-                [
1204
-                    $where,
1205
-                    'order_by' => $orderby,
1206
-                    'limit'    => [$offset, $per_page],
1207
-                    'group_by' => 'TKT_ID',
1208
-                ]
1209
-            );
1210
-    }
1211
-
1212
-
1213
-    /**
1214
-     * @param bool $trash
1215
-     * @throws EE_Error
1216
-     * @throws InvalidArgumentException
1217
-     * @throws InvalidDataTypeException
1218
-     * @throws InvalidInterfaceException
1219
-     * @throws ReflectionException
1220
-     */
1221
-    protected function _trash_or_restore_ticket(bool $trash = false)
1222
-    {
1223
-        $success = 1;
1224
-        $TKT     = EEM_Ticket::instance();
1225
-        // checkboxes?
1226
-        $checkboxes = $this->request->getRequestParam('checkbox', [], 'int', true);
1227
-        if (! empty($checkboxes)) {
1228
-            // if array has more than one element then success message should be plural
1229
-            $success = count($checkboxes) > 1 ? 2 : 1;
1230
-            // cycle thru the boxes
1231
-            foreach ($checkboxes as $TKT_ID => $value) {
1232
-                if ($trash) {
1233
-                    if (! $TKT->delete_by_ID($TKT_ID)) {
1234
-                        $success = 0;
1235
-                    }
1236
-                } elseif (! $TKT->restore_by_ID($TKT_ID)) {
1237
-                    $success = 0;
1238
-                }
1239
-            }
1240
-        } else {
1241
-            // grab single id and trash
1242
-            $TKT_ID = $this->request->getRequestParam('TKT_ID', 0, 'int');
1243
-            if ($trash) {
1244
-                if (! $TKT->delete_by_ID($TKT_ID)) {
1245
-                    $success = 0;
1246
-                }
1247
-            } elseif (! $TKT->restore_by_ID($TKT_ID)) {
1248
-                $success = 0;
1249
-            }
1250
-        }
1251
-        $action_desc = $trash ? 'moved to the trash' : 'restored';
1252
-        $query_args  = [
1253
-            'action' => 'ticket_list_table',
1254
-            'status' => $trash ? '' : 'trashed',
1255
-        ];
1256
-        $this->_redirect_after_action($success, esc_html__('Tickets', 'event_espresso'), $action_desc, $query_args);
1257
-    }
1258
-
1259
-
1260
-    /**
1261
-     * Handles trashing default ticket.
1262
-     *
1263
-     * @throws EE_Error
1264
-     * @throws ReflectionException
1265
-     */
1266
-    protected function _delete_ticket()
1267
-    {
1268
-        $success = 1;
1269
-        // checkboxes?
1270
-        $checkboxes = $this->request->getRequestParam('checkbox', [], 'int', true);
1271
-        if (! empty($checkboxes)) {
1272
-            // if array has more than one element then success message should be plural
1273
-            $success = count($checkboxes) > 1 ? 2 : 1;
1274
-            // cycle thru the boxes
1275
-            foreach ($checkboxes as $TKT_ID => $value) {
1276
-                // delete
1277
-                if (! $this->_delete_the_ticket($TKT_ID)) {
1278
-                    $success = 0;
1279
-                }
1280
-            }
1281
-        } else {
1282
-            // grab single id and trash
1283
-            $TKT_ID = $this->request->getRequestParam('TKT_ID', 0, 'int');
1284
-            if (! $this->_delete_the_ticket($TKT_ID)) {
1285
-                $success = 0;
1286
-            }
1287
-        }
1288
-        $action_desc = 'deleted';
1289
-        $query_args  = [
1290
-            'action' => 'ticket_list_table',
1291
-            'status' => 'trashed',
1292
-        ];
1293
-        // fail safe.  If the default ticket count === 1 then we need to redirect to event overview.
1294
-        if (
1295
-            EEM_Ticket::instance()->count_deleted_and_undeleted(
1296
-                [['TKT_is_default' => 1]],
1297
-                'TKT_ID',
1298
-                true
1299
-            )
1300
-        ) {
1301
-            $query_args = [];
1302
-        }
1303
-        $this->_redirect_after_action($success, esc_html__('Tickets', 'event_espresso'), $action_desc, $query_args);
1304
-    }
1305
-
1306
-
1307
-    /**
1308
-     * @param int $TKT_ID
1309
-     * @return bool|int
1310
-     * @throws EE_Error
1311
-     * @throws ReflectionException
1312
-     */
1313
-    protected function _delete_the_ticket(int $TKT_ID)
1314
-    {
1315
-        $ticket = EEM_Ticket::instance()->get_one_by_ID($TKT_ID);
1316
-        if (! $ticket instanceof EE_Ticket) {
1317
-            return false;
1318
-        }
1319
-        $ticket->_remove_relations('Datetime');
1320
-        // delete all related prices first
1321
-        $ticket->delete_related_permanently('Price');
1322
-        return $ticket->delete_permanently();
1323
-    }
392
+		}
393
+		if (EE_Registry::instance()->CAP->current_user_can('ee_read_global_messages', 'view_filtered_messages')) {
394
+			EE_Registry::instance()->load_helper('MSG_Template');
395
+			$action_links[] = EEH_MSG_Template::get_message_action_link(
396
+				'see_notifications_for',
397
+				null,
398
+				['EVT_ID' => $event->ID()]
399
+			);
400
+		}
401
+		return $action_links;
402
+	}
403
+
404
+
405
+	/**
406
+	 * @param $items
407
+	 * @return mixed
408
+	 */
409
+	public function additional_legend_items($items)
410
+	{
411
+		if (
412
+			EE_Registry::instance()->CAP->current_user_can(
413
+				'ee_read_registrations',
414
+				'espresso_registrations_reports'
415
+			)
416
+		) {
417
+			$items['reports'] = [
418
+				'class' => 'dashicons dashicons-chart-bar',
419
+				'desc'  => esc_html__('Event Reports', 'event_espresso'),
420
+			];
421
+		}
422
+		if (EE_Registry::instance()->CAP->current_user_can('ee_read_global_messages', 'view_filtered_messages')) {
423
+			$related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
424
+			// $related_for_icon can sometimes be a string so 'css_class' would be an illegal offset
425
+			// (can only use numeric offsets when treating strings as arrays)
426
+			if (is_array($related_for_icon) && isset($related_for_icon['css_class'], $related_for_icon['label'])) {
427
+				$items['view_related_messages'] = [
428
+					'class' => $related_for_icon['css_class'],
429
+					'desc'  => $related_for_icon['label'],
430
+				];
431
+			}
432
+		}
433
+		return $items;
434
+	}
435
+
436
+
437
+	/**
438
+	 * This is the callback method for the duplicate event route
439
+	 * Method looks for 'EVT_ID' in the request and retrieves that event and its details and duplicates them
440
+	 * into a new event.  We add a hook so that any plugins that add extra event details can hook into this
441
+	 * action.  Note that the dupe will have **DUPLICATE** as its title and slug.
442
+	 * After duplication the redirect is to the new event edit page.
443
+	 *
444
+	 * @return void
445
+	 * @throws EE_Error If EE_Event is not available with given ID
446
+	 * @throws ReflectionException
447
+	 * @access protected
448
+	 */
449
+	protected function _duplicate_event()
450
+	{
451
+		// first make sure the ID for the event is in the request.
452
+		//  If it isn't then we need to bail and redirect back to overview list table (cause how did we get here?)
453
+		$EVT_ID = $this->request->getRequestParam('EVT_ID', 0, 'int');
454
+		if (! $EVT_ID) {
455
+			EE_Error::add_error(
456
+				esc_html__(
457
+					'In order to duplicate an event an Event ID is required.  None was given.',
458
+					'event_espresso'
459
+				),
460
+				__FILE__,
461
+				__FUNCTION__,
462
+				__LINE__
463
+			);
464
+			$this->_redirect_after_action(false, '', '', [], true);
465
+			return;
466
+		}
467
+		// k we've got EVT_ID so let's use that to get the event we'll duplicate
468
+		$orig_event = EEM_Event::instance()->get_one_by_ID($EVT_ID);
469
+		if (! $orig_event instanceof EE_Event) {
470
+			throw new EE_Error(
471
+				sprintf(
472
+					esc_html__('An EE_Event object could not be retrieved for the given ID (%s)', 'event_espresso'),
473
+					$EVT_ID
474
+				)
475
+			);
476
+		}
477
+		// k now let's clone the $orig_event before getting relations
478
+		$new_event = clone $orig_event;
479
+		// original datetimes
480
+		$orig_datetimes = $orig_event->get_many_related('Datetime');
481
+		// other original relations
482
+		$orig_ven = $orig_event->get_many_related('Venue');
483
+		// reset the ID and modify other details to make it clear this is a dupe
484
+		$new_event->set('EVT_ID', 0);
485
+		$new_name = $new_event->name() . ' ' . esc_html__('**DUPLICATE**', 'event_espresso');
486
+		$new_event->set('EVT_name', $new_name);
487
+		$new_event->set(
488
+			'EVT_slug',
489
+			wp_unique_post_slug(
490
+				sanitize_title($orig_event->name()),
491
+				0,
492
+				'publish',
493
+				EspressoPostType::EVENTS,
494
+				0
495
+			)
496
+		);
497
+		$new_event->set('status', 'draft');
498
+		// duplicate discussion settings
499
+		$new_event->set('comment_status', $orig_event->get('comment_status'));
500
+		$new_event->set('ping_status', $orig_event->get('ping_status'));
501
+		// save the new event
502
+		$new_event->save();
503
+		// venues
504
+		foreach ($orig_ven as $ven) {
505
+			$new_event->_add_relation_to($ven, 'Venue');
506
+		}
507
+		$new_event->save();
508
+		// now we need to get the question group relations and handle that
509
+		// first primary question groups
510
+		$orig_primary_qgs = $orig_event->get_many_related(
511
+			'Question_Group',
512
+			[['Event_Question_Group.EQG_primary' => true]]
513
+		);
514
+		if (! empty($orig_primary_qgs)) {
515
+			foreach ($orig_primary_qgs as $obj) {
516
+				if ($obj instanceof EE_Question_Group) {
517
+					$new_event->_add_relation_to($obj, 'Question_Group', ['EQG_primary' => true]);
518
+				}
519
+			}
520
+		}
521
+		// next additional attendee question groups
522
+		$orig_additional_qgs = $orig_event->get_many_related(
523
+			'Question_Group',
524
+			[['Event_Question_Group.EQG_additional' => true]]
525
+		);
526
+		if (! empty($orig_additional_qgs)) {
527
+			foreach ($orig_additional_qgs as $obj) {
528
+				if ($obj instanceof EE_Question_Group) {
529
+					$new_event->_add_relation_to($obj, 'Question_Group', ['EQG_additional' => true]);
530
+				}
531
+			}
532
+		}
533
+
534
+		$new_event->save();
535
+
536
+		// k now that we have the new event saved we can loop through the datetimes and start adding relations.
537
+		$cloned_tickets = [];
538
+		foreach ($orig_datetimes as $orig_dtt) {
539
+			if (! $orig_dtt instanceof EE_Datetime) {
540
+				continue;
541
+			}
542
+			$new_dtt      = clone $orig_dtt;
543
+			$orig_tickets = $orig_dtt->tickets();
544
+			// save new dtt then add to event
545
+			$new_dtt->set('DTT_ID', 0);
546
+			$new_dtt->set('DTT_sold', 0);
547
+			$new_dtt->set_reserved(0);
548
+			$new_dtt->save();
549
+			$new_event->_add_relation_to($new_dtt, 'Datetime');
550
+			$new_event->save();
551
+			// now let's get the ticket relations setup.
552
+			foreach ((array) $orig_tickets as $orig_ticket) {
553
+				// it's possible a datetime will have no tickets so let's verify we HAVE a ticket first.
554
+				if (! $orig_ticket instanceof EE_Ticket) {
555
+					continue;
556
+				}
557
+				// is this ticket archived?  If it is then let's skip
558
+				if ($orig_ticket->get('TKT_deleted')) {
559
+					continue;
560
+				}
561
+				// does this original ticket already exist in the clone_tickets cache?
562
+				//  If so we'll just use the new ticket from it.
563
+				if (isset($cloned_tickets[ $orig_ticket->ID() ])) {
564
+					$new_ticket = $cloned_tickets[ $orig_ticket->ID() ];
565
+				} else {
566
+					$new_ticket = clone $orig_ticket;
567
+					// get relations on the $orig_ticket that we need to set up.
568
+					$orig_prices = $orig_ticket->prices();
569
+					$new_ticket->set('TKT_ID', 0);
570
+					$new_ticket->set('TKT_sold', 0);
571
+					$new_ticket->set('TKT_reserved', 0);
572
+					// make sure new ticket has ID.
573
+					$new_ticket->save();
574
+					// price relations on new ticket need to be setup.
575
+					foreach ($orig_prices as $orig_price) {
576
+						// don't clone default prices, just add a relation
577
+						if ($orig_price->is_default()) {
578
+							$new_ticket->_add_relation_to($orig_price, 'Price');
579
+							$new_ticket->save();
580
+							continue;
581
+						}
582
+						$new_price = clone $orig_price;
583
+						$new_price->set('PRC_ID', 0);
584
+						$new_price->save();
585
+						$new_ticket->_add_relation_to($new_price, 'Price');
586
+					}
587
+					$new_ticket->save();
588
+
589
+					do_action(
590
+						'AHEE__Extend_Events_Admin_Page___duplicate_event__duplicate_ticket__after',
591
+						$orig_ticket,
592
+						$new_ticket,
593
+						$orig_prices,
594
+						$orig_event,
595
+						$orig_dtt,
596
+						$new_dtt
597
+					);
598
+					$cloned_tickets[ $orig_ticket->ID() ] = $new_ticket;
599
+				}
600
+				// k now we can add the new ticket as a relation to the new datetime
601
+				// and make sure it's added to our cached $cloned_tickets array
602
+				// for use with later datetimes that have the same ticket.
603
+				$new_dtt->_add_relation_to($new_ticket, 'Ticket');
604
+			}
605
+			$new_dtt->save();
606
+		}
607
+		// clone taxonomy information
608
+		$taxonomies_to_clone_with = apply_filters(
609
+			'FHEE__Extend_Events_Admin_Page___duplicate_event__taxonomies_to_clone',
610
+			['espresso_event_categories', 'espresso_event_type', 'post_tag']
611
+		);
612
+		// get terms for original event (notice)
613
+		$orig_terms = wp_get_object_terms($orig_event->ID(), $taxonomies_to_clone_with);
614
+		// loop through terms and add them to new event.
615
+		foreach ($orig_terms as $term) {
616
+			wp_set_object_terms($new_event->ID(), $term->term_id, $term->taxonomy, true);
617
+		}
618
+
619
+		// duplicate other core WP_Post items for this event.
620
+		// post thumbnail (feature image).
621
+		$feature_image_id = get_post_thumbnail_id($orig_event->ID());
622
+		if ($feature_image_id) {
623
+			update_post_meta($new_event->ID(), '_thumbnail_id', $feature_image_id);
624
+		}
625
+
626
+		// duplicate page_template setting
627
+		$page_template = get_post_meta($orig_event->ID(), '_wp_page_template', true);
628
+		if ($page_template) {
629
+			update_post_meta($new_event->ID(), '_wp_page_template', $page_template);
630
+		}
631
+
632
+		do_action('AHEE__Extend_Events_Admin_Page___duplicate_event__after', $new_event, $orig_event);
633
+		// now let's redirect to the edit page for this duplicated event if we have a new event id.
634
+		if ($new_event->ID()) {
635
+			$redirect_args = [
636
+				'post'   => $new_event->ID(),
637
+				'action' => 'edit',
638
+			];
639
+			EE_Error::add_success(
640
+				esc_html__(
641
+					'Event successfully duplicated.  Please review the details below and make any necessary edits',
642
+					'event_espresso'
643
+				)
644
+			);
645
+		} else {
646
+			$redirect_args = [
647
+				'action' => 'default',
648
+			];
649
+			EE_Error::add_error(
650
+				esc_html__('Not able to duplicate event.  Something went wrong.', 'event_espresso'),
651
+				__FILE__,
652
+				__FUNCTION__,
653
+				__LINE__
654
+			);
655
+		}
656
+		$this->_redirect_after_action(false, '', '', $redirect_args, true);
657
+	}
658
+
659
+
660
+	/**
661
+	 * Generates output for the import page.
662
+	 *
663
+	 * @throws EE_Error
664
+	 */
665
+	protected function _import_page()
666
+	{
667
+		$title = esc_html__('Import', 'event_espresso');
668
+		$intro = esc_html__(
669
+			'If you have a previously exported Event Espresso 4 information in a Comma Separated Value (CSV) file format, you can upload the file here: ',
670
+			'event_espresso'
671
+		);
672
+
673
+		$form_url = EVENTS_ADMIN_URL;
674
+		$action   = 'import_events';
675
+		$type     = 'csv';
676
+
677
+		$this->_template_args['form'] = EE_Import::instance()->upload_form(
678
+			$title,
679
+			$intro,
680
+			$form_url,
681
+			$action,
682
+			$type
683
+		);
684
+
685
+		$this->_template_args['sample_file_link']   = EE_Admin_Page::add_query_args_and_nonce(
686
+			['action' => 'sample_export_file'],
687
+			$this->_admin_base_url
688
+		);
689
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
690
+			EVENTS_CAF_TEMPLATE_PATH . 'import_page.template.php',
691
+			$this->_template_args,
692
+			true
693
+		);
694
+		$this->display_admin_page_with_sidebar();
695
+	}
696
+
697
+
698
+	/**
699
+	 * _import_events
700
+	 * This handles displaying the screen and running imports for importing events.
701
+	 *
702
+	 * @return void
703
+	 * @throws EE_Error
704
+	 */
705
+	protected function _import_events()
706
+	{
707
+		require_once(EE_CLASSES . 'EE_Import.class.php');
708
+		$success = EE_Import::instance()->import();
709
+		$this->_redirect_after_action(
710
+			$success,
711
+			esc_html__('Import File', 'event_espresso'),
712
+			'ran',
713
+			['action' => 'import_page'],
714
+			true
715
+		);
716
+	}
717
+
718
+
719
+	/**
720
+	 * _events_export
721
+	 * Will export all (or just the given event) to a Excel compatible file.
722
+	 *
723
+	 * @access protected
724
+	 * @return void
725
+	 */
726
+	protected function _events_export()
727
+	{
728
+		$EVT_ID = $this->request->getRequestParam('EVT_ID', 0, 'int');
729
+		$EVT_ID = $this->request->getRequestParam('EVT_IDs', $EVT_ID, 'int');
730
+		$this->request->mergeRequestParams(
731
+			[
732
+				'export' => 'report',
733
+				'action' => 'all_event_data',
734
+				'EVT_ID' => $EVT_ID,
735
+			]
736
+		);
737
+		if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
738
+			require_once(EE_CLASSES . 'EE_Export.class.php');
739
+			$EE_Export = EE_Export::instance($this->request->requestParams());
740
+			$EE_Export->export();
741
+		}
742
+	}
743
+
744
+
745
+	/**
746
+	 * handle category exports()
747
+	 *
748
+	 * @return void
749
+	 */
750
+	protected function _categories_export()
751
+	{
752
+		$EVT_ID = $this->request->getRequestParam('EVT_CAT_ID', 0, 'int');
753
+		$this->request->mergeRequestParams(
754
+			[
755
+				'export' => 'report',
756
+				'action' => 'categories',
757
+				'EVT_ID' => $EVT_ID,
758
+			]
759
+		);
760
+		if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
761
+			require_once(EE_CLASSES . 'EE_Export.class.php');
762
+			$EE_Export = EE_Export::instance($this->request->requestParams());
763
+			$EE_Export->export();
764
+		}
765
+	}
766
+
767
+
768
+	/**
769
+	 * Creates a sample CSV file for importing
770
+	 */
771
+	protected function _sample_export_file()
772
+	{
773
+		$EE_Export = EE_Export::instance();
774
+		if ($EE_Export instanceof EE_Export) {
775
+			$EE_Export->export();
776
+		}
777
+	}
778
+
779
+
780
+	/*************        Template Settings        *************/
781
+	/**
782
+	 * Generates template settings page output
783
+	 *
784
+	 * @throws DomainException
785
+	 * @throws EE_Error
786
+	 * @throws InvalidArgumentException
787
+	 * @throws InvalidDataTypeException
788
+	 * @throws InvalidInterfaceException
789
+	 */
790
+	protected function _template_settings()
791
+	{
792
+		new TemplateCacheAdmin(EE_Registry::instance()->CFG->template_settings, $this->request);
793
+		$this->_template_args['values'] = $this->_yes_no_values;
794
+		/**
795
+		 * Note leaving this filter in for backward compatibility this was moved in 4.6.x
796
+		 * from General_Settings_Admin_Page to here.
797
+		 */
798
+		$this->_template_args = apply_filters(
799
+			'FHEE__General_Settings_Admin_Page__template_settings__template_args',
800
+			$this->_template_args
801
+		);
802
+		$this->_set_add_edit_form_tags('update_template_settings');
803
+		$this->_set_publish_post_box_vars();
804
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
805
+			EVENTS_CAF_TEMPLATE_PATH . 'template_settings.template.php',
806
+			$this->_template_args,
807
+			true
808
+		);
809
+		$this->display_admin_page_with_sidebar();
810
+	}
811
+
812
+
813
+	/**
814
+	 * Handler for updating template settings.
815
+	 *
816
+	 * @throws EE_Error
817
+	 */
818
+	protected function _update_template_settings()
819
+	{
820
+		new TemplateCacheAdmin(EE_Registry::instance()->CFG->template_settings, $this->request);
821
+		/**
822
+		 * Note leaving this filter in for backward compatibility this was moved in 4.6.x
823
+		 * from General_Settings_Admin_Page to here.
824
+		 */
825
+		EE_Registry::instance()->CFG->template_settings = apply_filters(
826
+			'FHEE__General_Settings_Admin_Page__update_template_settings__data',
827
+			EE_Registry::instance()->CFG->template_settings,
828
+			$this->request->requestParams()
829
+		);
830
+		// update custom post type slugs and detect if we need to flush rewrite rules
831
+		$old_slug = EE_Registry::instance()->CFG->core->event_cpt_slug;
832
+
833
+		$event_cpt_slug = $this->request->getRequestParam('event_cpt_slug');
834
+
835
+		EE_Registry::instance()->CFG->core->event_cpt_slug = $event_cpt_slug
836
+			? EEH_URL::slugify($event_cpt_slug, 'events')
837
+			: EE_Registry::instance()->CFG->core->event_cpt_slug;
838
+
839
+		$what    = esc_html__('Template Settings', 'event_espresso');
840
+		$success = $this->_update_espresso_configuration(
841
+			$what,
842
+			EE_Registry::instance()->CFG->template_settings,
843
+			__FILE__,
844
+			__FUNCTION__,
845
+			__LINE__
846
+		);
847
+		if (EE_Registry::instance()->CFG->core->event_cpt_slug !== $old_slug) {
848
+			/** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
849
+			$rewrite_rules = LoaderFactory::getLoader()->getShared(
850
+				'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
851
+			);
852
+			$rewrite_rules->flush();
853
+		}
854
+		do_action(
855
+			'AHEE__General_Settings_Admin_Page__update_template_settings__after_update',
856
+			EE_Registry::instance()->CFG->template_settings,
857
+			$this->request->requestParams(),
858
+			$success
859
+		);
860
+		$this->_redirect_after_action($success, $what, 'updated', ['action' => 'template_settings']);
861
+	}
862
+
863
+
864
+	/**
865
+	 * _premium_event_editor_meta_boxes
866
+	 * add all metaboxes related to the event_editor
867
+	 *
868
+	 * @access protected
869
+	 * @return void
870
+	 * @throws EE_Error
871
+	 * @throws ReflectionException
872
+	 */
873
+	protected function _premium_event_editor_meta_boxes()
874
+	{
875
+		$this->verify_cpt_object();
876
+		// check if the new EDTR reg options meta box is being used, and if so, don't load the legacy version
877
+		if (
878
+			! $this->admin_config->useAdvancedEditor()
879
+			|| ! $this->feature->allowed('use_reg_options_meta_box')
880
+		) {
881
+			$this->addMetaBox(
882
+				'espresso_event_editor_event_options',
883
+				esc_html__('Event Registration Options', 'event_espresso'),
884
+				[$this, 'registration_options_meta_box'],
885
+				$this->page_slug,
886
+				'side',
887
+				'core'
888
+			);
889
+		}
890
+	}
891
+
892
+
893
+	/**
894
+	 * override caf metabox
895
+	 *
896
+	 * @return void
897
+	 * @throws EE_Error
898
+	 * @throws ReflectionException
899
+	 */
900
+	public function registration_options_meta_box()
901
+	{
902
+		$yes_no_values = [
903
+			['id' => true, 'text' => esc_html__('Yes', 'event_espresso')],
904
+			['id' => false, 'text' => esc_html__('No', 'event_espresso')],
905
+		];
906
+
907
+		$default_reg_status_values = EEM_Registration::reg_status_array(
908
+			[
909
+				RegStatus::CANCELLED,
910
+				RegStatus::DECLINED,
911
+				RegStatus::INCOMPLETE,
912
+				RegStatus::WAIT_LIST,
913
+			],
914
+			true
915
+		);
916
+
917
+		$template_args['active_status']    = $this->_cpt_model_obj->pretty_active_status(false);
918
+		$template_args['_event']           = $this->_cpt_model_obj;
919
+		$template_args['additional_limit'] = $this->_cpt_model_obj->additional_limit();
920
+
921
+		$template_args['default_registration_status']     = EEH_Form_Fields::select_input(
922
+			'default_reg_status',
923
+			$default_reg_status_values,
924
+			$this->_cpt_model_obj->default_registration_status(),
925
+			'',
926
+			'ee-input-width--reg',
927
+			false
928
+		);
929
+		$template_args['display_description']             = EEH_Form_Fields::select_input(
930
+			'display_desc',
931
+			$yes_no_values,
932
+			$this->_cpt_model_obj->display_description()
933
+		);
934
+		$template_args['display_ticket_selector']         = EEH_Form_Fields::select_input(
935
+			'display_ticket_selector',
936
+			$yes_no_values,
937
+			$this->_cpt_model_obj->display_ticket_selector(),
938
+			'',
939
+			'ee-input-width--small',
940
+			false
941
+		);
942
+		$template_args['EVT_default_registration_status'] = EEH_Form_Fields::select_input(
943
+			'EVT_default_registration_status',
944
+			$default_reg_status_values,
945
+			$this->_cpt_model_obj->default_registration_status(),
946
+			'',
947
+			'ee-input-width--reg',
948
+			false
949
+		);
950
+		$template_args['additional_registration_options'] = apply_filters(
951
+			'FHEE__Events_Admin_Page__registration_options_meta_box__additional_registration_options',
952
+			'',
953
+			$template_args,
954
+			$yes_no_values,
955
+			$default_reg_status_values
956
+		);
957
+		EEH_Template::display_template(
958
+			EVENTS_CAF_TEMPLATE_PATH . 'event_registration_options.template.php',
959
+			$template_args
960
+		);
961
+	}
962
+
963
+
964
+
965
+	/**
966
+	 * wp_list_table_mods for caf
967
+	 * ============================
968
+	 */
969
+
970
+
971
+	/**
972
+	 * espresso_event_months_dropdown
973
+	 *
974
+	 * @deprecatd 5.0.0.p
975
+	 * @access public
976
+	 * @return string                dropdown listing month/year selections for events.
977
+	 * @throws EE_Error
978
+	 */
979
+	public function espresso_event_months_dropdown(): string
980
+	{
981
+		// what we need to do is get all PRIMARY datetimes for all events to filter on.
982
+		// Note we need to include any other filters that are set!
983
+		return EEH_Form_Fields::generate_event_months_dropdown(
984
+			$this->request->getRequestParam('month_range', ''),
985
+			$this->request->getRequestParam('status', ''),
986
+			$this->request->getRequestParam('EVT_CAT', 0, 'int'),
987
+			$this->request->getRequestParam('active_status', '')
988
+		);
989
+	}
990
+
991
+
992
+	/**
993
+	 * returns a list of "active" statuses on the event
994
+	 *
995
+	 * @deprecatd 5.0.0.p
996
+	 * @param string $current_value whatever the current active status is
997
+	 * @return string
998
+	 */
999
+	public function active_status_dropdown(string $current_value = ''): string
1000
+	{
1001
+		$select_name = 'active_status';
1002
+		$values      = [
1003
+			'none'     => esc_html__('Show Active/Inactive', 'event_espresso'),
1004
+			'active'   => esc_html__('Active', 'event_espresso'),
1005
+			'upcoming' => esc_html__('Upcoming', 'event_espresso'),
1006
+			'expired'  => esc_html__('Expired', 'event_espresso'),
1007
+			'inactive' => esc_html__('Inactive', 'event_espresso'),
1008
+		];
1009
+
1010
+		return EEH_Form_Fields::select_input($select_name, $values, $current_value);
1011
+	}
1012
+
1013
+
1014
+	/**
1015
+	 * returns a list of "venues"
1016
+	 *
1017
+	 * @deprecatd 5.0.0.p
1018
+	 * @param string $current_value whatever the current active status is
1019
+	 * @return string
1020
+	 * @throws EE_Error
1021
+	 * @throws ReflectionException
1022
+	 */
1023
+	protected function venuesDropdown(string $current_value = ''): string
1024
+	{
1025
+		$values = ['' => esc_html__('All Venues', 'event_espresso')];
1026
+		// populate the list of venues.
1027
+		$venues = EEM_Venue::instance()->get_all(['order_by' => ['VNU_name' => 'ASC']]);
1028
+
1029
+		foreach ($venues as $venue) {
1030
+			$values[ $venue->ID() ] = $venue->name();
1031
+		}
1032
+
1033
+		return EEH_Form_Fields::select_input('venue', $values, $current_value);
1034
+	}
1035
+
1036
+
1037
+	/**
1038
+	 * output a dropdown of the categories for the category filter on the event admin list table
1039
+	 *
1040
+	 * @deprecatd 5.0.0.p
1041
+	 * @access  public
1042
+	 * @return string html
1043
+	 * @throws EE_Error
1044
+	 * @throws ReflectionException
1045
+	 */
1046
+	public function category_dropdown(): string
1047
+	{
1048
+		return EEH_Form_Fields::generate_event_category_dropdown(
1049
+			$this->request->getRequestParam('EVT_CAT', -1, 'int')
1050
+		);
1051
+	}
1052
+
1053
+
1054
+	/**
1055
+	 * get total number of events today
1056
+	 *
1057
+	 * @access public
1058
+	 * @return int
1059
+	 * @throws EE_Error
1060
+	 * @throws InvalidArgumentException
1061
+	 * @throws InvalidDataTypeException
1062
+	 * @throws InvalidInterfaceException
1063
+	 * @throws ReflectionException
1064
+	 */
1065
+	public function total_events_today(): int
1066
+	{
1067
+		$start = EEM_Datetime::instance()->convert_datetime_for_query(
1068
+			'DTT_EVT_start',
1069
+			date('Y-m-d') . ' 00:00:00',
1070
+			'Y-m-d H:i:s',
1071
+			'UTC'
1072
+		);
1073
+		$end   = EEM_Datetime::instance()->convert_datetime_for_query(
1074
+			'DTT_EVT_start',
1075
+			date('Y-m-d') . ' 23:59:59',
1076
+			'Y-m-d H:i:s',
1077
+			'UTC'
1078
+		);
1079
+		$where = [
1080
+			'Datetime.DTT_EVT_start' => ['BETWEEN', [$start, $end]],
1081
+		];
1082
+		return EEM_Event::instance()->count([$where, 'caps' => 'read_admin'], 'EVT_ID', true);
1083
+	}
1084
+
1085
+
1086
+	/**
1087
+	 * get total number of events this month
1088
+	 *
1089
+	 * @access public
1090
+	 * @return int
1091
+	 * @throws EE_Error
1092
+	 * @throws InvalidArgumentException
1093
+	 * @throws InvalidDataTypeException
1094
+	 * @throws InvalidInterfaceException
1095
+	 * @throws ReflectionException
1096
+	 */
1097
+	public function total_events_this_month(): int
1098
+	{
1099
+		// Dates
1100
+		$this_year_r     = date('Y');
1101
+		$this_month_r    = date('m');
1102
+		$days_this_month = date('t');
1103
+		$start           = EEM_Datetime::instance()->convert_datetime_for_query(
1104
+			'DTT_EVT_start',
1105
+			$this_year_r . '-' . $this_month_r . '-01 00:00:00',
1106
+			'Y-m-d H:i:s',
1107
+			'UTC'
1108
+		);
1109
+		$end             = EEM_Datetime::instance()->convert_datetime_for_query(
1110
+			'DTT_EVT_start',
1111
+			$this_year_r . '-' . $this_month_r . '-' . $days_this_month . ' 23:59:59',
1112
+			'Y-m-d H:i:s',
1113
+			'UTC'
1114
+		);
1115
+		$where           = [
1116
+			'Datetime.DTT_EVT_start' => ['BETWEEN', [$start, $end]],
1117
+		];
1118
+		return EEM_Event::instance()->count([$where, 'caps' => 'read_admin'], 'EVT_ID', true);
1119
+	}
1120
+
1121
+
1122
+	/** DEFAULT TICKETS STUFF **/
1123
+
1124
+	/**
1125
+	 * Output default tickets list table view.
1126
+	 *
1127
+	 * @throws EE_Error
1128
+	 */
1129
+	public function _tickets_overview_list_table()
1130
+	{
1131
+		if (
1132
+			$this->admin_config->useAdvancedEditor()
1133
+			&& $this->feature->allowed('use_default_ticket_manager')
1134
+		) {
1135
+			// check if the new EDTR reg options meta box is being used, and if so, don't load the legacy version
1136
+			$this->_template_args['admin_page_content'] = EEH_Template::display_template(
1137
+				EVENTS_CAF_TEMPLATE_PATH . 'default_tickets_moved_notice.template.php',
1138
+				[],
1139
+				true
1140
+			);
1141
+			$this->display_admin_page_with_no_sidebar();
1142
+		} else {
1143
+			$this->_search_btn_label = esc_html__('Tickets', 'event_espresso');
1144
+			$this->display_admin_list_table_page_with_no_sidebar();
1145
+		}
1146
+	}
1147
+
1148
+
1149
+	/**
1150
+	 * @param int  $per_page
1151
+	 * @param bool $count
1152
+	 * @param bool $trashed
1153
+	 * @return EE_Soft_Delete_Base_Class[]|int
1154
+	 * @throws EE_Error
1155
+	 * @throws ReflectionException
1156
+	 */
1157
+	public function get_default_tickets(int $per_page = 10, bool $count = false, bool $trashed = false)
1158
+	{
1159
+		$orderby = $this->request->getRequestParam('orderby', 'TKT_name');
1160
+		$order   = $this->request->getRequestParam('order', 'ASC');
1161
+		switch ($orderby) {
1162
+			case 'TKT_name':
1163
+				$orderby = ['TKT_name' => $order];
1164
+				break;
1165
+			case 'TKT_price':
1166
+				$orderby = ['TKT_price' => $order];
1167
+				break;
1168
+			case 'TKT_uses':
1169
+				$orderby = ['TKT_uses' => $order];
1170
+				break;
1171
+			case 'TKT_min':
1172
+				$orderby = ['TKT_min' => $order];
1173
+				break;
1174
+			case 'TKT_max':
1175
+				$orderby = ['TKT_max' => $order];
1176
+				break;
1177
+			case 'TKT_qty':
1178
+				$orderby = ['TKT_qty' => $order];
1179
+				break;
1180
+		}
1181
+
1182
+		$current_page = $this->request->getRequestParam('paged', 1, 'int');
1183
+		$per_page     = $this->request->getRequestParam('perpage', $per_page, 'int');
1184
+		$offset       = ($current_page - 1) * $per_page;
1185
+
1186
+		$where = [
1187
+			'TKT_is_default' => 1,
1188
+			'TKT_deleted'    => $trashed,
1189
+		];
1190
+
1191
+		$search_term = $this->request->getRequestParam('s');
1192
+		if ($search_term) {
1193
+			$search_term = '%' . $search_term . '%';
1194
+			$where['OR'] = [
1195
+				'TKT_name'        => ['LIKE', $search_term],
1196
+				'TKT_description' => ['LIKE', $search_term],
1197
+			];
1198
+		}
1199
+
1200
+		return $count
1201
+			? EEM_Ticket::instance()->count_deleted_and_undeleted([$where])
1202
+			: EEM_Ticket::instance()->get_all_deleted_and_undeleted(
1203
+				[
1204
+					$where,
1205
+					'order_by' => $orderby,
1206
+					'limit'    => [$offset, $per_page],
1207
+					'group_by' => 'TKT_ID',
1208
+				]
1209
+			);
1210
+	}
1211
+
1212
+
1213
+	/**
1214
+	 * @param bool $trash
1215
+	 * @throws EE_Error
1216
+	 * @throws InvalidArgumentException
1217
+	 * @throws InvalidDataTypeException
1218
+	 * @throws InvalidInterfaceException
1219
+	 * @throws ReflectionException
1220
+	 */
1221
+	protected function _trash_or_restore_ticket(bool $trash = false)
1222
+	{
1223
+		$success = 1;
1224
+		$TKT     = EEM_Ticket::instance();
1225
+		// checkboxes?
1226
+		$checkboxes = $this->request->getRequestParam('checkbox', [], 'int', true);
1227
+		if (! empty($checkboxes)) {
1228
+			// if array has more than one element then success message should be plural
1229
+			$success = count($checkboxes) > 1 ? 2 : 1;
1230
+			// cycle thru the boxes
1231
+			foreach ($checkboxes as $TKT_ID => $value) {
1232
+				if ($trash) {
1233
+					if (! $TKT->delete_by_ID($TKT_ID)) {
1234
+						$success = 0;
1235
+					}
1236
+				} elseif (! $TKT->restore_by_ID($TKT_ID)) {
1237
+					$success = 0;
1238
+				}
1239
+			}
1240
+		} else {
1241
+			// grab single id and trash
1242
+			$TKT_ID = $this->request->getRequestParam('TKT_ID', 0, 'int');
1243
+			if ($trash) {
1244
+				if (! $TKT->delete_by_ID($TKT_ID)) {
1245
+					$success = 0;
1246
+				}
1247
+			} elseif (! $TKT->restore_by_ID($TKT_ID)) {
1248
+				$success = 0;
1249
+			}
1250
+		}
1251
+		$action_desc = $trash ? 'moved to the trash' : 'restored';
1252
+		$query_args  = [
1253
+			'action' => 'ticket_list_table',
1254
+			'status' => $trash ? '' : 'trashed',
1255
+		];
1256
+		$this->_redirect_after_action($success, esc_html__('Tickets', 'event_espresso'), $action_desc, $query_args);
1257
+	}
1258
+
1259
+
1260
+	/**
1261
+	 * Handles trashing default ticket.
1262
+	 *
1263
+	 * @throws EE_Error
1264
+	 * @throws ReflectionException
1265
+	 */
1266
+	protected function _delete_ticket()
1267
+	{
1268
+		$success = 1;
1269
+		// checkboxes?
1270
+		$checkboxes = $this->request->getRequestParam('checkbox', [], 'int', true);
1271
+		if (! empty($checkboxes)) {
1272
+			// if array has more than one element then success message should be plural
1273
+			$success = count($checkboxes) > 1 ? 2 : 1;
1274
+			// cycle thru the boxes
1275
+			foreach ($checkboxes as $TKT_ID => $value) {
1276
+				// delete
1277
+				if (! $this->_delete_the_ticket($TKT_ID)) {
1278
+					$success = 0;
1279
+				}
1280
+			}
1281
+		} else {
1282
+			// grab single id and trash
1283
+			$TKT_ID = $this->request->getRequestParam('TKT_ID', 0, 'int');
1284
+			if (! $this->_delete_the_ticket($TKT_ID)) {
1285
+				$success = 0;
1286
+			}
1287
+		}
1288
+		$action_desc = 'deleted';
1289
+		$query_args  = [
1290
+			'action' => 'ticket_list_table',
1291
+			'status' => 'trashed',
1292
+		];
1293
+		// fail safe.  If the default ticket count === 1 then we need to redirect to event overview.
1294
+		if (
1295
+			EEM_Ticket::instance()->count_deleted_and_undeleted(
1296
+				[['TKT_is_default' => 1]],
1297
+				'TKT_ID',
1298
+				true
1299
+			)
1300
+		) {
1301
+			$query_args = [];
1302
+		}
1303
+		$this->_redirect_after_action($success, esc_html__('Tickets', 'event_espresso'), $action_desc, $query_args);
1304
+	}
1305
+
1306
+
1307
+	/**
1308
+	 * @param int $TKT_ID
1309
+	 * @return bool|int
1310
+	 * @throws EE_Error
1311
+	 * @throws ReflectionException
1312
+	 */
1313
+	protected function _delete_the_ticket(int $TKT_ID)
1314
+	{
1315
+		$ticket = EEM_Ticket::instance()->get_one_by_ID($TKT_ID);
1316
+		if (! $ticket instanceof EE_Ticket) {
1317
+			return false;
1318
+		}
1319
+		$ticket->_remove_relations('Datetime');
1320
+		// delete all related prices first
1321
+		$ticket->delete_related_permanently('Price');
1322
+		return $ticket->delete_permanently();
1323
+	}
1324 1324
 }
Please login to merge, or discard this patch.
admin/extend/events/espresso_events_Events_Hooks_Extend.class.php 1 patch
Indentation   +2313 added lines, -2313 removed lines patch added patch discarded remove patch
@@ -16,2331 +16,2331 @@
 block discarded – undo
16 16
  */
17 17
 class espresso_events_Events_Hooks_Extend extends EE_Admin_Hooks
18 18
 {
19
-    /**
20
-     * This property is just used to hold the status of whether an event is currently being
21
-     * created (true) or edited (false)
22
-     *
23
-     * @access protected
24
-     * @var bool
25
-     */
26
-    protected $_is_creating_event;
27
-
28
-    /**
29
-     * Used to contain the format strings for date and time that will be used for php date and
30
-     * time.
31
-     * Is set in the _set_hooks_properties() method.
32
-     *
33
-     * @var array
34
-     */
35
-    protected $_date_format_strings;
36
-
37
-    /**
38
-     * @var string $_date_time_format
39
-     */
40
-    protected $_date_time_format;
41
-
42
-
43
-    /**
44
-     * @throws InvalidArgumentException
45
-     * @throws InvalidInterfaceException
46
-     * @throws InvalidDataTypeException
47
-     */
48
-    protected function _set_hooks_properties()
49
-    {
50
-        $this->_name = 'events';
51
-        // capability check
52
-        if (
53
-            $this->_adminpage_obj->adminConfig()->useAdvancedEditor()
54
-            || ! EE_Registry::instance()->CAP->current_user_can(
55
-                'ee_read_default_prices',
56
-                'advanced_ticket_datetime_metabox'
57
-            )
58
-        ) {
59
-            $this->_metaboxes      = [];
60
-            $this->_scripts_styles = [];
61
-            return;
62
-        }
63
-        $this->_setup_metaboxes();
64
-        $this->_set_date_time_formats();
65
-        $this->_validate_format_strings();
66
-        $this->_set_scripts_styles();
67
-        add_filter(
68
-            'FHEE__Events_Admin_Page___insert_update_cpt_item__event_update_callbacks',
69
-            [$this, 'caf_updates']
70
-        );
71
-    }
72
-
73
-
74
-    /**
75
-     * @return void
76
-     */
77
-    protected function _setup_metaboxes()
78
-    {
79
-        // if we were going to add our own metaboxes we'd use the below.
80
-        $this->_metaboxes        = [
81
-            0 => [
82
-                'page_route' => ['edit', 'create_new'],
83
-                'func'       => [$this, 'pricing_metabox'],
84
-                'label'      => esc_html__('Event Tickets & Datetimes', 'event_espresso'),
85
-                'priority'   => 'high',
86
-                'context'    => 'normal',
87
-            ],
88
-        ];
89
-        $this->_remove_metaboxes = [
90
-            0 => [
91
-                'page_route' => ['edit', 'create_new'],
92
-                'id'         => 'espresso_event_editor_tickets',
93
-                'context'    => 'normal',
94
-            ],
95
-        ];
96
-    }
97
-
98
-
99
-    /**
100
-     * @return void
101
-     */
102
-    protected function _set_date_time_formats()
103
-    {
104
-        /**
105
-         * Format strings for date and time.  Defaults are existing behaviour from 4.1.
106
-         * Note, that if you return null as the value for 'date', and 'time' in the array, then
107
-         * EE will automatically use the set wp_options, 'date_format', and 'time_format'.
108
-         *
109
-         * @since 4.6.7
110
-         * @var array  Expected an array returned with 'date' and 'time' keys.
111
-         */
112
-        $this->_date_format_strings = apply_filters(
113
-            'FHEE__espresso_events_Pricing_Hooks___set_hooks_properties__date_format_strings',
114
-            [
115
-                'date' => 'Y-m-d',
116
-                'time' => 'h:i a',
117
-            ]
118
-        );
119
-        // validate
120
-        $this->_date_format_strings['date'] = $this->_date_format_strings['date'] ?? '';
121
-        $this->_date_format_strings['time'] = $this->_date_format_strings['time'] ?? '';
122
-
123
-        $this->_date_time_format = $this->_date_format_strings['date'] . ' ' . $this->_date_format_strings['time'];
124
-    }
125
-
126
-
127
-    /**
128
-     * @return void
129
-     */
130
-    protected function _validate_format_strings()
131
-    {
132
-        // validate format strings
133
-        $format_validation = EEH_DTT_Helper::validate_format_string(
134
-            $this->_date_time_format
135
-        );
136
-        if (is_array($format_validation)) {
137
-            $msg = '<p>';
138
-            $msg .= sprintf(
139
-                esc_html__(
140
-                    'The format "%s" was likely added via a filter and is invalid for the following reasons:',
141
-                    'event_espresso'
142
-                ),
143
-                $this->_date_time_format
144
-            );
145
-            $msg .= '</p><ul>';
146
-            foreach ($format_validation as $error) {
147
-                $msg .= '<li>' . $error . '</li>';
148
-            }
149
-            $msg .= '</ul><p>';
150
-            $msg .= sprintf(
151
-                esc_html__(
152
-                    '%sPlease note that your date and time formats have been reset to "Y-m-d" and "h:i a" respectively.%s',
153
-                    'event_espresso'
154
-                ),
155
-                '<span style="color:#D54E21;">',
156
-                '</span>'
157
-            );
158
-            $msg .= '</p>';
159
-            EE_Error::add_attention($msg, __FILE__, __FUNCTION__, __LINE__);
160
-            $this->_date_format_strings = [
161
-                'date' => 'Y-m-d',
162
-                'time' => 'h:i a',
163
-            ];
164
-        }
165
-    }
166
-
167
-
168
-    /**
169
-     * @return void
170
-     */
171
-    protected function _set_scripts_styles()
172
-    {
173
-        $this->_scripts_styles = [
174
-            'registers'   => [
175
-                'ee-tickets-datetimes-css' => [
176
-                    'url'  => PRICING_ASSETS_URL . 'event-tickets-datetimes.css',
177
-                    'type' => 'css',
178
-                ],
179
-                'ee-dtt-ticket-metabox'    => [
180
-                    'url'     => PRICING_ASSETS_URL . 'ee-datetime-ticket-metabox.js',
181
-                    'depends' => ['ee-datepicker', 'ee-dialog', 'underscore'],
182
-                ],
183
-            ],
184
-            'deregisters' => [
185
-                'event-editor-css'       => ['type' => 'css'],
186
-                'event-datetime-metabox' => ['type' => 'js'],
187
-            ],
188
-            'enqueues'    => [
189
-                'ee-tickets-datetimes-css' => ['edit', 'create_new'],
190
-                'ee-dtt-ticket-metabox'    => ['edit', 'create_new'],
191
-            ],
192
-            'localize'    => [
193
-                'ee-dtt-ticket-metabox' => [
194
-                    'DTT_TRASH_BLOCK'       => [
195
-                        'main_warning'            => esc_html__(
196
-                            'The Datetime you are attempting to trash is the only datetime selected for the following ticket(s):',
197
-                            'event_espresso'
198
-                        ),
199
-                        'after_warning'           => esc_html__(
200
-                            'In order to trash this datetime you must first make sure the above ticket(s) are assigned to other datetimes.',
201
-                            'event_espresso'
202
-                        ),
203
-                        'cancel_button'           => '
19
+	/**
20
+	 * This property is just used to hold the status of whether an event is currently being
21
+	 * created (true) or edited (false)
22
+	 *
23
+	 * @access protected
24
+	 * @var bool
25
+	 */
26
+	protected $_is_creating_event;
27
+
28
+	/**
29
+	 * Used to contain the format strings for date and time that will be used for php date and
30
+	 * time.
31
+	 * Is set in the _set_hooks_properties() method.
32
+	 *
33
+	 * @var array
34
+	 */
35
+	protected $_date_format_strings;
36
+
37
+	/**
38
+	 * @var string $_date_time_format
39
+	 */
40
+	protected $_date_time_format;
41
+
42
+
43
+	/**
44
+	 * @throws InvalidArgumentException
45
+	 * @throws InvalidInterfaceException
46
+	 * @throws InvalidDataTypeException
47
+	 */
48
+	protected function _set_hooks_properties()
49
+	{
50
+		$this->_name = 'events';
51
+		// capability check
52
+		if (
53
+			$this->_adminpage_obj->adminConfig()->useAdvancedEditor()
54
+			|| ! EE_Registry::instance()->CAP->current_user_can(
55
+				'ee_read_default_prices',
56
+				'advanced_ticket_datetime_metabox'
57
+			)
58
+		) {
59
+			$this->_metaboxes      = [];
60
+			$this->_scripts_styles = [];
61
+			return;
62
+		}
63
+		$this->_setup_metaboxes();
64
+		$this->_set_date_time_formats();
65
+		$this->_validate_format_strings();
66
+		$this->_set_scripts_styles();
67
+		add_filter(
68
+			'FHEE__Events_Admin_Page___insert_update_cpt_item__event_update_callbacks',
69
+			[$this, 'caf_updates']
70
+		);
71
+	}
72
+
73
+
74
+	/**
75
+	 * @return void
76
+	 */
77
+	protected function _setup_metaboxes()
78
+	{
79
+		// if we were going to add our own metaboxes we'd use the below.
80
+		$this->_metaboxes        = [
81
+			0 => [
82
+				'page_route' => ['edit', 'create_new'],
83
+				'func'       => [$this, 'pricing_metabox'],
84
+				'label'      => esc_html__('Event Tickets & Datetimes', 'event_espresso'),
85
+				'priority'   => 'high',
86
+				'context'    => 'normal',
87
+			],
88
+		];
89
+		$this->_remove_metaboxes = [
90
+			0 => [
91
+				'page_route' => ['edit', 'create_new'],
92
+				'id'         => 'espresso_event_editor_tickets',
93
+				'context'    => 'normal',
94
+			],
95
+		];
96
+	}
97
+
98
+
99
+	/**
100
+	 * @return void
101
+	 */
102
+	protected function _set_date_time_formats()
103
+	{
104
+		/**
105
+		 * Format strings for date and time.  Defaults are existing behaviour from 4.1.
106
+		 * Note, that if you return null as the value for 'date', and 'time' in the array, then
107
+		 * EE will automatically use the set wp_options, 'date_format', and 'time_format'.
108
+		 *
109
+		 * @since 4.6.7
110
+		 * @var array  Expected an array returned with 'date' and 'time' keys.
111
+		 */
112
+		$this->_date_format_strings = apply_filters(
113
+			'FHEE__espresso_events_Pricing_Hooks___set_hooks_properties__date_format_strings',
114
+			[
115
+				'date' => 'Y-m-d',
116
+				'time' => 'h:i a',
117
+			]
118
+		);
119
+		// validate
120
+		$this->_date_format_strings['date'] = $this->_date_format_strings['date'] ?? '';
121
+		$this->_date_format_strings['time'] = $this->_date_format_strings['time'] ?? '';
122
+
123
+		$this->_date_time_format = $this->_date_format_strings['date'] . ' ' . $this->_date_format_strings['time'];
124
+	}
125
+
126
+
127
+	/**
128
+	 * @return void
129
+	 */
130
+	protected function _validate_format_strings()
131
+	{
132
+		// validate format strings
133
+		$format_validation = EEH_DTT_Helper::validate_format_string(
134
+			$this->_date_time_format
135
+		);
136
+		if (is_array($format_validation)) {
137
+			$msg = '<p>';
138
+			$msg .= sprintf(
139
+				esc_html__(
140
+					'The format "%s" was likely added via a filter and is invalid for the following reasons:',
141
+					'event_espresso'
142
+				),
143
+				$this->_date_time_format
144
+			);
145
+			$msg .= '</p><ul>';
146
+			foreach ($format_validation as $error) {
147
+				$msg .= '<li>' . $error . '</li>';
148
+			}
149
+			$msg .= '</ul><p>';
150
+			$msg .= sprintf(
151
+				esc_html__(
152
+					'%sPlease note that your date and time formats have been reset to "Y-m-d" and "h:i a" respectively.%s',
153
+					'event_espresso'
154
+				),
155
+				'<span style="color:#D54E21;">',
156
+				'</span>'
157
+			);
158
+			$msg .= '</p>';
159
+			EE_Error::add_attention($msg, __FILE__, __FUNCTION__, __LINE__);
160
+			$this->_date_format_strings = [
161
+				'date' => 'Y-m-d',
162
+				'time' => 'h:i a',
163
+			];
164
+		}
165
+	}
166
+
167
+
168
+	/**
169
+	 * @return void
170
+	 */
171
+	protected function _set_scripts_styles()
172
+	{
173
+		$this->_scripts_styles = [
174
+			'registers'   => [
175
+				'ee-tickets-datetimes-css' => [
176
+					'url'  => PRICING_ASSETS_URL . 'event-tickets-datetimes.css',
177
+					'type' => 'css',
178
+				],
179
+				'ee-dtt-ticket-metabox'    => [
180
+					'url'     => PRICING_ASSETS_URL . 'ee-datetime-ticket-metabox.js',
181
+					'depends' => ['ee-datepicker', 'ee-dialog', 'underscore'],
182
+				],
183
+			],
184
+			'deregisters' => [
185
+				'event-editor-css'       => ['type' => 'css'],
186
+				'event-datetime-metabox' => ['type' => 'js'],
187
+			],
188
+			'enqueues'    => [
189
+				'ee-tickets-datetimes-css' => ['edit', 'create_new'],
190
+				'ee-dtt-ticket-metabox'    => ['edit', 'create_new'],
191
+			],
192
+			'localize'    => [
193
+				'ee-dtt-ticket-metabox' => [
194
+					'DTT_TRASH_BLOCK'       => [
195
+						'main_warning'            => esc_html__(
196
+							'The Datetime you are attempting to trash is the only datetime selected for the following ticket(s):',
197
+							'event_espresso'
198
+						),
199
+						'after_warning'           => esc_html__(
200
+							'In order to trash this datetime you must first make sure the above ticket(s) are assigned to other datetimes.',
201
+							'event_espresso'
202
+						),
203
+						'cancel_button'           => '
204 204
                             <button class="button--secondary ee-modal-cancel">
205 205
                                 ' . esc_html__('Cancel', 'event_espresso') . '
206 206
                             </button>',
207
-                        'close_button'            => '
207
+						'close_button'            => '
208 208
                             <button class="button--secondary ee-modal-cancel">
209 209
                                 ' . esc_html__('Close', 'event_espresso') . '
210 210
                             </button>',
211
-                        'single_warning_from_tkt' => esc_html__(
212
-                            'The Datetime you are attempting to unassign from this ticket is the only remaining datetime for this ticket. Tickets must always have at least one datetime assigned to them.',
213
-                            'event_espresso'
214
-                        ),
215
-                        'single_warning_from_dtt' => esc_html__(
216
-                            'The ticket you are attempting to unassign from this datetime cannot be unassigned because the datetime is the only remaining datetime for the ticket.  Tickets must always have at least one datetime assigned to them.',
217
-                            'event_espresso'
218
-                        ),
219
-                        'dismiss_button'          => '
211
+						'single_warning_from_tkt' => esc_html__(
212
+							'The Datetime you are attempting to unassign from this ticket is the only remaining datetime for this ticket. Tickets must always have at least one datetime assigned to them.',
213
+							'event_espresso'
214
+						),
215
+						'single_warning_from_dtt' => esc_html__(
216
+							'The ticket you are attempting to unassign from this datetime cannot be unassigned because the datetime is the only remaining datetime for the ticket.  Tickets must always have at least one datetime assigned to them.',
217
+							'event_espresso'
218
+						),
219
+						'dismiss_button'          => '
220 220
                             <button class="button--secondary ee-modal-cancel">
221 221
                                 ' . esc_html__('Dismiss', 'event_espresso') . '
222 222
                             </button>',
223
-                    ],
224
-                    'DTT_ERROR_MSG'         => [
225
-                        'no_ticket_name' => esc_html__('General Admission', 'event_espresso'),
226
-                        'dismiss_button' => '
223
+					],
224
+					'DTT_ERROR_MSG'         => [
225
+						'no_ticket_name' => esc_html__('General Admission', 'event_espresso'),
226
+						'dismiss_button' => '
227 227
                             <div class="save-cancel-button-container">
228 228
                                 <button class="button--secondary ee-modal-cancel">
229 229
                                     ' . esc_html__('Dismiss', 'event_espresso') . '
230 230
                                 </button>
231 231
                             </div>',
232
-                    ],
233
-                    'DTT_OVERSELL_WARNING'  => [
234
-                        'datetime_ticket' => esc_html__(
235
-                            'You cannot add this ticket to this datetime because it has a sold amount that is greater than the amount of spots remaining for this datetime.',
236
-                            'event_espresso'
237
-                        ),
238
-                        'ticket_datetime' => esc_html__(
239
-                            'You cannot add this datetime to this ticket because the ticket has a sold amount that is greater than the amount of spots remaining on the datetime.',
240
-                            'event_espresso'
241
-                        ),
242
-                    ],
243
-                    'DTT_CONVERTED_FORMATS' => EEH_DTT_Helper::convert_php_to_js_and_moment_date_formats(
244
-                        $this->_date_format_strings['date'],
245
-                        $this->_date_format_strings['time']
246
-                    ),
247
-                    'DTT_START_OF_WEEK'     => ['dayValue' => (int) get_option('start_of_week')],
248
-                ],
249
-            ],
250
-        ];
251
-    }
252
-
253
-
254
-    /**
255
-     * @param array $update_callbacks
256
-     * @return array
257
-     */
258
-    public function caf_updates(array $update_callbacks): array
259
-    {
260
-        unset($update_callbacks['_default_tickets_update']);
261
-        $update_callbacks['datetime_and_tickets_caf_update'] = [$this, 'datetime_and_tickets_caf_update'];
262
-        return $update_callbacks;
263
-    }
264
-
265
-
266
-    /**
267
-     * Handles saving everything related to Tickets (datetimes, tickets, prices)
268
-     *
269
-     * @param EE_Event $event The Event object we're attaching data to
270
-     * @param array    $data  The request data from the form
271
-     * @throws ReflectionException
272
-     * @throws Exception
273
-     * @throws InvalidInterfaceException
274
-     * @throws InvalidDataTypeException
275
-     * @throws EE_Error
276
-     * @throws InvalidArgumentException
277
-     */
278
-    public function datetime_and_tickets_caf_update(EE_Event $event, array $data)
279
-    {
280
-        // first we need to start with datetimes cause they are the "root" items attached to events.
281
-        $saved_datetimes = $this->_update_datetimes($event, $data);
282
-        // next tackle the tickets (and prices?)
283
-        $this->_update_tickets($event, $saved_datetimes, $data);
284
-    }
285
-
286
-
287
-    /**
288
-     * update event_datetimes
289
-     *
290
-     * @param EE_Event $event Event being updated
291
-     * @param array    $data  the request data from the form
292
-     * @return EE_Datetime[]
293
-     * @throws Exception
294
-     * @throws ReflectionException
295
-     * @throws InvalidInterfaceException
296
-     * @throws InvalidDataTypeException
297
-     * @throws InvalidArgumentException
298
-     * @throws EE_Error
299
-     */
300
-    protected function _update_datetimes(EE_Event $event, array $data): array
301
-    {
302
-        $saved_datetime_ids  = [];
303
-        $saved_datetime_objs = [];
304
-        $timezone            = $data['timezone_string'] ?? null;
305
-        $datetime_model      = EEM_Datetime::instance($timezone);
306
-
307
-        if (empty($data['edit_event_datetimes']) || ! is_array($data['edit_event_datetimes'])) {
308
-            throw new InvalidArgumentException(
309
-                esc_html__(
310
-                    'The "edit_event_datetimes" array is invalid therefore the event can not be updated.',
311
-                    'event_espresso'
312
-                )
313
-            );
314
-        }
315
-        foreach ($data['edit_event_datetimes'] as $row => $datetime_data) {
316
-            // trim all values to ensure any excess whitespace is removed.
317
-            $datetime_data = array_map(
318
-                function ($datetime_data) {
319
-                    return is_array($datetime_data)
320
-                        ? $datetime_data
321
-                        : trim($datetime_data);
322
-                },
323
-                $datetime_data
324
-            );
325
-
326
-            $datetime_data['DTT_EVT_end'] = isset($datetime_data['DTT_EVT_end'])
327
-                                            && ! empty($datetime_data['DTT_EVT_end'])
328
-                ? $datetime_data['DTT_EVT_end']
329
-                : $datetime_data['DTT_EVT_start'];
330
-            $datetime_values              = [
331
-                'DTT_ID'          => ! empty($datetime_data['DTT_ID'])
332
-                    ? $datetime_data['DTT_ID']
333
-                    : null,
334
-                'DTT_name'        => ! empty($datetime_data['DTT_name'])
335
-                    ? $datetime_data['DTT_name']
336
-                    : '',
337
-                'DTT_description' => ! empty($datetime_data['DTT_description'])
338
-                    ? $datetime_data['DTT_description']
339
-                    : '',
340
-                'DTT_EVT_start'   => $datetime_data['DTT_EVT_start'],
341
-                'DTT_EVT_end'     => $datetime_data['DTT_EVT_end'],
342
-                'DTT_reg_limit'   => empty($datetime_data['DTT_reg_limit'])
343
-                    ? EE_INF
344
-                    : $datetime_data['DTT_reg_limit'],
345
-                'DTT_order'       => ! isset($datetime_data['DTT_order'])
346
-                    ? $row
347
-                    : $datetime_data['DTT_order'],
348
-            ];
349
-
350
-            // if we have an id then let's get existing object first and then set the new values.
351
-            // Otherwise we instantiate a new object for save.
352
-            if (! empty($datetime_data['DTT_ID'])) {
353
-                $datetime = EE_Registry::instance()
354
-                                       ->load_model('Datetime', [$timezone])
355
-                                       ->get_one_by_ID($datetime_data['DTT_ID']);
356
-                // set date and time format according to what is set in this class.
357
-                $datetime->set_date_format($this->_date_format_strings['date']);
358
-                $datetime->set_time_format($this->_date_format_strings['time']);
359
-                foreach ($datetime_values as $field => $value) {
360
-                    $datetime->set($field, $value);
361
-                }
362
-
363
-                // make sure the $datetime_id here is saved just in case
364
-                // after the add_relation_to() the autosave replaces it.
365
-                // We need to do this so we dont' TRASH the parent DTT.
366
-                // (save the ID for both key and value to avoid duplications)
367
-                $saved_datetime_ids[ $datetime->ID() ] = $datetime->ID();
368
-            } else {
369
-                $datetime = EE_Datetime::new_instance(
370
-                    $datetime_values,
371
-                    $timezone,
372
-                    [$this->_date_format_strings['date'], $this->_date_format_strings['time']]
373
-                );
374
-                foreach ($datetime_values as $field => $value) {
375
-                    $datetime->set($field, $value);
376
-                }
377
-            }
378
-            $datetime->save();
379
-            do_action(
380
-                'AHEE__espresso_events_Pricing_Hooks___update_datetimes_after_save',
381
-                $datetime,
382
-                $row,
383
-                $datetime_data,
384
-                $data
385
-            );
386
-            $datetime = $event->_add_relation_to($datetime, 'Datetime');
387
-            // before going any further make sure our dates are setup correctly
388
-            // so that the end date is always equal or greater than the start date.
389
-            if ($datetime->get_raw('DTT_EVT_start') > $datetime->get_raw('DTT_EVT_end')) {
390
-                $datetime->set('DTT_EVT_end', $datetime->get('DTT_EVT_start'));
391
-                $datetime = EEH_DTT_Helper::date_time_add($datetime, 'DTT_EVT_end', 'days');
392
-                $datetime->save();
393
-            }
394
-            // now we have to make sure we add the new DTT_ID to the $saved_datetime_ids array
395
-            // because it is possible there was a new one created for the autosave.
396
-            // (save the ID for both key and value to avoid duplications)
397
-            $DTT_ID                        = $datetime->ID();
398
-            $saved_datetime_ids[ $DTT_ID ] = $DTT_ID;
399
-            $saved_datetime_objs[ $row ]   = $datetime;
400
-            // @todo if ANY of these updates fail then we want the appropriate global error message.
401
-        }
402
-        $event->save();
403
-        // now we need to REMOVE any datetimes that got deleted.
404
-        // Keep in mind that this process will only kick in for datetimes that don't have any DTT_sold on them.
405
-        // So its safe to permanently delete at this point.
406
-        $old_datetimes = explode(',', $data['datetime_IDs']);
407
-        $old_datetimes = $old_datetimes[0] === ''
408
-            ? []
409
-            : $old_datetimes;
410
-        if (is_array($old_datetimes)) {
411
-            $datetimes_to_delete = array_diff($old_datetimes, $saved_datetime_ids);
412
-            foreach ($datetimes_to_delete as $id) {
413
-                $id = absint($id);
414
-                if (empty($id)) {
415
-                    continue;
416
-                }
417
-                $dtt_to_remove = $datetime_model->get_one_by_ID($id);
418
-                // remove tkt relationships.
419
-                $related_tickets = $dtt_to_remove->get_many_related('Ticket');
420
-                foreach ($related_tickets as $ticket) {
421
-                    $dtt_to_remove->_remove_relation_to($ticket, 'Ticket');
422
-                }
423
-                $event->_remove_relation_to($id, 'Datetime');
424
-                $dtt_to_remove->refresh_cache_of_related_objects();
425
-            }
426
-        }
427
-        return $saved_datetime_objs;
428
-    }
429
-
430
-
431
-    /**
432
-     * update tickets
433
-     *
434
-     * @param EE_Event      $event           Event object being updated
435
-     * @param EE_Datetime[] $saved_datetimes an array of datetime ids being updated
436
-     * @param array         $data            incoming request data
437
-     * @return EE_Ticket[]
438
-     * @throws Exception
439
-     * @throws ReflectionException
440
-     * @throws InvalidInterfaceException
441
-     * @throws InvalidDataTypeException
442
-     * @throws InvalidArgumentException
443
-     * @throws EE_Error
444
-     */
445
-    protected function _update_tickets(EE_Event $event, array $saved_datetimes, array $data): array
446
-    {
447
-        $new_ticket = null;
448
-        // stripslashes because WP filtered the $_POST ($data) array to add slashes
449
-        $data         = stripslashes_deep($data);
450
-        $timezone     = $data['timezone_string'] ?? null;
451
-        $ticket_model = EEM_Ticket::instance($timezone);
452
-
453
-        $saved_tickets = [];
454
-        $old_tickets   = isset($data['ticket_IDs'])
455
-            ? explode(',', $data['ticket_IDs'])
456
-            : [];
457
-        if (empty($data['edit_tickets']) || ! is_array($data['edit_tickets'])) {
458
-            throw new InvalidArgumentException(
459
-                esc_html__(
460
-                    'The "edit_tickets" array is invalid therefore the event can not be updated.',
461
-                    'event_espresso'
462
-                )
463
-            );
464
-        }
465
-        foreach ($data['edit_tickets'] as $row => $ticket_data) {
466
-            $update_prices = $create_new_TKT = false;
467
-            // figure out what datetimes were added to the ticket
468
-            // and what datetimes were removed from the ticket in the session.
469
-            $starting_ticket_datetime_rows = explode(',', $data['starting_ticket_datetime_rows'][ $row ]);
470
-            $ticket_datetime_rows          = explode(',', $data['ticket_datetime_rows'][ $row ]);
471
-            $datetimes_added               = array_diff($ticket_datetime_rows, $starting_ticket_datetime_rows);
472
-            $datetimes_removed             = array_diff($starting_ticket_datetime_rows, $ticket_datetime_rows);
473
-            // trim inputs to ensure any excess whitespace is removed.
474
-            $ticket_data = array_map(
475
-                function ($ticket_data) {
476
-                    return is_array($ticket_data)
477
-                        ? $ticket_data
478
-                        : trim($ticket_data);
479
-                },
480
-                $ticket_data
481
-            );
482
-            // note we are doing conversions to floats here instead of allowing EE_Money_Field to handle
483
-            // because we're doing calculations prior to using the models.
484
-            // note incoming ['TKT_price'] value is already in standard notation (via js).
485
-            $ticket_price = isset($ticket_data['TKT_price'])
486
-                ? round((float) $ticket_data['TKT_price'], 3)
487
-                : 0;
488
-            // note incoming base price needs converted from localized value.
489
-            $base_price = isset($ticket_data['TKT_base_price'])
490
-                ? EEH_Money::convert_to_float_from_localized_money($ticket_data['TKT_base_price'])
491
-                : 0;
492
-            // if ticket price == 0 and $base_price != 0 then ticket price == base_price
493
-            $ticket_price  = $ticket_price === 0 && $base_price !== 0
494
-                ? $base_price
495
-                : $ticket_price;
496
-            $base_price_id = $ticket_data['TKT_base_price_ID'] ?? 0;
497
-            $price_rows    = is_array($data['edit_prices']) && isset($data['edit_prices'][ $row ])
498
-                ? $data['edit_prices'][ $row ]
499
-                : [];
500
-            $now           = null;
501
-            if (empty($ticket_data['TKT_start_date'])) {
502
-                // lets' use now in the set timezone.
503
-                $now                           = new DateTime('now', new DateTimeZone($event->get_timezone()));
504
-                $ticket_data['TKT_start_date'] = $now->format($this->_date_time_format);
505
-            }
506
-            if (empty($ticket_data['TKT_end_date'])) {
507
-                /**
508
-                 * set the TKT_end_date to the first datetime attached to the ticket.
509
-                 */
510
-                $first_datetime              = $saved_datetimes[ reset($ticket_datetime_rows) ];
511
-                $ticket_data['TKT_end_date'] = $first_datetime->start_date_and_time($this->_date_time_format);
512
-            }
513
-            $TKT_values = [
514
-                'TKT_ID'          => ! empty($ticket_data['TKT_ID'])
515
-                    ? $ticket_data['TKT_ID']
516
-                    : null,
517
-                'TTM_ID'          => ! empty($ticket_data['TTM_ID'])
518
-                    ? $ticket_data['TTM_ID']
519
-                    : 0,
520
-                'TKT_name'        => ! empty($ticket_data['TKT_name'])
521
-                    ? $ticket_data['TKT_name']
522
-                    : '',
523
-                'TKT_description' => ! empty($ticket_data['TKT_description'])
524
-                                     && $ticket_data['TKT_description'] !== esc_html__(
525
-                                         'You can modify this description',
526
-                                         'event_espresso'
527
-                                     )
528
-                    ? $ticket_data['TKT_description']
529
-                    : '',
530
-                'TKT_start_date'  => $ticket_data['TKT_start_date'],
531
-                'TKT_end_date'    => $ticket_data['TKT_end_date'],
532
-                'TKT_qty'         => ! isset($ticket_data['TKT_qty']) || $ticket_data['TKT_qty'] === ''
533
-                    ? EE_INF
534
-                    : $ticket_data['TKT_qty'],
535
-                'TKT_uses'        => ! isset($ticket_data['TKT_uses']) || $ticket_data['TKT_uses'] === ''
536
-                    ? EE_INF
537
-                    : $ticket_data['TKT_uses'],
538
-                'TKT_min'         => empty($ticket_data['TKT_min'])
539
-                    ? 0
540
-                    : $ticket_data['TKT_min'],
541
-                'TKT_max'         => empty($ticket_data['TKT_max'])
542
-                    ? EE_INF
543
-                    : $ticket_data['TKT_max'],
544
-                'TKT_row'         => $row,
545
-                'TKT_order'       => $ticket_data['TKT_order'] ?? 0,
546
-                'TKT_taxable'     => ! empty($ticket_data['TKT_taxable'])
547
-                    ? 1
548
-                    : 0,
549
-                'TKT_required'    => ! empty($ticket_data['TKT_required'])
550
-                    ? 1
551
-                    : 0,
552
-                'TKT_price'       => $ticket_price,
553
-            ];
554
-            // if this is a default TKT, then we need to set the TKT_ID to 0 and update accordingly,
555
-            // which means in turn that the prices will become new prices as well.
556
-            if (isset($ticket_data['TKT_is_default']) && $ticket_data['TKT_is_default']) {
557
-                $TKT_values['TKT_ID']         = 0;
558
-                $TKT_values['TKT_is_default'] = 0;
559
-                $update_prices                = true;
560
-            }
561
-            // if we have a TKT_ID then we need to get that existing TKT_obj and update it
562
-            // we actually do our saves ahead of doing any add_relations to
563
-            // because its entirely possible that this ticket wasn't removed or added to any datetime in the session
564
-            // but DID have it's items modified.
565
-            // keep in mind that if the TKT has been sold (and we have changed pricing information),
566
-            // then we won't be updating the ticket but instead a new ticket will be created and the old one archived.
567
-            if (absint($TKT_values['TKT_ID'])) {
568
-                $ticket = EE_Registry::instance()
569
-                                     ->load_model('Ticket', [$timezone])
570
-                                     ->get_one_by_ID($TKT_values['TKT_ID']);
571
-                if ($ticket instanceof EE_Ticket) {
572
-                    $ticket = $this->_update_ticket_datetimes(
573
-                        $ticket,
574
-                        $saved_datetimes,
575
-                        $datetimes_added,
576
-                        $datetimes_removed
577
-                    );
578
-                    // are there any registrations using this ticket ?
579
-                    $tickets_sold = $ticket->count_related(
580
-                        'Registration',
581
-                        [
582
-                            [
583
-                                'STS_ID' => ['NOT IN', [RegStatus::INCOMPLETE]],
584
-                            ],
585
-                        ]
586
-                    );
587
-                    // set ticket formats
588
-                    $ticket->set_date_format($this->_date_format_strings['date']);
589
-                    $ticket->set_time_format($this->_date_format_strings['time']);
590
-                    // let's just check the total price for the existing ticket
591
-                    // and determine if it matches the new total price.
592
-                    // if they are different then we create a new ticket (if tickets sold)
593
-                    // if they aren't different then we go ahead and modify existing ticket.
594
-                    $create_new_TKT = $tickets_sold > 0 && $ticket_price !== $ticket->price() && ! $ticket->deleted();
595
-                    // set new values
596
-                    foreach ($TKT_values as $field => $value) {
597
-                        if ($field === 'TKT_qty') {
598
-                            $ticket->set_qty($value);
599
-                        } else {
600
-                            $ticket->set($field, $value);
601
-                        }
602
-                    }
603
-                    // if $create_new_TKT is false then we can safely update the existing ticket.
604
-                    // Otherwise we have to create a new ticket.
605
-                    if ($create_new_TKT) {
606
-                        $new_ticket = $this->_duplicate_ticket(
607
-                            $ticket,
608
-                            $price_rows,
609
-                            $ticket_price,
610
-                            $base_price,
611
-                            $base_price_id
612
-                        );
613
-                    }
614
-                }
615
-            } else {
616
-                // no TKT_id so a new TKT
617
-                $ticket = EE_Ticket::new_instance(
618
-                    $TKT_values,
619
-                    $timezone,
620
-                    [$this->_date_format_strings['date'], $this->_date_format_strings['time']]
621
-                );
622
-                if ($ticket instanceof EE_Ticket) {
623
-                    // make sure ticket has an ID of setting relations won't work
624
-                    $ticket->save();
625
-                    $ticket        = $this->_update_ticket_datetimes(
626
-                        $ticket,
627
-                        $saved_datetimes,
628
-                        $datetimes_added,
629
-                        $datetimes_removed
630
-                    );
631
-                    $update_prices = true;
632
-                }
633
-            }
634
-            // make sure any current values have been saved.
635
-            // $ticket->save();
636
-            // before going any further make sure our dates are setup correctly
637
-            // so that the end date is always equal or greater than the start date.
638
-            if ($ticket->get_raw('TKT_start_date') > $ticket->get_raw('TKT_end_date')) {
639
-                $ticket->set('TKT_end_date', $ticket->get('TKT_start_date'));
640
-                $ticket = EEH_DTT_Helper::date_time_add($ticket, 'TKT_end_date', 'days');
641
-            }
642
-            // let's make sure the base price is handled
643
-            $ticket = ! $create_new_TKT
644
-                ? $this->_add_prices_to_ticket(
645
-                    [],
646
-                    $ticket,
647
-                    $update_prices,
648
-                    $base_price,
649
-                    $base_price_id
650
-                )
651
-                : $ticket;
652
-            // add/update price_modifiers
653
-            $ticket = ! $create_new_TKT
654
-                ? $this->_add_prices_to_ticket($price_rows, $ticket, $update_prices)
655
-                : $ticket;
656
-            // need to make sue that the TKT_price is accurate after saving the prices.
657
-            $ticket->ensure_TKT_Price_correct();
658
-            // handle CREATING a default ticket from the incoming ticket but ONLY if this isn't an autosave.
659
-            if (! defined('DOING_AUTOSAVE') && ! empty($ticket_data['TKT_is_default_selector'])) {
660
-                $new_default = clone $ticket;
661
-                $new_default->set('TKT_ID', 0);
662
-                $new_default->set('TKT_is_default', 1);
663
-                $new_default->set('TKT_row', 1);
664
-                $new_default->set('TKT_price', $ticket_price);
665
-                // remove any datetime relations cause we DON'T want datetime relations attached
666
-                // (note this is just removing the cached relations in the object)
667
-                $new_default->_remove_relations('Datetime');
668
-                // @todo we need to add the current attached prices as new prices to the new default ticket.
669
-                $new_default = $this->_add_prices_to_ticket(
670
-                    $price_rows,
671
-                    $new_default,
672
-                    true
673
-                );
674
-                // don't forget the base price!
675
-                $new_default = $this->_add_prices_to_ticket(
676
-                    [],
677
-                    $new_default,
678
-                    true,
679
-                    $base_price,
680
-                    $base_price_id
681
-                );
682
-                $new_default->save();
683
-                do_action(
684
-                    'AHEE__espresso_events_Pricing_Hooks___update_tkts_new_default_ticket',
685
-                    $new_default,
686
-                    $row,
687
-                    $ticket,
688
-                    $data
689
-                );
690
-            }
691
-            // DO ALL datetime relationships for both current tickets and any archived tickets
692
-            // for the given datetime that are related to the current ticket.
693
-            // TODO... not sure exactly how we're going to do this considering we don't know
694
-            // what current ticket the archived tickets are related to
695
-            // (and TKT_parent is used for autosaves so that's not a field we can reliably use).
696
-            // let's assign any tickets that have been setup to the saved_tickets tracker
697
-            // save existing TKT
698
-            $ticket->save();
699
-            if ($create_new_TKT && $new_ticket instanceof EE_Ticket) {
700
-                // save new TKT
701
-                $new_ticket->save();
702
-                // add new ticket to array
703
-                $saved_tickets[ $new_ticket->ID() ] = $new_ticket;
704
-                do_action(
705
-                    'AHEE__espresso_events_Pricing_Hooks___update_tkts_new_ticket',
706
-                    $new_ticket,
707
-                    $row,
708
-                    $ticket_data,
709
-                    $data
710
-                );
711
-            } else {
712
-                // add ticket to saved tickets
713
-                $saved_tickets[ $ticket->ID() ] = $ticket;
714
-                do_action(
715
-                    'AHEE__espresso_events_Pricing_Hooks___update_tkts_update_ticket',
716
-                    $ticket,
717
-                    $row,
718
-                    $ticket_data,
719
-                    $data
720
-                );
721
-            }
722
-        }
723
-        // now we need to handle tickets actually "deleted permanently".
724
-        // There are cases where we'd want this to happen
725
-        // (i.e. autosaves are happening and then in between autosaves the user trashes a ticket).
726
-        // Or a draft event was saved and in the process of editing a ticket is trashed.
727
-        // No sense in keeping all the related data in the db!
728
-        $old_tickets     = isset($old_tickets[0]) && $old_tickets[0] === ''
729
-            ? []
730
-            : $old_tickets;
731
-        $tickets_removed = array_diff($old_tickets, array_keys($saved_tickets));
732
-        foreach ($tickets_removed as $id) {
733
-            $id = absint($id);
734
-            // get the ticket for this id
735
-            $ticket_to_remove = $ticket_model->get_one_by_ID($id);
736
-            // if this tkt is a default tkt we leave it alone cause it won't be attached to the datetime
737
-            if ($ticket_to_remove->get('TKT_is_default')) {
738
-                continue;
739
-            }
740
-            // if this ticket has any registrations attached so then we just ARCHIVE
741
-            // because we don't actually permanently delete these tickets.
742
-            if ($ticket_to_remove->count_related('Registration') > 0) {
743
-                $ticket_to_remove->delete();
744
-                continue;
745
-            }
746
-            // need to get all the related datetimes on this ticket and remove from every single one of them
747
-            // (remember this process can ONLY kick off if there are NO tickets_sold)
748
-            $datetimes = $ticket_to_remove->get_many_related('Datetime');
749
-            foreach ($datetimes as $datetime) {
750
-                $ticket_to_remove->_remove_relation_to($datetime, 'Datetime');
751
-            }
752
-            // need to do the same for prices (except these prices can also be deleted because again,
753
-            // tickets can only be trashed if they don't have any TKTs sold (otherwise they are just archived))
754
-            $ticket_to_remove->delete_related('Price');
755
-            do_action('AHEE__espresso_events_Pricing_Hooks___update_tkts_delete_ticket', $ticket_to_remove);
756
-            // finally let's delete this ticket
757
-            // (which should not be blocked at this point b/c we've removed all our relationships)
758
-            $ticket_to_remove->delete_or_restore();
759
-        }
760
-        return $saved_tickets;
761
-    }
762
-
763
-
764
-    /**
765
-     * @access  protected
766
-     * @param EE_Ticket     $ticket
767
-     * @param EE_Datetime[] $saved_datetimes
768
-     * @param int[]         $added_datetimes
769
-     * @param int[]         $removed_datetimes
770
-     * @return EE_Ticket
771
-     * @throws EE_Error
772
-     * @throws ReflectionException
773
-     */
774
-    protected function _update_ticket_datetimes(
775
-        EE_Ticket $ticket,
776
-        array $saved_datetimes = [],
777
-        array $added_datetimes = [],
778
-        array $removed_datetimes = []
779
-    ): EE_Ticket {
780
-        // to start we have to add the ticket to all the datetimes its supposed to be with,
781
-        // and removing the ticket from datetimes it got removed from.
782
-        // first let's add datetimes
783
-        if (! empty($added_datetimes) && is_array($added_datetimes)) {
784
-            foreach ($added_datetimes as $row_id) {
785
-                if (isset($saved_datetimes[ $row_id ]) && $saved_datetimes[ $row_id ] instanceof EE_Datetime) {
786
-                    $ticket->_add_relation_to($saved_datetimes[ $row_id ], 'Datetime');
787
-                    // Is this an existing ticket (has an ID) and does it have any sold?
788
-                    // If so, then we need to add that to the DTT sold because this DTT is getting added.
789
-                    if ($ticket->ID() && $ticket->sold() > 0) {
790
-                        $saved_datetimes[ $row_id ]->increaseSold($ticket->sold(), false);
791
-                    }
792
-                }
793
-            }
794
-        }
795
-        // then remove datetimes
796
-        if (! empty($removed_datetimes) && is_array($removed_datetimes)) {
797
-            foreach ($removed_datetimes as $row_id) {
798
-                // its entirely possible that a datetime got deleted (instead of just removed from relationship.
799
-                // So make sure we skip over this if the datetime isn't in the $saved_datetimes array)
800
-                if (isset($saved_datetimes[ $row_id ]) && $saved_datetimes[ $row_id ] instanceof EE_Datetime) {
801
-                    $ticket->_remove_relation_to($saved_datetimes[ $row_id ], 'Datetime');
802
-                }
803
-            }
804
-        }
805
-        // cap ticket qty by datetime reg limits
806
-        $ticket->set_qty(min($ticket->qty(), $ticket->qty('reg_limit')));
807
-        return $ticket;
808
-    }
809
-
810
-
811
-    /**
812
-     * @access  protected
813
-     * @param EE_Ticket $ticket
814
-     * @param array     $price_rows
815
-     * @param int|float $ticket_price
816
-     * @param int|float $base_price
817
-     * @param int       $base_price_id
818
-     * @return EE_Ticket
819
-     * @throws ReflectionException
820
-     * @throws InvalidArgumentException
821
-     * @throws InvalidInterfaceException
822
-     * @throws InvalidDataTypeException
823
-     * @throws EE_Error
824
-     */
825
-    protected function _duplicate_ticket(
826
-        EE_Ticket $ticket,
827
-        array $price_rows = [],
828
-        $ticket_price = 0,
829
-        $base_price = 0,
830
-        int $base_price_id = 0
831
-    ): EE_Ticket {
832
-        // create new ticket that's a copy of the existing
833
-        // except a new id of course (and not archived)
834
-        // AND has the new TKT_price associated with it.
835
-        $new_ticket = clone $ticket;
836
-        $new_ticket->set('TKT_ID', 0);
837
-        $new_ticket->set_deleted(0);
838
-        $new_ticket->set_price($ticket_price);
839
-        $new_ticket->set_sold(0);
840
-        // let's get a new ID for this ticket
841
-        $new_ticket->save();
842
-        // we also need to make sure this new ticket gets the same datetime attachments as the archived ticket
843
-        $datetimes_on_existing = $ticket->datetimes();
844
-        $new_ticket            = $this->_update_ticket_datetimes(
845
-            $new_ticket,
846
-            $datetimes_on_existing,
847
-            array_keys($datetimes_on_existing)
848
-        );
849
-        // $ticket will get archived later b/c we are NOT adding it to the saved_tickets array.
850
-        // if existing $ticket has sold amount, then we need to adjust the qty for the new TKT to = the remaining
851
-        // available.
852
-        if ($ticket->sold() > 0) {
853
-            $new_qty = $ticket->qty() - $ticket->sold();
854
-            $new_ticket->set_qty($new_qty);
855
-        }
856
-        // now we update the prices just for this ticket
857
-        $new_ticket = $this->_add_prices_to_ticket($price_rows, $new_ticket, true);
858
-        // and we update the base price
859
-        return $this->_add_prices_to_ticket(
860
-            [],
861
-            $new_ticket,
862
-            true,
863
-            $base_price,
864
-            $base_price_id
865
-        );
866
-    }
867
-
868
-
869
-    /**
870
-     * This attaches a list of given prices to a ticket.
871
-     * Note we dont' have to worry about ever removing relationships (or archiving prices) because if there is a change
872
-     * in price information on a ticket, a new ticket is created anyways so the archived ticket will retain the old
873
-     * price info and prices are automatically "archived" via the ticket.
874
-     *
875
-     * @access  private
876
-     * @param array     $prices        Array of prices from the form.
877
-     * @param EE_Ticket $ticket        EE_Ticket object that prices are being attached to.
878
-     * @param bool      $new_prices    Whether attach existing incoming prices or create new ones.
879
-     * @param int|bool  $base_price    if FALSE then NOT doing a base price add.
880
-     * @param int|bool  $base_price_id if present then this is the base_price_id being updated.
881
-     * @return EE_Ticket
882
-     * @throws ReflectionException
883
-     * @throws InvalidArgumentException
884
-     * @throws InvalidInterfaceException
885
-     * @throws InvalidDataTypeException
886
-     * @throws EE_Error
887
-     */
888
-    protected function _add_prices_to_ticket(
889
-        array $prices,
890
-        EE_Ticket $ticket,
891
-        bool $new_prices = false,
892
-        $base_price = false,
893
-        $base_price_id = false
894
-    ): EE_Ticket {
895
-        $price_model = EEM_Price::instance();
896
-        // let's just get any current prices that may exist on the given ticket
897
-        // so we can remove any prices that got trashed in this session.
898
-        $current_prices_on_ticket = $base_price !== false
899
-            ? $ticket->base_price(true)
900
-            : $ticket->price_modifiers();
901
-        $updated_prices           = [];
902
-        // if $base_price ! FALSE then updating a base price.
903
-        if ($base_price !== false) {
904
-            $prices[1] = [
905
-                'PRC_ID'     => $new_prices || $base_price_id === 1
906
-                    ? null
907
-                    : $base_price_id,
908
-                'PRT_ID'     => 1,
909
-                'PRC_amount' => $base_price,
910
-                'PRC_name'   => $ticket->get('TKT_name'),
911
-                'PRC_desc'   => $ticket->get('TKT_description'),
912
-            ];
913
-        }
914
-        // possibly need to save ticket
915
-        if (! $ticket->ID()) {
916
-            $ticket->save();
917
-        }
918
-        foreach ($prices as $row => $prc) {
919
-            $prt_id = ! empty($prc['PRT_ID'])
920
-                ? $prc['PRT_ID']
921
-                : null;
922
-            if (empty($prt_id)) {
923
-                continue;
924
-            } //prices MUST have a price type id.
925
-            $PRC_values = [
926
-                'PRC_ID'         => ! empty($prc['PRC_ID'])
927
-                    ? $prc['PRC_ID']
928
-                    : null,
929
-                'PRT_ID'         => $prt_id,
930
-                'PRC_amount'     => ! empty($prc['PRC_amount'])
931
-                    ? $prc['PRC_amount']
932
-                    : 0,
933
-                'PRC_name'       => ! empty($prc['PRC_name'])
934
-                    ? $prc['PRC_name']
935
-                    : '',
936
-                'PRC_desc'       => ! empty($prc['PRC_desc'])
937
-                    ? $prc['PRC_desc']
938
-                    : '',
939
-                'PRC_is_default' => false,
940
-                // make sure we set PRC_is_default to false for all ticket saves from event_editor
941
-                'PRC_order'      => $row,
942
-            ];
943
-            if ($new_prices || empty($PRC_values['PRC_ID'])) {
944
-                $PRC_values['PRC_ID'] = 0;
945
-                $price                = EE_Registry::instance()->load_class(
946
-                    'Price',
947
-                    [$PRC_values],
948
-                    false,
949
-                    false
950
-                );
951
-            } else {
952
-                $price = $price_model->get_one_by_ID($prc['PRC_ID']);
953
-                // update this price with new values
954
-                foreach ($PRC_values as $field => $value) {
955
-                    $price->set($field, $value);
956
-                }
957
-            }
958
-            $price->save();
959
-            $updated_prices[ $price->ID() ] = $price;
960
-            $ticket->_add_relation_to($price, 'Price');
961
-        }
962
-        // now let's remove any prices that got removed from the ticket
963
-        if (! empty($current_prices_on_ticket)) {
964
-            $current          = array_keys($current_prices_on_ticket);
965
-            $updated          = array_keys($updated_prices);
966
-            $prices_to_remove = array_diff($current, $updated);
967
-            if (! empty($prices_to_remove)) {
968
-                foreach ($prices_to_remove as $prc_id) {
969
-                    $p = $current_prices_on_ticket[ $prc_id ];
970
-                    $ticket->_remove_relation_to($p, 'Price');
971
-                    // delete permanently the price
972
-                    $p->delete_or_restore();
973
-                }
974
-            }
975
-        }
976
-        return $ticket;
977
-    }
978
-
979
-
980
-    /**
981
-     * @throws ReflectionException
982
-     * @throws InvalidArgumentException
983
-     * @throws InvalidInterfaceException
984
-     * @throws InvalidDataTypeException
985
-     * @throws DomainException
986
-     * @throws EE_Error
987
-     */
988
-    public function pricing_metabox()
989
-    {
990
-        $event          = $this->_adminpage_obj->get_cpt_model_obj();
991
-        $timezone       = $event instanceof EE_Event
992
-            ? $event->timezone_string()
993
-            : null;
994
-        $price_model    = EEM_Price::instance($timezone);
995
-        $ticket_model   = EEM_Ticket::instance($timezone);
996
-        $datetime_model = EEM_Datetime::instance($timezone);
997
-        $all_tickets    = [];
998
-
999
-        // set is_creating_event property.
1000
-        $EVT_ID                   = $event->ID();
1001
-        $this->_is_creating_event = empty($this->_req_data['post']);
1002
-        $existing_datetime_ids    = $existing_ticket_ids = $datetime_tickets = $ticket_datetimes = [];
1003
-
1004
-        // default main template args
1005
-        $main_template_args = [
1006
-            'event_datetime_help_link' => EEH_Template::get_help_tab_link(
1007
-                'event_editor_event_datetimes_help_tab',
1008
-                $this->_adminpage_obj->page_slug,
1009
-                $this->_adminpage_obj->get_req_action()
1010
-            ),
1011
-
1012
-            // todo need to add a filter to the template for the help text
1013
-            // in the Events_Admin_Page core file so we can add further help
1014
-            'add_new_dtt_help_link'    => EEH_Template::get_help_tab_link(
1015
-                'add_new_dtt_info',
1016
-                $this->_adminpage_obj->page_slug,
1017
-                $this->_adminpage_obj->get_req_action()
1018
-            ),
1019
-            // todo need to add this help info id to the Events_Admin_Page core file so we can access it here.
1020
-            'datetime_rows'            => '',
1021
-            'show_tickets_container'   => '',
1022
-            'ticket_rows'              => '',
1023
-            'ee_collapsible_status'    => ' ee-collapsible-open',
1024
-            // $this->_adminpage_obj->get_cpt_model_obj()->ID() > 0 ? ' ee-collapsible-closed' : ' ee-collapsible-open'
1025
-        ];
1026
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
1027
-
1028
-        /**
1029
-         * 1. Start with retrieving Datetimes
1030
-         * 2. For each datetime get related tickets
1031
-         * 3. For each ticket get related prices
1032
-         */
1033
-        $datetimes                            = $datetime_model->get_all_event_dates($EVT_ID);
1034
-        $main_template_args['total_dtt_rows'] = count($datetimes);
1035
-
1036
-        /**
1037
-         * @see https://events.codebasehq.com/projects/event-espresso/tickets/9486
1038
-         * for why we are counting $datetime_row and then setting that on the Datetime object
1039
-         */
1040
-        $datetime_row = 1;
1041
-        foreach ($datetimes as $datetime) {
1042
-            $DTT_ID = $datetime->get('DTT_ID');
1043
-            $datetime->set('DTT_order', $datetime_row);
1044
-            $existing_datetime_ids[] = $DTT_ID;
1045
-            // tickets attached
1046
-            $related_tickets = $datetime->ID() > 0
1047
-                ? $datetime->get_many_related(
1048
-                    'Ticket',
1049
-                    [
1050
-                        [
1051
-                            'OR' => ['TKT_deleted' => 1, 'TKT_deleted*' => 0],
1052
-                        ],
1053
-                        'default_where_conditions' => 'none',
1054
-                        'order_by'                 => ['TKT_order' => 'ASC'],
1055
-                    ]
1056
-                )
1057
-                : [];
1058
-            // if there are no related tickets this is likely a new event OR auto-draft
1059
-            // event so we need to generate the default tickets because datetimes
1060
-            // ALWAYS have at least one related ticket!!.  EXCEPT, we dont' do this if there is already more than one
1061
-            // datetime on the event.
1062
-            if (empty($related_tickets) && count($datetimes) < 2) {
1063
-                $related_tickets = $ticket_model->get_all_default_tickets();
1064
-                // this should be ordered by TKT_ID, so let's grab the first default ticket
1065
-                // (which will be the main default) and ensure it has any default prices added to it (but do NOT save).
1066
-                $default_prices      = $price_model->get_all_default_prices();
1067
-                $main_default_ticket = reset($related_tickets);
1068
-                if ($main_default_ticket instanceof EE_Ticket) {
1069
-                    foreach ($default_prices as $default_price) {
1070
-                        if ($default_price instanceof EE_Price && $default_price->is_base_price()) {
1071
-                            continue;
1072
-                        }
1073
-                        $main_default_ticket->cache('Price', $default_price);
1074
-                    }
1075
-                }
1076
-            }
1077
-            // we can't actually setup rows in this loop yet cause we don't know all
1078
-            // the unique tickets for this event yet (tickets are linked through all datetimes).
1079
-            // So we're going to temporarily cache some of that information.
1080
-            // loop through and setup the ticket rows and make sure the order is set.
1081
-            foreach ($related_tickets as $ticket) {
1082
-                $TKT_ID     = $ticket->get('TKT_ID');
1083
-                $ticket_row = $ticket->get('TKT_row');
1084
-                // we only want unique tickets in our final display!!
1085
-                if (! in_array($TKT_ID, $existing_ticket_ids, true)) {
1086
-                    $existing_ticket_ids[] = $TKT_ID;
1087
-                    $all_tickets[]         = $ticket;
1088
-                }
1089
-                // temporary cache of this ticket info for this datetime for later processing of datetime rows.
1090
-                $datetime_tickets[ $DTT_ID ][] = $ticket_row;
1091
-                // temporary cache of this datetime info for this ticket for later processing of ticket rows.
1092
-                if (
1093
-                    ! isset($ticket_datetimes[ $TKT_ID ])
1094
-                    || ! in_array($datetime_row, $ticket_datetimes[ $TKT_ID ], true)
1095
-                ) {
1096
-                    $ticket_datetimes[ $TKT_ID ][] = $datetime_row;
1097
-                }
1098
-            }
1099
-            $datetime_row++;
1100
-        }
1101
-        $main_template_args['total_ticket_rows']     = count($existing_ticket_ids);
1102
-        $main_template_args['existing_ticket_ids']   = implode(',', $existing_ticket_ids);
1103
-        $main_template_args['existing_datetime_ids'] = implode(',', $existing_datetime_ids);
1104
-        // sort $all_tickets by order
1105
-        usort(
1106
-            $all_tickets,
1107
-            function (EE_Ticket $a, EE_Ticket $b) {
1108
-                $a_order = (int) $a->get('TKT_order');
1109
-                $b_order = (int) $b->get('TKT_order');
1110
-                if ($a_order === $b_order) {
1111
-                    return 0;
1112
-                }
1113
-                return ($a_order < $b_order)
1114
-                    ? -1
1115
-                    : 1;
1116
-            }
1117
-        );
1118
-        // k NOW we have all the data we need for setting up the datetime rows
1119
-        // and ticket rows so we start our datetime loop again.
1120
-        $datetime_row = 1;
1121
-        foreach ($datetimes as $datetime) {
1122
-            $main_template_args['datetime_rows'] .= $this->_get_datetime_row(
1123
-                $datetime_row,
1124
-                $datetime,
1125
-                $datetime_tickets,
1126
-                $all_tickets,
1127
-                false,
1128
-                $datetimes
1129
-            );
1130
-            $datetime_row++;
1131
-        }
1132
-        // then loop through all tickets for the ticket rows.
1133
-        $ticket_row = 1;
1134
-        foreach ($all_tickets as $ticket) {
1135
-            $main_template_args['ticket_rows'] .= $this->_get_ticket_row(
1136
-                $ticket_row,
1137
-                $ticket,
1138
-                $ticket_datetimes,
1139
-                $datetimes,
1140
-                false,
1141
-                $all_tickets
1142
-            );
1143
-            $ticket_row++;
1144
-        }
1145
-        $main_template_args['ticket_js_structure'] = $this->_get_ticket_js_structure($datetimes, $all_tickets);
1146
-
1147
-        $status_change_notice = LoaderFactory::getLoader()->getShared(
1148
-            'EventEspresso\core\domain\services\admin\notices\status_change\StatusChangeNotice'
1149
-        );
1150
-
1151
-        $main_template_args['status_change_notice'] = $status_change_notice->display(
1152
-            '__event-editor',
1153
-            'espresso-events'
1154
-        );
1155
-
1156
-        EEH_Template::display_template(
1157
-            PRICING_TEMPLATE_PATH . 'event_tickets_metabox_main.template.php',
1158
-            $main_template_args
1159
-        );
1160
-    }
1161
-
1162
-
1163
-    /**
1164
-     * @param int|string  $datetime_row
1165
-     * @param EE_Datetime $datetime
1166
-     * @param array       $datetime_tickets
1167
-     * @param array       $all_tickets
1168
-     * @param bool        $default
1169
-     * @param array       $all_datetimes
1170
-     * @return string
1171
-     * @throws DomainException
1172
-     * @throws EE_Error
1173
-     * @throws ReflectionException
1174
-     */
1175
-    protected function _get_datetime_row(
1176
-        $datetime_row,
1177
-        EE_Datetime $datetime,
1178
-        array $datetime_tickets = [],
1179
-        array $all_tickets = [],
1180
-        bool $default = false,
1181
-        array $all_datetimes = []
1182
-    ): string {
1183
-        return EEH_Template::display_template(
1184
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_row_wrapper.template.php',
1185
-            [
1186
-                'dtt_edit_row'             => $this->_get_dtt_edit_row(
1187
-                    $datetime_row,
1188
-                    $datetime,
1189
-                    $default,
1190
-                    $all_datetimes
1191
-                ),
1192
-                'dtt_attached_tickets_row' => $this->_get_dtt_attached_tickets_row(
1193
-                    $datetime_row,
1194
-                    $datetime,
1195
-                    $datetime_tickets,
1196
-                    $all_tickets,
1197
-                    $default
1198
-                ),
1199
-                'dtt_row'                  => $default
1200
-                    ? 'DTTNUM'
1201
-                    : $datetime_row,
1202
-            ],
1203
-            true
1204
-        );
1205
-    }
1206
-
1207
-
1208
-    /**
1209
-     * This method is used to generate a datetime fields  edit row.
1210
-     * The same row is used to generate a row with valid DTT objects
1211
-     * and the default row that is used as the skeleton by the js.
1212
-     *
1213
-     * @param int|string       $datetime_row  The row number for the row being generated.
1214
-     * @param EE_Datetime|null $datetime
1215
-     * @param bool             $default       Whether a default row is being generated or not.
1216
-     * @param EE_Datetime[]    $all_datetimes This is the array of all datetimes used in the editor.
1217
-     * @return string
1218
-     * @throws EE_Error
1219
-     * @throws ReflectionException
1220
-     */
1221
-    protected function _get_dtt_edit_row(
1222
-        $datetime_row,
1223
-        ?EE_Datetime $datetime,
1224
-        bool $default,
1225
-        array $all_datetimes
1226
-    ): string {
1227
-        // if the incoming $datetime object is NOT an instance of EE_Datetime then force default to true.
1228
-        $default                     = ! $datetime instanceof EE_Datetime
1229
-            ? true
1230
-            : $default;
1231
-        $template_args               = [
1232
-            'dtt_row'              => $default
1233
-                ? 'DTTNUM'
1234
-                : $datetime_row,
1235
-            'event_datetimes_name' => $default
1236
-                ? 'DTTNAMEATTR'
1237
-                : 'edit_event_datetimes',
1238
-            'edit_dtt_expanded'    => '',
1239
-            'DTT_ID'               => $default
1240
-                ? ''
1241
-                : $datetime->ID(),
1242
-            'DTT_name'             => $default
1243
-                ? ''
1244
-                : $datetime->get_f('DTT_name'),
1245
-            'DTT_description'      => $default
1246
-                ? ''
1247
-                : $datetime->get_raw('DTT_description'),
1248
-            'DTT_EVT_start'        => $default
1249
-                ? ''
1250
-                : $datetime->start_date($this->_date_time_format),
1251
-            'DTT_EVT_end'          => $default
1252
-                ? ''
1253
-                : $datetime->end_date($this->_date_time_format),
1254
-            'DTT_reg_limit'        => $default
1255
-                ? ''
1256
-                : $datetime->get_pretty(
1257
-                    'DTT_reg_limit',
1258
-                    'input'
1259
-                ),
1260
-            'DTT_order'            => $default
1261
-                ? 'DTTNUM'
1262
-                : $datetime_row,
1263
-            'dtt_sold'             => $default
1264
-                ? '0'
1265
-                : $datetime->get('DTT_sold'),
1266
-            'dtt_reserved'         => $default
1267
-                ? '0'
1268
-                : $datetime->reserved(),
1269
-            'can_clone'            => $datetime instanceof EE_Datetime,
1270
-            'can_trash'            => count($all_datetimes) > 1
1271
-                                      && $datetime instanceof EE_Datetime
1272
-                                      && ! $datetime->get('DTT_sold'),
1273
-            'trash_icon'           => ! empty($datetime) && $datetime->get('DTT_sold') > 0
1274
-                ? 'trash-entity dashicons dashicons-lock'
1275
-                : 'trash-entity dashicons dashicons-post-trash clickable',
1276
-            'reg_list_url'         => $default || ! $datetime->event() instanceof EE_Event
1277
-                ? ''
1278
-                : EE_Admin_Page::add_query_args_and_nonce(
1279
-                    [
1280
-                        'event_id'    => $datetime->event()->ID(),
1281
-                        'datetime_id' => $datetime->ID(),
1282
-                        'use_filters' => true,
1283
-                    ],
1284
-                    REG_ADMIN_URL
1285
-                ),
1286
-        ];
1287
-        $template_args['show_trash'] = count($all_datetimes) === 1
1288
-                                       && $template_args['trash_icon'] !== 'dashicons dashicons-lock'
1289
-            ? 'display:none'
1290
-            : '';
1291
-        // allow filtering of template args at this point.
1292
-        $template_args = apply_filters(
1293
-            'FHEE__espresso_events_Pricing_Hooks___get_dtt_edit_row__template_args',
1294
-            $template_args,
1295
-            $datetime_row,
1296
-            $datetime,
1297
-            $default,
1298
-            $all_datetimes,
1299
-            $this->_is_creating_event
1300
-        );
1301
-        return EEH_Template::display_template(
1302
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_edit_row.template.php',
1303
-            $template_args,
1304
-            true
1305
-        );
1306
-    }
1307
-
1308
-
1309
-    /**
1310
-     * @param int|string       $datetime_row
1311
-     * @param EE_Datetime|null $datetime
1312
-     * @param array            $datetime_tickets
1313
-     * @param array            $all_tickets
1314
-     * @param bool             $default
1315
-     * @return string
1316
-     * @throws DomainException
1317
-     * @throws EE_Error
1318
-     * @throws ReflectionException
1319
-     */
1320
-    protected function _get_dtt_attached_tickets_row(
1321
-        $datetime_row,
1322
-        ?EE_Datetime $datetime,
1323
-        array $datetime_tickets = [],
1324
-        array $all_tickets = [],
1325
-        bool $default = false
1326
-    ): string {
1327
-        $template_args = [
1328
-            'dtt_row'                           => $default
1329
-                ? 'DTTNUM'
1330
-                : $datetime_row,
1331
-            'event_datetimes_name'              => $default
1332
-                ? 'DTTNAMEATTR'
1333
-                : 'edit_event_datetimes',
1334
-            'DTT_description'                   => $default
1335
-                ? ''
1336
-                : $datetime->get_raw('DTT_description'),
1337
-            'datetime_tickets_list'             => $default
1338
-                ? '<li class="hidden"></li>'
1339
-                : '',
1340
-            'show_tickets_row'                  => 'display:none;',
1341
-            'add_new_datetime_ticket_help_link' => EEH_Template::get_help_tab_link(
1342
-                'add_new_ticket_via_datetime',
1343
-                $this->_adminpage_obj->page_slug,
1344
-                $this->_adminpage_obj->get_req_action()
1345
-            ),
1346
-            // todo need to add this help info id to the Events_Admin_Page core file so we can access it here.
1347
-            'DTT_ID'                            => $default
1348
-                ? ''
1349
-                : $datetime->ID(),
1350
-        ];
1351
-        // need to setup the list items (but only if this isn't a default skeleton setup)
1352
-        if (! $default) {
1353
-            $ticket_row = 1;
1354
-            foreach ($all_tickets as $ticket) {
1355
-                $template_args['datetime_tickets_list'] .= $this->_get_datetime_tickets_list_item(
1356
-                    $datetime_row,
1357
-                    $ticket_row,
1358
-                    $datetime,
1359
-                    $ticket,
1360
-                    $datetime_tickets
1361
-                );
1362
-                $ticket_row++;
1363
-            }
1364
-        }
1365
-        // filter template args at this point
1366
-        $template_args = apply_filters(
1367
-            'FHEE__espresso_events_Pricing_Hooks___get_dtt_attached_ticket_row__template_args',
1368
-            $template_args,
1369
-            $datetime_row,
1370
-            $datetime,
1371
-            $datetime_tickets,
1372
-            $all_tickets,
1373
-            $default,
1374
-            $this->_is_creating_event
1375
-        );
1376
-        return EEH_Template::display_template(
1377
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_attached_tickets_row.template.php',
1378
-            $template_args,
1379
-            true
1380
-        );
1381
-    }
1382
-
1383
-
1384
-    /**
1385
-     * @param int|string       $datetime_row
1386
-     * @param int|string       $ticket_row
1387
-     * @param EE_Datetime|null $datetime
1388
-     * @param EE_Ticket|null   $ticket
1389
-     * @param array            $datetime_tickets
1390
-     * @param bool             $default
1391
-     * @return string
1392
-     * @throws EE_Error
1393
-     * @throws ReflectionException
1394
-     */
1395
-    protected function _get_datetime_tickets_list_item(
1396
-        $datetime_row,
1397
-        $ticket_row,
1398
-        ?EE_Datetime $datetime,
1399
-        ?EE_Ticket $ticket,
1400
-        array $datetime_tickets = [],
1401
-        bool $default = false
1402
-    ): string {
1403
-        $datetime_tickets = $datetime instanceof EE_Datetime && isset($datetime_tickets[ $datetime->ID() ])
1404
-            ? $datetime_tickets[ $datetime->ID() ]
1405
-            : [];
1406
-        $display_row      = $ticket instanceof EE_Ticket
1407
-            ? $ticket->get('TKT_row')
1408
-            : 0;
1409
-        $no_ticket        = $default && empty($ticket);
1410
-        $template_args    = [
1411
-            'dtt_row'                 => $default
1412
-                ? 'DTTNUM'
1413
-                : $datetime_row,
1414
-            'tkt_row'                 => $no_ticket
1415
-                ? 'TICKETNUM'
1416
-                : $ticket_row,
1417
-            'datetime_ticket_checked' => in_array($display_row, $datetime_tickets, true)
1418
-                ? ' checked'
1419
-                : '',
1420
-            'ticket_selected'         => in_array($display_row, $datetime_tickets, true)
1421
-                ? ' ticket-selected'
1422
-                : '',
1423
-            'TKT_name'                => $no_ticket
1424
-                ? 'TKTNAME'
1425
-                : $ticket->get('TKT_name'),
1426
-            'tkt_status_class'        => $no_ticket || $this->_is_creating_event
1427
-                ? ' tkt-status-' . EE_Ticket::onsale
1428
-                : ' tkt-status-' . $ticket->ticket_status(),
1429
-        ];
1430
-        // filter template args
1431
-        $template_args = apply_filters(
1432
-            'FHEE__espresso_events_Pricing_Hooks___get_datetime_tickets_list_item__template_args',
1433
-            $template_args,
1434
-            $datetime_row,
1435
-            $ticket_row,
1436
-            $datetime,
1437
-            $ticket,
1438
-            $datetime_tickets,
1439
-            $default,
1440
-            $this->_is_creating_event
1441
-        );
1442
-        return EEH_Template::display_template(
1443
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_dtt_tickets_list.template.php',
1444
-            $template_args,
1445
-            true
1446
-        );
1447
-    }
1448
-
1449
-
1450
-    /**
1451
-     * This generates the ticket row for tickets.
1452
-     * This same method is used to generate both the actual rows and the js skeleton row
1453
-     * (when default === true)
1454
-     *
1455
-     * @param int|string     $ticket_row       Represents the row number being generated.
1456
-     * @param EE_Ticket|null $ticket
1457
-     * @param EE_Datetime[]  $ticket_datetimes Either an array of all datetimes on all tickets indexed by each ticket
1458
-     *                                         or empty for default
1459
-     * @param EE_Datetime[]  $all_datetimes    All Datetimes on the event or empty for default.
1460
-     * @param bool           $default          Whether default row being generated or not.
1461
-     * @param EE_Ticket[]    $all_tickets      This is an array of all tickets attached to the event
1462
-     *                                         (or empty in the case of defaults)
1463
-     * @return string
1464
-     * @throws InvalidArgumentException
1465
-     * @throws InvalidInterfaceException
1466
-     * @throws InvalidDataTypeException
1467
-     * @throws DomainException
1468
-     * @throws EE_Error
1469
-     * @throws ReflectionException
1470
-     */
1471
-    protected function _get_ticket_row(
1472
-        $ticket_row,
1473
-        ?EE_Ticket $ticket,
1474
-        array $ticket_datetimes,
1475
-        array $all_datetimes,
1476
-        bool $default = false,
1477
-        array $all_tickets = []
1478
-    ): string {
1479
-        // if $ticket is not an instance of EE_Ticket then force default to true.
1480
-        $default = ! $ticket instanceof EE_Ticket
1481
-            ? true
1482
-            : $default;
1483
-        $prices  = ! empty($ticket) && ! $default
1484
-            ? $ticket->get_many_related(
1485
-                'Price',
1486
-                ['default_where_conditions' => 'none', 'order_by' => ['PRC_order' => 'ASC']]
1487
-            )
1488
-            : [];
1489
-        // if there is only one price (which would be the base price)
1490
-        // or NO prices and this ticket is a default ticket,
1491
-        // let's just make sure there are no cached default prices on the object.
1492
-        // This is done by not including any query_params.
1493
-        if ($ticket instanceof EE_Ticket && $ticket->is_default() && (count($prices) === 1 || empty($prices))) {
1494
-            $prices = $ticket->prices();
1495
-        }
1496
-        // check if we're dealing with a default ticket in which case
1497
-        // we don't want any starting_ticket_datetime_row values set
1498
-        // (otherwise there won't be any new relationships created for tickets based off of the default ticket).
1499
-        // This will future proof in case there is ever any behaviour change between what the primary_key defaults to.
1500
-        $default_datetime = $default || ($ticket instanceof EE_Ticket && $ticket->is_default());
1501
-        $tkt_datetimes    = $ticket instanceof EE_Ticket && isset($ticket_datetimes[ $ticket->ID() ])
1502
-            ? $ticket_datetimes[ $ticket->ID() ]
1503
-            : [];
1504
-        $ticket_subtotal  = $default
1505
-            ? 0
1506
-            : $ticket->get_ticket_subtotal();
1507
-        $base_price       = $default
1508
-            ? null
1509
-            : $ticket->base_price();
1510
-        $count_price_mods = EEM_Price::instance()->get_all_default_prices(true);
1511
-        // breaking out complicated condition for ticket_status
1512
-        if ($default) {
1513
-            $ticket_status_class = ' tkt-status-' . EE_Ticket::onsale;
1514
-        } else {
1515
-            $ticket_status_class = $ticket->is_default()
1516
-                ? ' tkt-status-' . EE_Ticket::onsale
1517
-                : ' tkt-status-' . $ticket->ticket_status();
1518
-        }
1519
-        // breaking out complicated condition for TKT_taxable
1520
-        if ($default) {
1521
-            $TKT_taxable = '';
1522
-        } else {
1523
-            $TKT_taxable = $ticket->taxable()
1524
-                ? 'checked'
1525
-                : '';
1526
-        }
1527
-        if ($default) {
1528
-            $TKT_status = EEH_Template::pretty_status(EE_Ticket::onsale, false, 'sentence');
1529
-        } elseif ($ticket->is_default()) {
1530
-            $TKT_status = EEH_Template::pretty_status(EE_Ticket::onsale, false, 'sentence');
1531
-        } else {
1532
-            $TKT_status = $ticket->ticket_status(true);
1533
-        }
1534
-        if ($default) {
1535
-            $TKT_min = '';
1536
-        } else {
1537
-            $TKT_min = $ticket->min();
1538
-            if ($TKT_min === -1 || $TKT_min === 0) {
1539
-                $TKT_min = '';
1540
-            }
1541
-        }
1542
-        $template_args                 = [
1543
-            'tkt_row'                       => $default
1544
-                ? 'TICKETNUM'
1545
-                : $ticket_row,
1546
-            'TKT_order'                     => $default
1547
-                ? 'TICKETNUM'
1548
-                : $ticket_row,
1549
-            // on initial page load this will always be the correct order.
1550
-            'tkt_status_class'              => $ticket_status_class,
1551
-            'display_edit_tkt_row'          => 'display:none;',
1552
-            'edit_tkt_expanded'             => '',
1553
-            'edit_tickets_name'             => $default
1554
-                ? 'TICKETNAMEATTR'
1555
-                : 'edit_tickets',
1556
-            'TKT_name'                      => $default
1557
-                ? ''
1558
-                : $ticket->get_f('TKT_name'),
1559
-            'TKT_start_date'                => $default
1560
-                ? ''
1561
-                : $ticket->get_date('TKT_start_date', $this->_date_time_format),
1562
-            'TKT_end_date'                  => $default
1563
-                ? ''
1564
-                : $ticket->get_date('TKT_end_date', $this->_date_time_format),
1565
-            'TKT_status'                    => $TKT_status,
1566
-            'TKT_price'                     => $default
1567
-                ? ''
1568
-                : EEH_Template::format_currency(
1569
-                    $ticket->get_ticket_total_with_taxes(),
1570
-                    false,
1571
-                    false
1572
-                ),
1573
-            'TKT_price_code'                => EE_Registry::instance()->CFG->currency->code,
1574
-            'TKT_price_amount'              => $default
1575
-                ? 0
1576
-                : $ticket_subtotal,
1577
-            'TKT_qty'                       => $default
1578
-                ? ''
1579
-                : $ticket->get_pretty('TKT_qty', 'symbol'),
1580
-            'TKT_qty_for_input'             => $default
1581
-                ? ''
1582
-                : $ticket->get_pretty('TKT_qty', 'input'),
1583
-            'TKT_uses'                      => $default
1584
-                ? ''
1585
-                : $ticket->get_pretty('TKT_uses', 'input'),
1586
-            'TKT_min'                       => $TKT_min,
1587
-            'TKT_max'                       => $default
1588
-                ? ''
1589
-                : $ticket->get_pretty('TKT_max', 'input'),
1590
-            'TKT_sold'                      => $default
1591
-                ? 0
1592
-                : $ticket->tickets_sold(),
1593
-            'TKT_reserved'                  => $default
1594
-                ? 0
1595
-                : $ticket->reserved(),
1596
-            'TKT_registrations'             => $default
1597
-                ? 0
1598
-                : $ticket->count_registrations(
1599
-                    [
1600
-                        [
1601
-                            'STS_ID' => [
1602
-                                '!=',
1603
-                                RegStatus::INCOMPLETE,
1604
-                            ],
1605
-                        ],
1606
-                    ]
1607
-                ),
1608
-            'TKT_ID'                        => $default
1609
-                ? 0
1610
-                : $ticket->ID(),
1611
-            'TKT_description'               => $default
1612
-                ? ''
1613
-                : $ticket->get_raw('TKT_description'),
1614
-            'TKT_is_default'                => $default
1615
-                ? 0
1616
-                : $ticket->is_default(),
1617
-            'TKT_required'                  => $default
1618
-                ? 0
1619
-                : $ticket->required(),
1620
-            'TKT_is_default_selector'       => '',
1621
-            'ticket_price_rows'             => '',
1622
-            'TKT_base_price'                => $default || ! $base_price instanceof EE_Price
1623
-                ? ''
1624
-                : $base_price->get_pretty('PRC_amount', 'localized_float'),
1625
-            'TKT_base_price_ID'             => $default || ! $base_price instanceof EE_Price
1626
-                ? 0
1627
-                : $base_price->ID(),
1628
-            'show_price_modifier'           => count($prices) > 1 || ($default && $count_price_mods > 0)
1629
-                ? ''
1630
-                : 'display:none;',
1631
-            'show_price_mod_button'         => count($prices) > 1
1632
-                                               || ($default && $count_price_mods > 0)
1633
-                                               || (! $default && $ticket->deleted())
1634
-                ? 'display:none;'
1635
-                : '',
1636
-            'total_price_rows'              => count($prices) > 1
1637
-                ? count($prices)
1638
-                : 1,
1639
-            'ticket_datetimes_list'         => $default
1640
-                ? '<li class="hidden"></li>'
1641
-                : '',
1642
-            'starting_ticket_datetime_rows' => $default || $default_datetime
1643
-                ? ''
1644
-                : implode(',', $tkt_datetimes),
1645
-            'ticket_datetime_rows'          => $default
1646
-                ? ''
1647
-                : implode(',', $tkt_datetimes),
1648
-            'existing_ticket_price_ids'     => $default
1649
-                ? ''
1650
-                : implode(',', array_keys($prices)),
1651
-            'ticket_template_id'            => $default
1652
-                ? 0
1653
-                : $ticket->get('TTM_ID'),
1654
-            'TKT_taxable'                   => $TKT_taxable,
1655
-            'display_subtotal'              => $ticket instanceof EE_Ticket && $ticket->taxable()
1656
-                ? ''
1657
-                : 'display:none;',
1658
-            'price_currency_symbol'         => EE_Registry::instance()->CFG->currency->sign,
1659
-            'TKT_subtotal_amount_display'   => EEH_Template::format_currency(
1660
-                $ticket_subtotal,
1661
-                false,
1662
-                false
1663
-            ),
1664
-            'TKT_subtotal_amount'           => $ticket_subtotal,
1665
-            'tax_rows'                      => $this->_get_tax_rows($ticket_row, $ticket),
1666
-            'disabled'                      => $ticket instanceof EE_Ticket && $ticket->deleted(),
1667
-            'ticket_archive_class'          => $ticket instanceof EE_Ticket && $ticket->deleted()
1668
-                ? ' ticket-archived'
1669
-                : '',
1670
-            'trash_icon'                    => $ticket instanceof EE_Ticket
1671
-                                               && $ticket->deleted()
1672
-                                               && ! $ticket->is_permanently_deleteable()
1673
-                ? 'dashicons dashicons-lock '
1674
-                : 'trash-entity dashicons dashicons-post-trash clickable',
1675
-
1676
-            'can_clone' => $ticket instanceof EE_Ticket && ! $ticket->deleted(),
1677
-            'can_trash' => $ticket instanceof EE_Ticket
1678
-                           && (! $ticket->deleted() && $ticket->is_permanently_deleteable()),
1679
-        ];
1680
-        $template_args['trash_hidden'] = count($all_tickets) === 1
1681
-                                         && $template_args['trash_icon'] !== 'dashicons dashicons-lock'
1682
-            ? 'display:none'
1683
-            : '';
1684
-        // handle rows that should NOT be empty
1685
-        if (empty($template_args['TKT_start_date'])) {
1686
-            // if empty then the start date will be now.
1687
-            $template_args['TKT_start_date']   = date(
1688
-                $this->_date_time_format,
1689
-                current_time('timestamp')
1690
-            );
1691
-            $template_args['tkt_status_class'] = ' tkt-status-' . EE_Ticket::onsale;
1692
-        }
1693
-        if (empty($template_args['TKT_end_date'])) {
1694
-            // get the earliest datetime (if present);
1695
-            $earliest_datetime = $this->_adminpage_obj->get_cpt_model_obj()->ID() > 0
1696
-                ? $this->_adminpage_obj->get_cpt_model_obj()->get_first_related(
1697
-                    'Datetime',
1698
-                    ['order_by' => ['DTT_EVT_start' => 'ASC']]
1699
-                )
1700
-                : null;
1701
-            if (! empty($earliest_datetime)) {
1702
-                $template_args['TKT_end_date'] = $earliest_datetime->get_datetime(
1703
-                    'DTT_EVT_start',
1704
-                    $this->_date_time_format
1705
-                );
1706
-            } else {
1707
-                // default so let's just use what's been set for the default date-time which is 30 days from now.
1708
-                $template_args['TKT_end_date'] = date(
1709
-                    $this->_date_time_format,
1710
-                    mktime(
1711
-                        24,
1712
-                        0,
1713
-                        0,
1714
-                        date('m'),
1715
-                        date('d') + 29,
1716
-                        date('Y')
1717
-                    )
1718
-                );
1719
-            }
1720
-            $template_args['tkt_status_class'] = ' tkt-status-' . EE_Ticket::onsale;
1721
-        }
1722
-        // generate ticket_datetime items
1723
-        if (! $default) {
1724
-            $datetime_row = 1;
1725
-            foreach ($all_datetimes as $datetime) {
1726
-                $template_args['ticket_datetimes_list'] .= $this->_get_ticket_datetime_list_item(
1727
-                    $datetime_row,
1728
-                    $ticket_row,
1729
-                    $datetime,
1730
-                    $ticket,
1731
-                    $ticket_datetimes,
1732
-                    $default
1733
-                );
1734
-                $datetime_row++;
1735
-            }
1736
-        }
1737
-        $price_row = 1;
1738
-        foreach ($prices as $price) {
1739
-            if (! $price instanceof EE_Price) {
1740
-                continue;
1741
-            }
1742
-            if ($price->is_base_price()) {
1743
-                $price_row++;
1744
-                continue;
1745
-            }
1746
-
1747
-            $show_trash  = ! ((count($prices) > 1 && $price_row === 1) || count($prices) === 1);
1748
-            $show_create = ! (count($prices) > 1 && count($prices) !== $price_row);
1749
-
1750
-            $template_args['ticket_price_rows'] .= $this->_get_ticket_price_row(
1751
-                $ticket_row,
1752
-                $price_row,
1753
-                $price,
1754
-                $default,
1755
-                $ticket,
1756
-                $show_trash,
1757
-                $show_create
1758
-            );
1759
-            $price_row++;
1760
-        }
1761
-        // filter $template_args
1762
-        $template_args = apply_filters(
1763
-            'FHEE__espresso_events_Pricing_Hooks___get_ticket_row__template_args',
1764
-            $template_args,
1765
-            $ticket_row,
1766
-            $ticket,
1767
-            $ticket_datetimes,
1768
-            $all_datetimes,
1769
-            $default,
1770
-            $all_tickets,
1771
-            $this->_is_creating_event
1772
-        );
1773
-        return EEH_Template::display_template(
1774
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_row.template.php',
1775
-            $template_args,
1776
-            true
1777
-        );
1778
-    }
1779
-
1780
-
1781
-    /**
1782
-     * @param int|string     $ticket_row
1783
-     * @param EE_Ticket|null $ticket
1784
-     * @return string
1785
-     * @throws DomainException
1786
-     * @throws EE_Error
1787
-     * @throws ReflectionException
1788
-     */
1789
-    protected function _get_tax_rows($ticket_row, ?EE_Ticket $ticket): string
1790
-    {
1791
-        $tax_rows = '';
1792
-        /** @var EE_Price[] $taxes */
1793
-        $taxes = EE_Taxes::get_taxes_for_admin();
1794
-        foreach ($taxes as $tax) {
1795
-            $tax_added     = $this->_get_tax_added($tax, $ticket);
1796
-            $template_args = [
1797
-                'display_tax'       => ! empty($ticket) && $ticket->get('TKT_taxable')
1798
-                    ? ''
1799
-                    : 'display:none;',
1800
-                'tax_id'            => $tax->ID(),
1801
-                'tkt_row'           => $ticket_row,
1802
-                'tax_label'         => $tax->get('PRC_name'),
1803
-                'tax_added'         => $tax_added,
1804
-                'tax_added_display' => EEH_Template::format_currency($tax_added, false, false),
1805
-                'tax_amount'        => $tax->get('PRC_amount'),
1806
-            ];
1807
-            $template_args = apply_filters(
1808
-                'FHEE__espresso_events_Pricing_Hooks___get_tax_rows__template_args',
1809
-                $template_args,
1810
-                $ticket_row,
1811
-                $ticket,
1812
-                $this->_is_creating_event
1813
-            );
1814
-            $tax_rows      .= EEH_Template::display_template(
1815
-                PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_tax_row.template.php',
1816
-                $template_args,
1817
-                true
1818
-            );
1819
-        }
1820
-        return $tax_rows;
1821
-    }
1822
-
1823
-
1824
-    /**
1825
-     * @param EE_Price       $tax
1826
-     * @param EE_Ticket|null $ticket
1827
-     * @return float|int
1828
-     * @throws EE_Error
1829
-     * @throws ReflectionException
1830
-     */
1831
-    protected function _get_tax_added(EE_Price $tax, ?EE_Ticket $ticket)
1832
-    {
1833
-        $subtotal = empty($ticket)
1834
-            ? 0
1835
-            : $ticket->get_ticket_subtotal();
1836
-        return $subtotal * $tax->get('PRC_amount') / 100;
1837
-    }
1838
-
1839
-
1840
-    /**
1841
-     * @param int|string     $ticket_row
1842
-     * @param int|string     $price_row
1843
-     * @param EE_Price|null  $price
1844
-     * @param bool           $default
1845
-     * @param EE_Ticket|null $ticket
1846
-     * @param bool           $show_trash
1847
-     * @param bool           $show_create
1848
-     * @return string
1849
-     * @throws InvalidArgumentException
1850
-     * @throws InvalidInterfaceException
1851
-     * @throws InvalidDataTypeException
1852
-     * @throws DomainException
1853
-     * @throws EE_Error
1854
-     * @throws ReflectionException
1855
-     */
1856
-    protected function _get_ticket_price_row(
1857
-        $ticket_row,
1858
-        $price_row,
1859
-        ?EE_Price $price,
1860
-        bool $default,
1861
-        ?EE_Ticket $ticket,
1862
-        bool $show_trash = true,
1863
-        bool $show_create = true
1864
-    ): string {
1865
-        $send_disabled = ! empty($ticket) && $ticket->get('TKT_deleted');
1866
-        $template_args = [
1867
-            'tkt_row'               => $default && empty($ticket)
1868
-                ? 'TICKETNUM'
1869
-                : $ticket_row,
1870
-            'PRC_order'             => $default && empty($price)
1871
-                ? 'PRICENUM'
1872
-                : $price_row,
1873
-            'edit_prices_name'      => $default && empty($price)
1874
-                ? 'PRICENAMEATTR'
1875
-                : 'edit_prices',
1876
-            'price_type_selector'   => $this->_get_price_type_selector(
1877
-                $ticket_row,
1878
-                $price_row,
1879
-                $price,
1880
-                $default,
1881
-                $send_disabled
1882
-            ),
1883
-            'PRC_ID'                => $default && empty($price)
1884
-                ? 0
1885
-                : $price->ID(),
1886
-            'PRC_is_default'        => $default && empty($price)
1887
-                ? 0
1888
-                : $price->get('PRC_is_default'),
1889
-            'PRC_name'              => $default && empty($price)
1890
-                ? ''
1891
-                : $price->get('PRC_name'),
1892
-            'price_currency_symbol' => EE_Registry::instance()->CFG->currency->sign,
1893
-            'show_plus_or_minus'    => $default && empty($price)
1894
-                ? ''
1895
-                : 'display:none;',
1896
-            'show_plus'             => ($default && empty($price)) || ($price->is_discount() || $price->is_base_price())
1897
-                ? 'display:none;'
1898
-                : '',
1899
-            'show_minus'            => ($default && empty($price)) || ! $price->is_discount()
1900
-                ? 'display:none;'
1901
-                : '',
1902
-            'show_currency_symbol'  => ($default && empty($price)) || $price->is_percent()
1903
-                ? 'display:none'
1904
-                : '',
1905
-            'PRC_amount'            => $default && empty($price)
1906
-                ? 0
1907
-                : $price->get_pretty('PRC_amount', 'localized_float'),
1908
-            'show_percentage'       => ($default && empty($price)) || ! $price->is_percent()
1909
-                ? 'display:none;'
1910
-                : '',
1911
-            'show_trash_icon'       => $show_trash
1912
-                ? ''
1913
-                : ' style="display:none;"',
1914
-            'show_create_button'    => $show_create
1915
-                ? ''
1916
-                : ' style="display:none;"',
1917
-            'PRC_desc'              => $default && empty($price)
1918
-                ? ''
1919
-                : $price->get('PRC_desc'),
1920
-            'disabled'              => ! empty($ticket) && $ticket->get('TKT_deleted'),
1921
-        ];
1922
-        $template_args = apply_filters(
1923
-            'FHEE__espresso_events_Pricing_Hooks___get_ticket_price_row__template_args',
1924
-            $template_args,
1925
-            $ticket_row,
1926
-            $price_row,
1927
-            $price,
1928
-            $default,
1929
-            $ticket,
1930
-            $show_trash,
1931
-            $show_create,
1932
-            $this->_is_creating_event
1933
-        );
1934
-        return EEH_Template::display_template(
1935
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_price_row.template.php',
1936
-            $template_args,
1937
-            true
1938
-        );
1939
-    }
1940
-
1941
-
1942
-    /**
1943
-     * @param int|string    $ticket_row
1944
-     * @param int|string    $price_row
1945
-     * @param EE_Price|null $price
1946
-     * @param bool          $default
1947
-     * @param bool          $disabled
1948
-     * @return string
1949
-     * @throws ReflectionException
1950
-     * @throws InvalidArgumentException
1951
-     * @throws InvalidInterfaceException
1952
-     * @throws InvalidDataTypeException
1953
-     * @throws DomainException
1954
-     * @throws EE_Error
1955
-     */
1956
-    protected function _get_price_type_selector(
1957
-        $ticket_row,
1958
-        $price_row,
1959
-        ?EE_Price $price,
1960
-        bool $default,
1961
-        bool $disabled = false
1962
-    ): string {
1963
-        if (($price instanceof EE_Price && $price->is_base_price()) || (! $price instanceof EE_Price && $default)) {
1964
-            return $this->_get_base_price_template(
1965
-                $ticket_row,
1966
-                $price_row,
1967
-                $price,
1968
-                $default
1969
-            );
1970
-        }
1971
-        return $this->_get_price_modifier_template(
1972
-            $ticket_row,
1973
-            $price_row,
1974
-            $price,
1975
-            $default,
1976
-            $disabled
1977
-        );
1978
-    }
1979
-
1980
-
1981
-    /**
1982
-     * @param int|string    $ticket_row
1983
-     * @param int|string    $price_row
1984
-     * @param EE_Price|null $price
1985
-     * @param bool          $default
1986
-     * @return string
1987
-     * @throws DomainException
1988
-     * @throws EE_Error
1989
-     * @throws ReflectionException
1990
-     */
1991
-    protected function _get_base_price_template(
1992
-        $ticket_row,
1993
-        $price_row,
1994
-        ?EE_Price $price,
1995
-        bool $default
1996
-    ): string {
1997
-        $template_args = [
1998
-            'tkt_row'                   => $default
1999
-                ? 'TICKETNUM'
2000
-                : $ticket_row,
2001
-            'PRC_order'                 => $default && empty($price)
2002
-                ? 'PRICENUM'
2003
-                : $price_row,
2004
-            'PRT_ID'                    => $default && empty($price)
2005
-                ? 1
2006
-                : $price->get('PRT_ID'),
2007
-            'PRT_name'                  => esc_html__('Price', 'event_espresso'),
2008
-            'price_selected_operator'   => '+',
2009
-            'price_selected_is_percent' => 0,
2010
-        ];
2011
-        $template_args = apply_filters(
2012
-            'FHEE__espresso_events_Pricing_Hooks___get_base_price_template__template_args',
2013
-            $template_args,
2014
-            $ticket_row,
2015
-            $price_row,
2016
-            $price,
2017
-            $default,
2018
-            $this->_is_creating_event
2019
-        );
2020
-        return EEH_Template::display_template(
2021
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_type_base.template.php',
2022
-            $template_args,
2023
-            true
2024
-        );
2025
-    }
2026
-
2027
-
2028
-    /**
2029
-     * @param int|string    $ticket_row
2030
-     * @param int|string    $price_row
2031
-     * @param EE_Price|null $price
2032
-     * @param bool          $default
2033
-     * @param bool          $disabled
2034
-     * @return string
2035
-     * @throws ReflectionException
2036
-     * @throws InvalidArgumentException
2037
-     * @throws InvalidInterfaceException
2038
-     * @throws InvalidDataTypeException
2039
-     * @throws DomainException
2040
-     * @throws EE_Error
2041
-     */
2042
-    protected function _get_price_modifier_template(
2043
-        $ticket_row,
2044
-        $price_row,
2045
-        ?EE_Price $price,
2046
-        bool $default,
2047
-        bool $disabled = false
2048
-    ): string {
2049
-        $use_default = $default && ! $price instanceof EE_Price;
2050
-        $selected_price_type_id =  $use_default ? 0 : $price->type();
2051
-
2052
-        $select_name = $use_default
2053
-            ? 'edit_prices[TICKETNUM][PRICENUM][PRT_ID]'
2054
-            : 'edit_prices[' . esc_attr($ticket_row) . '][' . esc_attr($price_row) . '][PRT_ID]';
2055
-
2056
-        $price_type_model       = EEM_Price_Type::instance();
2057
-        $price_types = $price_type_model->get_all([['NOT' => ['PBT_ID' => '1']]]);
2058
-        $all_price_types        = $use_default
2059
-            ? [esc_html__('Select Modifier', 'event_espresso')]
2060
-            : [];
2061
-        $price_option_spans     = '';
2062
-        // setup price types for selector
2063
-        foreach ($price_types as $price_type) {
2064
-            if (! $price_type instanceof EE_Price_Type) {
2065
-                continue;
2066
-            }
2067
-            $all_price_types[ $price_type->ID() ] = $price_type->get('PRT_name');
2068
-            // while we're in the loop lets set up the option spans used by js
2069
-            $span_args          = [
2070
-                'PRT_ID'         => $price_type->ID(),
2071
-                'PRT_operator'   => $price_type->is_discount()
2072
-                    ? '-'
2073
-                    : '+',
2074
-                'PRT_is_percent' => $price_type->get('PRT_is_percent')
2075
-                    ? 1
2076
-                    : 0,
2077
-            ];
2078
-            $price_option_spans .= EEH_Template::display_template(
2079
-                PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_option_span.template.php',
2080
-                $span_args,
2081
-                true
2082
-            );
2083
-        }
2084
-
2085
-        $select_name = $disabled
2086
-            ? 'archive_price[' . $ticket_row . '][' . $price_row . '][PRT_ID]'
2087
-            : $select_name;
2088
-
2089
-        $select_input = new EE_Select_Input(
2090
-            $all_price_types,
2091
-            [
2092
-                'default'               => $selected_price_type_id,
2093
-                'html_name'             => $select_name,
2094
-                'html_class'            => 'edit-price-PRT_ID',
2095
-                'other_html_attributes' => $disabled
2096
-                    ? 'style="width:auto;" disabled'
2097
-                    : 'style="width:auto;"',
2098
-            ]
2099
-        );
2100
-
2101
-        $price_selected_operator   = $price instanceof EE_Price && $price->is_discount()
2102
-            ? '-'
2103
-            : '+';
2104
-        $price_selected_operator   = $use_default
2105
-            ? ''
2106
-            : $price_selected_operator;
2107
-        $price_selected_is_percent = $price instanceof EE_Price && $price->is_percent()
2108
-            ? 1
2109
-            : 0;
2110
-        $price_selected_is_percent = $use_default
2111
-            ? ''
2112
-            : $price_selected_is_percent;
2113
-        $template_args             = [
2114
-            'tkt_row'                   => $default
2115
-                ? 'TICKETNUM'
2116
-                : $ticket_row,
2117
-            'PRC_order'                 => $use_default
2118
-                ? 'PRICENUM'
2119
-                : $price_row,
2120
-            'price_modifier_selector'   => $select_input->get_html_for_input(),
2121
-            'main_name'                 => $select_name,
2122
-            'selected_price_type_id'    => $selected_price_type_id,
2123
-            'price_option_spans'        => $price_option_spans,
2124
-            'price_selected_operator'   => $price_selected_operator,
2125
-            'price_selected_is_percent' => $price_selected_is_percent,
2126
-            'disabled'                  => $disabled,
2127
-        ];
2128
-        $template_args             = apply_filters(
2129
-            'FHEE__espresso_events_Pricing_Hooks___get_price_modifier_template__template_args',
2130
-            $template_args,
2131
-            $ticket_row,
2132
-            $price_row,
2133
-            $price,
2134
-            $default,
2135
-            $disabled,
2136
-            $this->_is_creating_event
2137
-        );
2138
-        return EEH_Template::display_template(
2139
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_modifier_selector.template.php',
2140
-            $template_args,
2141
-            true
2142
-        );
2143
-    }
2144
-
2145
-
2146
-    /**
2147
-     * @param int|string       $datetime_row
2148
-     * @param int|string       $ticket_row
2149
-     * @param EE_Datetime|null $datetime
2150
-     * @param EE_Ticket|null   $ticket
2151
-     * @param array            $ticket_datetimes
2152
-     * @param bool             $default
2153
-     * @return string
2154
-     * @throws DomainException
2155
-     * @throws EE_Error
2156
-     * @throws ReflectionException
2157
-     */
2158
-    protected function _get_ticket_datetime_list_item(
2159
-        $datetime_row,
2160
-        $ticket_row,
2161
-        ?EE_Datetime $datetime,
2162
-        ?EE_Ticket $ticket,
2163
-        array $ticket_datetimes = [],
2164
-        bool $default = false
2165
-    ): string {
2166
-        $tkt_datetimes = $ticket instanceof EE_Ticket && isset($ticket_datetimes[ $ticket->ID() ])
2167
-            ? $ticket_datetimes[ $ticket->ID() ]
2168
-            : [];
2169
-        $template_args = [
2170
-            'dtt_row'                  => $default && ! $datetime instanceof EE_Datetime
2171
-                ? 'DTTNUM'
2172
-                : $datetime_row,
2173
-            'tkt_row'                  => $default
2174
-                ? 'TICKETNUM'
2175
-                : $ticket_row,
2176
-            'ticket_datetime_selected' => in_array($datetime_row, $tkt_datetimes, true)
2177
-                ? ' ticket-selected'
2178
-                : '',
2179
-            'ticket_datetime_checked'  => in_array($datetime_row, $tkt_datetimes, true)
2180
-                ? ' checked'
2181
-                : '',
2182
-            'DTT_name'                 => $default && empty($datetime)
2183
-                ? 'DTTNAME'
2184
-                : $datetime->get_dtt_display_name(true),
2185
-            'tkt_status_class'         => '',
2186
-        ];
2187
-        $template_args = apply_filters(
2188
-            'FHEE__espresso_events_Pricing_Hooks___get_ticket_datetime_list_item__template_args',
2189
-            $template_args,
2190
-            $datetime_row,
2191
-            $ticket_row,
2192
-            $datetime,
2193
-            $ticket,
2194
-            $ticket_datetimes,
2195
-            $default,
2196
-            $this->_is_creating_event
2197
-        );
2198
-        return EEH_Template::display_template(
2199
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_datetimes_list_item.template.php',
2200
-            $template_args,
2201
-            true
2202
-        );
2203
-    }
2204
-
2205
-
2206
-    /**
2207
-     * @param array $all_datetimes
2208
-     * @param array $all_tickets
2209
-     * @return string
2210
-     * @throws ReflectionException
2211
-     * @throws InvalidArgumentException
2212
-     * @throws InvalidInterfaceException
2213
-     * @throws InvalidDataTypeException
2214
-     * @throws DomainException
2215
-     * @throws EE_Error
2216
-     */
2217
-    protected function _get_ticket_js_structure(array $all_datetimes = [], array $all_tickets = []): string
2218
-    {
2219
-        $template_args = [
2220
-            'default_datetime_edit_row' => $this->_get_dtt_edit_row(
2221
-                'DTTNUM',
2222
-                null,
2223
-                true,
2224
-                $all_datetimes
2225
-            ),
2226
-            'default_ticket_row'        => $this->_get_ticket_row(
2227
-                'TICKETNUM',
2228
-                null,
2229
-                [],
2230
-                [],
2231
-                true
2232
-            ),
2233
-            'default_price_row'         => $this->_get_ticket_price_row(
2234
-                'TICKETNUM',
2235
-                'PRICENUM',
2236
-                null,
2237
-                true,
2238
-                null
2239
-            ),
2240
-
2241
-            'default_price_rows'                       => '',
2242
-            'default_base_price_amount'                => 0,
2243
-            'default_base_price_name'                  => '',
2244
-            'default_base_price_description'           => '',
2245
-            'default_price_modifier_selector_row'      => $this->_get_price_modifier_template(
2246
-                'TICKETNUM',
2247
-                'PRICENUM',
2248
-                null,
2249
-                true
2250
-            ),
2251
-            'default_available_tickets_for_datetime'   => $this->_get_dtt_attached_tickets_row(
2252
-                'DTTNUM',
2253
-                null,
2254
-                [],
2255
-                [],
2256
-                true
2257
-            ),
2258
-            'existing_available_datetime_tickets_list' => '',
2259
-            'existing_available_ticket_datetimes_list' => '',
2260
-            'new_available_datetime_ticket_list_item'  => $this->_get_datetime_tickets_list_item(
2261
-                'DTTNUM',
2262
-                'TICKETNUM',
2263
-                null,
2264
-                null,
2265
-                [],
2266
-                true
2267
-            ),
2268
-            'new_available_ticket_datetime_list_item'  => $this->_get_ticket_datetime_list_item(
2269
-                'DTTNUM',
2270
-                'TICKETNUM',
2271
-                null,
2272
-                null,
2273
-                [],
2274
-                true
2275
-            ),
2276
-        ];
2277
-        $ticket_row    = 1;
2278
-        foreach ($all_tickets as $ticket) {
2279
-            $template_args['existing_available_datetime_tickets_list'] .= $this->_get_datetime_tickets_list_item(
2280
-                'DTTNUM',
2281
-                $ticket_row,
2282
-                null,
2283
-                $ticket,
2284
-                [],
2285
-                true
2286
-            );
2287
-            $ticket_row++;
2288
-        }
2289
-        $datetime_row = 1;
2290
-        foreach ($all_datetimes as $datetime) {
2291
-            $template_args['existing_available_ticket_datetimes_list'] .= $this->_get_ticket_datetime_list_item(
2292
-                $datetime_row,
2293
-                'TICKETNUM',
2294
-                $datetime,
2295
-                null,
2296
-                [],
2297
-                true
2298
-            );
2299
-            $datetime_row++;
2300
-        }
2301
-        $price_model    = EEM_Price::instance();
2302
-        $default_prices = $price_model->get_all_default_prices();
2303
-        $price_row      = 1;
2304
-        foreach ($default_prices as $price) {
2305
-            if (! $price instanceof EE_Price) {
2306
-                continue;
2307
-            }
2308
-            if ($price->is_base_price()) {
2309
-                $template_args['default_base_price_amount']      = $price->get_pretty(
2310
-                    'PRC_amount',
2311
-                    'localized_float'
2312
-                );
2313
-                $template_args['default_base_price_name']        = $price->get('PRC_name');
2314
-                $template_args['default_base_price_description'] = $price->get('PRC_desc');
2315
-                $price_row++;
2316
-                continue;
2317
-            }
2318
-
2319
-            $show_trash  = ! ((count($default_prices) > 1 && $price_row === 1) || count($default_prices) === 1);
2320
-            $show_create = ! (count($default_prices) > 1 && count($default_prices) !== $price_row);
2321
-
2322
-            $template_args['default_price_rows'] .= $this->_get_ticket_price_row(
2323
-                'TICKETNUM',
2324
-                $price_row,
2325
-                $price,
2326
-                true,
2327
-                null,
2328
-                $show_trash,
2329
-                $show_create
2330
-            );
2331
-            $price_row++;
2332
-        }
2333
-        $template_args = apply_filters(
2334
-            'FHEE__espresso_events_Pricing_Hooks___get_ticket_js_structure__template_args',
2335
-            $template_args,
2336
-            $all_datetimes,
2337
-            $all_tickets,
2338
-            $this->_is_creating_event
2339
-        );
2340
-        return EEH_Template::display_template(
2341
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_js_structure.template.php',
2342
-            $template_args,
2343
-            true
2344
-        );
2345
-    }
232
+					],
233
+					'DTT_OVERSELL_WARNING'  => [
234
+						'datetime_ticket' => esc_html__(
235
+							'You cannot add this ticket to this datetime because it has a sold amount that is greater than the amount of spots remaining for this datetime.',
236
+							'event_espresso'
237
+						),
238
+						'ticket_datetime' => esc_html__(
239
+							'You cannot add this datetime to this ticket because the ticket has a sold amount that is greater than the amount of spots remaining on the datetime.',
240
+							'event_espresso'
241
+						),
242
+					],
243
+					'DTT_CONVERTED_FORMATS' => EEH_DTT_Helper::convert_php_to_js_and_moment_date_formats(
244
+						$this->_date_format_strings['date'],
245
+						$this->_date_format_strings['time']
246
+					),
247
+					'DTT_START_OF_WEEK'     => ['dayValue' => (int) get_option('start_of_week')],
248
+				],
249
+			],
250
+		];
251
+	}
252
+
253
+
254
+	/**
255
+	 * @param array $update_callbacks
256
+	 * @return array
257
+	 */
258
+	public function caf_updates(array $update_callbacks): array
259
+	{
260
+		unset($update_callbacks['_default_tickets_update']);
261
+		$update_callbacks['datetime_and_tickets_caf_update'] = [$this, 'datetime_and_tickets_caf_update'];
262
+		return $update_callbacks;
263
+	}
264
+
265
+
266
+	/**
267
+	 * Handles saving everything related to Tickets (datetimes, tickets, prices)
268
+	 *
269
+	 * @param EE_Event $event The Event object we're attaching data to
270
+	 * @param array    $data  The request data from the form
271
+	 * @throws ReflectionException
272
+	 * @throws Exception
273
+	 * @throws InvalidInterfaceException
274
+	 * @throws InvalidDataTypeException
275
+	 * @throws EE_Error
276
+	 * @throws InvalidArgumentException
277
+	 */
278
+	public function datetime_and_tickets_caf_update(EE_Event $event, array $data)
279
+	{
280
+		// first we need to start with datetimes cause they are the "root" items attached to events.
281
+		$saved_datetimes = $this->_update_datetimes($event, $data);
282
+		// next tackle the tickets (and prices?)
283
+		$this->_update_tickets($event, $saved_datetimes, $data);
284
+	}
285
+
286
+
287
+	/**
288
+	 * update event_datetimes
289
+	 *
290
+	 * @param EE_Event $event Event being updated
291
+	 * @param array    $data  the request data from the form
292
+	 * @return EE_Datetime[]
293
+	 * @throws Exception
294
+	 * @throws ReflectionException
295
+	 * @throws InvalidInterfaceException
296
+	 * @throws InvalidDataTypeException
297
+	 * @throws InvalidArgumentException
298
+	 * @throws EE_Error
299
+	 */
300
+	protected function _update_datetimes(EE_Event $event, array $data): array
301
+	{
302
+		$saved_datetime_ids  = [];
303
+		$saved_datetime_objs = [];
304
+		$timezone            = $data['timezone_string'] ?? null;
305
+		$datetime_model      = EEM_Datetime::instance($timezone);
306
+
307
+		if (empty($data['edit_event_datetimes']) || ! is_array($data['edit_event_datetimes'])) {
308
+			throw new InvalidArgumentException(
309
+				esc_html__(
310
+					'The "edit_event_datetimes" array is invalid therefore the event can not be updated.',
311
+					'event_espresso'
312
+				)
313
+			);
314
+		}
315
+		foreach ($data['edit_event_datetimes'] as $row => $datetime_data) {
316
+			// trim all values to ensure any excess whitespace is removed.
317
+			$datetime_data = array_map(
318
+				function ($datetime_data) {
319
+					return is_array($datetime_data)
320
+						? $datetime_data
321
+						: trim($datetime_data);
322
+				},
323
+				$datetime_data
324
+			);
325
+
326
+			$datetime_data['DTT_EVT_end'] = isset($datetime_data['DTT_EVT_end'])
327
+											&& ! empty($datetime_data['DTT_EVT_end'])
328
+				? $datetime_data['DTT_EVT_end']
329
+				: $datetime_data['DTT_EVT_start'];
330
+			$datetime_values              = [
331
+				'DTT_ID'          => ! empty($datetime_data['DTT_ID'])
332
+					? $datetime_data['DTT_ID']
333
+					: null,
334
+				'DTT_name'        => ! empty($datetime_data['DTT_name'])
335
+					? $datetime_data['DTT_name']
336
+					: '',
337
+				'DTT_description' => ! empty($datetime_data['DTT_description'])
338
+					? $datetime_data['DTT_description']
339
+					: '',
340
+				'DTT_EVT_start'   => $datetime_data['DTT_EVT_start'],
341
+				'DTT_EVT_end'     => $datetime_data['DTT_EVT_end'],
342
+				'DTT_reg_limit'   => empty($datetime_data['DTT_reg_limit'])
343
+					? EE_INF
344
+					: $datetime_data['DTT_reg_limit'],
345
+				'DTT_order'       => ! isset($datetime_data['DTT_order'])
346
+					? $row
347
+					: $datetime_data['DTT_order'],
348
+			];
349
+
350
+			// if we have an id then let's get existing object first and then set the new values.
351
+			// Otherwise we instantiate a new object for save.
352
+			if (! empty($datetime_data['DTT_ID'])) {
353
+				$datetime = EE_Registry::instance()
354
+									   ->load_model('Datetime', [$timezone])
355
+									   ->get_one_by_ID($datetime_data['DTT_ID']);
356
+				// set date and time format according to what is set in this class.
357
+				$datetime->set_date_format($this->_date_format_strings['date']);
358
+				$datetime->set_time_format($this->_date_format_strings['time']);
359
+				foreach ($datetime_values as $field => $value) {
360
+					$datetime->set($field, $value);
361
+				}
362
+
363
+				// make sure the $datetime_id here is saved just in case
364
+				// after the add_relation_to() the autosave replaces it.
365
+				// We need to do this so we dont' TRASH the parent DTT.
366
+				// (save the ID for both key and value to avoid duplications)
367
+				$saved_datetime_ids[ $datetime->ID() ] = $datetime->ID();
368
+			} else {
369
+				$datetime = EE_Datetime::new_instance(
370
+					$datetime_values,
371
+					$timezone,
372
+					[$this->_date_format_strings['date'], $this->_date_format_strings['time']]
373
+				);
374
+				foreach ($datetime_values as $field => $value) {
375
+					$datetime->set($field, $value);
376
+				}
377
+			}
378
+			$datetime->save();
379
+			do_action(
380
+				'AHEE__espresso_events_Pricing_Hooks___update_datetimes_after_save',
381
+				$datetime,
382
+				$row,
383
+				$datetime_data,
384
+				$data
385
+			);
386
+			$datetime = $event->_add_relation_to($datetime, 'Datetime');
387
+			// before going any further make sure our dates are setup correctly
388
+			// so that the end date is always equal or greater than the start date.
389
+			if ($datetime->get_raw('DTT_EVT_start') > $datetime->get_raw('DTT_EVT_end')) {
390
+				$datetime->set('DTT_EVT_end', $datetime->get('DTT_EVT_start'));
391
+				$datetime = EEH_DTT_Helper::date_time_add($datetime, 'DTT_EVT_end', 'days');
392
+				$datetime->save();
393
+			}
394
+			// now we have to make sure we add the new DTT_ID to the $saved_datetime_ids array
395
+			// because it is possible there was a new one created for the autosave.
396
+			// (save the ID for both key and value to avoid duplications)
397
+			$DTT_ID                        = $datetime->ID();
398
+			$saved_datetime_ids[ $DTT_ID ] = $DTT_ID;
399
+			$saved_datetime_objs[ $row ]   = $datetime;
400
+			// @todo if ANY of these updates fail then we want the appropriate global error message.
401
+		}
402
+		$event->save();
403
+		// now we need to REMOVE any datetimes that got deleted.
404
+		// Keep in mind that this process will only kick in for datetimes that don't have any DTT_sold on them.
405
+		// So its safe to permanently delete at this point.
406
+		$old_datetimes = explode(',', $data['datetime_IDs']);
407
+		$old_datetimes = $old_datetimes[0] === ''
408
+			? []
409
+			: $old_datetimes;
410
+		if (is_array($old_datetimes)) {
411
+			$datetimes_to_delete = array_diff($old_datetimes, $saved_datetime_ids);
412
+			foreach ($datetimes_to_delete as $id) {
413
+				$id = absint($id);
414
+				if (empty($id)) {
415
+					continue;
416
+				}
417
+				$dtt_to_remove = $datetime_model->get_one_by_ID($id);
418
+				// remove tkt relationships.
419
+				$related_tickets = $dtt_to_remove->get_many_related('Ticket');
420
+				foreach ($related_tickets as $ticket) {
421
+					$dtt_to_remove->_remove_relation_to($ticket, 'Ticket');
422
+				}
423
+				$event->_remove_relation_to($id, 'Datetime');
424
+				$dtt_to_remove->refresh_cache_of_related_objects();
425
+			}
426
+		}
427
+		return $saved_datetime_objs;
428
+	}
429
+
430
+
431
+	/**
432
+	 * update tickets
433
+	 *
434
+	 * @param EE_Event      $event           Event object being updated
435
+	 * @param EE_Datetime[] $saved_datetimes an array of datetime ids being updated
436
+	 * @param array         $data            incoming request data
437
+	 * @return EE_Ticket[]
438
+	 * @throws Exception
439
+	 * @throws ReflectionException
440
+	 * @throws InvalidInterfaceException
441
+	 * @throws InvalidDataTypeException
442
+	 * @throws InvalidArgumentException
443
+	 * @throws EE_Error
444
+	 */
445
+	protected function _update_tickets(EE_Event $event, array $saved_datetimes, array $data): array
446
+	{
447
+		$new_ticket = null;
448
+		// stripslashes because WP filtered the $_POST ($data) array to add slashes
449
+		$data         = stripslashes_deep($data);
450
+		$timezone     = $data['timezone_string'] ?? null;
451
+		$ticket_model = EEM_Ticket::instance($timezone);
452
+
453
+		$saved_tickets = [];
454
+		$old_tickets   = isset($data['ticket_IDs'])
455
+			? explode(',', $data['ticket_IDs'])
456
+			: [];
457
+		if (empty($data['edit_tickets']) || ! is_array($data['edit_tickets'])) {
458
+			throw new InvalidArgumentException(
459
+				esc_html__(
460
+					'The "edit_tickets" array is invalid therefore the event can not be updated.',
461
+					'event_espresso'
462
+				)
463
+			);
464
+		}
465
+		foreach ($data['edit_tickets'] as $row => $ticket_data) {
466
+			$update_prices = $create_new_TKT = false;
467
+			// figure out what datetimes were added to the ticket
468
+			// and what datetimes were removed from the ticket in the session.
469
+			$starting_ticket_datetime_rows = explode(',', $data['starting_ticket_datetime_rows'][ $row ]);
470
+			$ticket_datetime_rows          = explode(',', $data['ticket_datetime_rows'][ $row ]);
471
+			$datetimes_added               = array_diff($ticket_datetime_rows, $starting_ticket_datetime_rows);
472
+			$datetimes_removed             = array_diff($starting_ticket_datetime_rows, $ticket_datetime_rows);
473
+			// trim inputs to ensure any excess whitespace is removed.
474
+			$ticket_data = array_map(
475
+				function ($ticket_data) {
476
+					return is_array($ticket_data)
477
+						? $ticket_data
478
+						: trim($ticket_data);
479
+				},
480
+				$ticket_data
481
+			);
482
+			// note we are doing conversions to floats here instead of allowing EE_Money_Field to handle
483
+			// because we're doing calculations prior to using the models.
484
+			// note incoming ['TKT_price'] value is already in standard notation (via js).
485
+			$ticket_price = isset($ticket_data['TKT_price'])
486
+				? round((float) $ticket_data['TKT_price'], 3)
487
+				: 0;
488
+			// note incoming base price needs converted from localized value.
489
+			$base_price = isset($ticket_data['TKT_base_price'])
490
+				? EEH_Money::convert_to_float_from_localized_money($ticket_data['TKT_base_price'])
491
+				: 0;
492
+			// if ticket price == 0 and $base_price != 0 then ticket price == base_price
493
+			$ticket_price  = $ticket_price === 0 && $base_price !== 0
494
+				? $base_price
495
+				: $ticket_price;
496
+			$base_price_id = $ticket_data['TKT_base_price_ID'] ?? 0;
497
+			$price_rows    = is_array($data['edit_prices']) && isset($data['edit_prices'][ $row ])
498
+				? $data['edit_prices'][ $row ]
499
+				: [];
500
+			$now           = null;
501
+			if (empty($ticket_data['TKT_start_date'])) {
502
+				// lets' use now in the set timezone.
503
+				$now                           = new DateTime('now', new DateTimeZone($event->get_timezone()));
504
+				$ticket_data['TKT_start_date'] = $now->format($this->_date_time_format);
505
+			}
506
+			if (empty($ticket_data['TKT_end_date'])) {
507
+				/**
508
+				 * set the TKT_end_date to the first datetime attached to the ticket.
509
+				 */
510
+				$first_datetime              = $saved_datetimes[ reset($ticket_datetime_rows) ];
511
+				$ticket_data['TKT_end_date'] = $first_datetime->start_date_and_time($this->_date_time_format);
512
+			}
513
+			$TKT_values = [
514
+				'TKT_ID'          => ! empty($ticket_data['TKT_ID'])
515
+					? $ticket_data['TKT_ID']
516
+					: null,
517
+				'TTM_ID'          => ! empty($ticket_data['TTM_ID'])
518
+					? $ticket_data['TTM_ID']
519
+					: 0,
520
+				'TKT_name'        => ! empty($ticket_data['TKT_name'])
521
+					? $ticket_data['TKT_name']
522
+					: '',
523
+				'TKT_description' => ! empty($ticket_data['TKT_description'])
524
+									 && $ticket_data['TKT_description'] !== esc_html__(
525
+										 'You can modify this description',
526
+										 'event_espresso'
527
+									 )
528
+					? $ticket_data['TKT_description']
529
+					: '',
530
+				'TKT_start_date'  => $ticket_data['TKT_start_date'],
531
+				'TKT_end_date'    => $ticket_data['TKT_end_date'],
532
+				'TKT_qty'         => ! isset($ticket_data['TKT_qty']) || $ticket_data['TKT_qty'] === ''
533
+					? EE_INF
534
+					: $ticket_data['TKT_qty'],
535
+				'TKT_uses'        => ! isset($ticket_data['TKT_uses']) || $ticket_data['TKT_uses'] === ''
536
+					? EE_INF
537
+					: $ticket_data['TKT_uses'],
538
+				'TKT_min'         => empty($ticket_data['TKT_min'])
539
+					? 0
540
+					: $ticket_data['TKT_min'],
541
+				'TKT_max'         => empty($ticket_data['TKT_max'])
542
+					? EE_INF
543
+					: $ticket_data['TKT_max'],
544
+				'TKT_row'         => $row,
545
+				'TKT_order'       => $ticket_data['TKT_order'] ?? 0,
546
+				'TKT_taxable'     => ! empty($ticket_data['TKT_taxable'])
547
+					? 1
548
+					: 0,
549
+				'TKT_required'    => ! empty($ticket_data['TKT_required'])
550
+					? 1
551
+					: 0,
552
+				'TKT_price'       => $ticket_price,
553
+			];
554
+			// if this is a default TKT, then we need to set the TKT_ID to 0 and update accordingly,
555
+			// which means in turn that the prices will become new prices as well.
556
+			if (isset($ticket_data['TKT_is_default']) && $ticket_data['TKT_is_default']) {
557
+				$TKT_values['TKT_ID']         = 0;
558
+				$TKT_values['TKT_is_default'] = 0;
559
+				$update_prices                = true;
560
+			}
561
+			// if we have a TKT_ID then we need to get that existing TKT_obj and update it
562
+			// we actually do our saves ahead of doing any add_relations to
563
+			// because its entirely possible that this ticket wasn't removed or added to any datetime in the session
564
+			// but DID have it's items modified.
565
+			// keep in mind that if the TKT has been sold (and we have changed pricing information),
566
+			// then we won't be updating the ticket but instead a new ticket will be created and the old one archived.
567
+			if (absint($TKT_values['TKT_ID'])) {
568
+				$ticket = EE_Registry::instance()
569
+									 ->load_model('Ticket', [$timezone])
570
+									 ->get_one_by_ID($TKT_values['TKT_ID']);
571
+				if ($ticket instanceof EE_Ticket) {
572
+					$ticket = $this->_update_ticket_datetimes(
573
+						$ticket,
574
+						$saved_datetimes,
575
+						$datetimes_added,
576
+						$datetimes_removed
577
+					);
578
+					// are there any registrations using this ticket ?
579
+					$tickets_sold = $ticket->count_related(
580
+						'Registration',
581
+						[
582
+							[
583
+								'STS_ID' => ['NOT IN', [RegStatus::INCOMPLETE]],
584
+							],
585
+						]
586
+					);
587
+					// set ticket formats
588
+					$ticket->set_date_format($this->_date_format_strings['date']);
589
+					$ticket->set_time_format($this->_date_format_strings['time']);
590
+					// let's just check the total price for the existing ticket
591
+					// and determine if it matches the new total price.
592
+					// if they are different then we create a new ticket (if tickets sold)
593
+					// if they aren't different then we go ahead and modify existing ticket.
594
+					$create_new_TKT = $tickets_sold > 0 && $ticket_price !== $ticket->price() && ! $ticket->deleted();
595
+					// set new values
596
+					foreach ($TKT_values as $field => $value) {
597
+						if ($field === 'TKT_qty') {
598
+							$ticket->set_qty($value);
599
+						} else {
600
+							$ticket->set($field, $value);
601
+						}
602
+					}
603
+					// if $create_new_TKT is false then we can safely update the existing ticket.
604
+					// Otherwise we have to create a new ticket.
605
+					if ($create_new_TKT) {
606
+						$new_ticket = $this->_duplicate_ticket(
607
+							$ticket,
608
+							$price_rows,
609
+							$ticket_price,
610
+							$base_price,
611
+							$base_price_id
612
+						);
613
+					}
614
+				}
615
+			} else {
616
+				// no TKT_id so a new TKT
617
+				$ticket = EE_Ticket::new_instance(
618
+					$TKT_values,
619
+					$timezone,
620
+					[$this->_date_format_strings['date'], $this->_date_format_strings['time']]
621
+				);
622
+				if ($ticket instanceof EE_Ticket) {
623
+					// make sure ticket has an ID of setting relations won't work
624
+					$ticket->save();
625
+					$ticket        = $this->_update_ticket_datetimes(
626
+						$ticket,
627
+						$saved_datetimes,
628
+						$datetimes_added,
629
+						$datetimes_removed
630
+					);
631
+					$update_prices = true;
632
+				}
633
+			}
634
+			// make sure any current values have been saved.
635
+			// $ticket->save();
636
+			// before going any further make sure our dates are setup correctly
637
+			// so that the end date is always equal or greater than the start date.
638
+			if ($ticket->get_raw('TKT_start_date') > $ticket->get_raw('TKT_end_date')) {
639
+				$ticket->set('TKT_end_date', $ticket->get('TKT_start_date'));
640
+				$ticket = EEH_DTT_Helper::date_time_add($ticket, 'TKT_end_date', 'days');
641
+			}
642
+			// let's make sure the base price is handled
643
+			$ticket = ! $create_new_TKT
644
+				? $this->_add_prices_to_ticket(
645
+					[],
646
+					$ticket,
647
+					$update_prices,
648
+					$base_price,
649
+					$base_price_id
650
+				)
651
+				: $ticket;
652
+			// add/update price_modifiers
653
+			$ticket = ! $create_new_TKT
654
+				? $this->_add_prices_to_ticket($price_rows, $ticket, $update_prices)
655
+				: $ticket;
656
+			// need to make sue that the TKT_price is accurate after saving the prices.
657
+			$ticket->ensure_TKT_Price_correct();
658
+			// handle CREATING a default ticket from the incoming ticket but ONLY if this isn't an autosave.
659
+			if (! defined('DOING_AUTOSAVE') && ! empty($ticket_data['TKT_is_default_selector'])) {
660
+				$new_default = clone $ticket;
661
+				$new_default->set('TKT_ID', 0);
662
+				$new_default->set('TKT_is_default', 1);
663
+				$new_default->set('TKT_row', 1);
664
+				$new_default->set('TKT_price', $ticket_price);
665
+				// remove any datetime relations cause we DON'T want datetime relations attached
666
+				// (note this is just removing the cached relations in the object)
667
+				$new_default->_remove_relations('Datetime');
668
+				// @todo we need to add the current attached prices as new prices to the new default ticket.
669
+				$new_default = $this->_add_prices_to_ticket(
670
+					$price_rows,
671
+					$new_default,
672
+					true
673
+				);
674
+				// don't forget the base price!
675
+				$new_default = $this->_add_prices_to_ticket(
676
+					[],
677
+					$new_default,
678
+					true,
679
+					$base_price,
680
+					$base_price_id
681
+				);
682
+				$new_default->save();
683
+				do_action(
684
+					'AHEE__espresso_events_Pricing_Hooks___update_tkts_new_default_ticket',
685
+					$new_default,
686
+					$row,
687
+					$ticket,
688
+					$data
689
+				);
690
+			}
691
+			// DO ALL datetime relationships for both current tickets and any archived tickets
692
+			// for the given datetime that are related to the current ticket.
693
+			// TODO... not sure exactly how we're going to do this considering we don't know
694
+			// what current ticket the archived tickets are related to
695
+			// (and TKT_parent is used for autosaves so that's not a field we can reliably use).
696
+			// let's assign any tickets that have been setup to the saved_tickets tracker
697
+			// save existing TKT
698
+			$ticket->save();
699
+			if ($create_new_TKT && $new_ticket instanceof EE_Ticket) {
700
+				// save new TKT
701
+				$new_ticket->save();
702
+				// add new ticket to array
703
+				$saved_tickets[ $new_ticket->ID() ] = $new_ticket;
704
+				do_action(
705
+					'AHEE__espresso_events_Pricing_Hooks___update_tkts_new_ticket',
706
+					$new_ticket,
707
+					$row,
708
+					$ticket_data,
709
+					$data
710
+				);
711
+			} else {
712
+				// add ticket to saved tickets
713
+				$saved_tickets[ $ticket->ID() ] = $ticket;
714
+				do_action(
715
+					'AHEE__espresso_events_Pricing_Hooks___update_tkts_update_ticket',
716
+					$ticket,
717
+					$row,
718
+					$ticket_data,
719
+					$data
720
+				);
721
+			}
722
+		}
723
+		// now we need to handle tickets actually "deleted permanently".
724
+		// There are cases where we'd want this to happen
725
+		// (i.e. autosaves are happening and then in between autosaves the user trashes a ticket).
726
+		// Or a draft event was saved and in the process of editing a ticket is trashed.
727
+		// No sense in keeping all the related data in the db!
728
+		$old_tickets     = isset($old_tickets[0]) && $old_tickets[0] === ''
729
+			? []
730
+			: $old_tickets;
731
+		$tickets_removed = array_diff($old_tickets, array_keys($saved_tickets));
732
+		foreach ($tickets_removed as $id) {
733
+			$id = absint($id);
734
+			// get the ticket for this id
735
+			$ticket_to_remove = $ticket_model->get_one_by_ID($id);
736
+			// if this tkt is a default tkt we leave it alone cause it won't be attached to the datetime
737
+			if ($ticket_to_remove->get('TKT_is_default')) {
738
+				continue;
739
+			}
740
+			// if this ticket has any registrations attached so then we just ARCHIVE
741
+			// because we don't actually permanently delete these tickets.
742
+			if ($ticket_to_remove->count_related('Registration') > 0) {
743
+				$ticket_to_remove->delete();
744
+				continue;
745
+			}
746
+			// need to get all the related datetimes on this ticket and remove from every single one of them
747
+			// (remember this process can ONLY kick off if there are NO tickets_sold)
748
+			$datetimes = $ticket_to_remove->get_many_related('Datetime');
749
+			foreach ($datetimes as $datetime) {
750
+				$ticket_to_remove->_remove_relation_to($datetime, 'Datetime');
751
+			}
752
+			// need to do the same for prices (except these prices can also be deleted because again,
753
+			// tickets can only be trashed if they don't have any TKTs sold (otherwise they are just archived))
754
+			$ticket_to_remove->delete_related('Price');
755
+			do_action('AHEE__espresso_events_Pricing_Hooks___update_tkts_delete_ticket', $ticket_to_remove);
756
+			// finally let's delete this ticket
757
+			// (which should not be blocked at this point b/c we've removed all our relationships)
758
+			$ticket_to_remove->delete_or_restore();
759
+		}
760
+		return $saved_tickets;
761
+	}
762
+
763
+
764
+	/**
765
+	 * @access  protected
766
+	 * @param EE_Ticket     $ticket
767
+	 * @param EE_Datetime[] $saved_datetimes
768
+	 * @param int[]         $added_datetimes
769
+	 * @param int[]         $removed_datetimes
770
+	 * @return EE_Ticket
771
+	 * @throws EE_Error
772
+	 * @throws ReflectionException
773
+	 */
774
+	protected function _update_ticket_datetimes(
775
+		EE_Ticket $ticket,
776
+		array $saved_datetimes = [],
777
+		array $added_datetimes = [],
778
+		array $removed_datetimes = []
779
+	): EE_Ticket {
780
+		// to start we have to add the ticket to all the datetimes its supposed to be with,
781
+		// and removing the ticket from datetimes it got removed from.
782
+		// first let's add datetimes
783
+		if (! empty($added_datetimes) && is_array($added_datetimes)) {
784
+			foreach ($added_datetimes as $row_id) {
785
+				if (isset($saved_datetimes[ $row_id ]) && $saved_datetimes[ $row_id ] instanceof EE_Datetime) {
786
+					$ticket->_add_relation_to($saved_datetimes[ $row_id ], 'Datetime');
787
+					// Is this an existing ticket (has an ID) and does it have any sold?
788
+					// If so, then we need to add that to the DTT sold because this DTT is getting added.
789
+					if ($ticket->ID() && $ticket->sold() > 0) {
790
+						$saved_datetimes[ $row_id ]->increaseSold($ticket->sold(), false);
791
+					}
792
+				}
793
+			}
794
+		}
795
+		// then remove datetimes
796
+		if (! empty($removed_datetimes) && is_array($removed_datetimes)) {
797
+			foreach ($removed_datetimes as $row_id) {
798
+				// its entirely possible that a datetime got deleted (instead of just removed from relationship.
799
+				// So make sure we skip over this if the datetime isn't in the $saved_datetimes array)
800
+				if (isset($saved_datetimes[ $row_id ]) && $saved_datetimes[ $row_id ] instanceof EE_Datetime) {
801
+					$ticket->_remove_relation_to($saved_datetimes[ $row_id ], 'Datetime');
802
+				}
803
+			}
804
+		}
805
+		// cap ticket qty by datetime reg limits
806
+		$ticket->set_qty(min($ticket->qty(), $ticket->qty('reg_limit')));
807
+		return $ticket;
808
+	}
809
+
810
+
811
+	/**
812
+	 * @access  protected
813
+	 * @param EE_Ticket $ticket
814
+	 * @param array     $price_rows
815
+	 * @param int|float $ticket_price
816
+	 * @param int|float $base_price
817
+	 * @param int       $base_price_id
818
+	 * @return EE_Ticket
819
+	 * @throws ReflectionException
820
+	 * @throws InvalidArgumentException
821
+	 * @throws InvalidInterfaceException
822
+	 * @throws InvalidDataTypeException
823
+	 * @throws EE_Error
824
+	 */
825
+	protected function _duplicate_ticket(
826
+		EE_Ticket $ticket,
827
+		array $price_rows = [],
828
+		$ticket_price = 0,
829
+		$base_price = 0,
830
+		int $base_price_id = 0
831
+	): EE_Ticket {
832
+		// create new ticket that's a copy of the existing
833
+		// except a new id of course (and not archived)
834
+		// AND has the new TKT_price associated with it.
835
+		$new_ticket = clone $ticket;
836
+		$new_ticket->set('TKT_ID', 0);
837
+		$new_ticket->set_deleted(0);
838
+		$new_ticket->set_price($ticket_price);
839
+		$new_ticket->set_sold(0);
840
+		// let's get a new ID for this ticket
841
+		$new_ticket->save();
842
+		// we also need to make sure this new ticket gets the same datetime attachments as the archived ticket
843
+		$datetimes_on_existing = $ticket->datetimes();
844
+		$new_ticket            = $this->_update_ticket_datetimes(
845
+			$new_ticket,
846
+			$datetimes_on_existing,
847
+			array_keys($datetimes_on_existing)
848
+		);
849
+		// $ticket will get archived later b/c we are NOT adding it to the saved_tickets array.
850
+		// if existing $ticket has sold amount, then we need to adjust the qty for the new TKT to = the remaining
851
+		// available.
852
+		if ($ticket->sold() > 0) {
853
+			$new_qty = $ticket->qty() - $ticket->sold();
854
+			$new_ticket->set_qty($new_qty);
855
+		}
856
+		// now we update the prices just for this ticket
857
+		$new_ticket = $this->_add_prices_to_ticket($price_rows, $new_ticket, true);
858
+		// and we update the base price
859
+		return $this->_add_prices_to_ticket(
860
+			[],
861
+			$new_ticket,
862
+			true,
863
+			$base_price,
864
+			$base_price_id
865
+		);
866
+	}
867
+
868
+
869
+	/**
870
+	 * This attaches a list of given prices to a ticket.
871
+	 * Note we dont' have to worry about ever removing relationships (or archiving prices) because if there is a change
872
+	 * in price information on a ticket, a new ticket is created anyways so the archived ticket will retain the old
873
+	 * price info and prices are automatically "archived" via the ticket.
874
+	 *
875
+	 * @access  private
876
+	 * @param array     $prices        Array of prices from the form.
877
+	 * @param EE_Ticket $ticket        EE_Ticket object that prices are being attached to.
878
+	 * @param bool      $new_prices    Whether attach existing incoming prices or create new ones.
879
+	 * @param int|bool  $base_price    if FALSE then NOT doing a base price add.
880
+	 * @param int|bool  $base_price_id if present then this is the base_price_id being updated.
881
+	 * @return EE_Ticket
882
+	 * @throws ReflectionException
883
+	 * @throws InvalidArgumentException
884
+	 * @throws InvalidInterfaceException
885
+	 * @throws InvalidDataTypeException
886
+	 * @throws EE_Error
887
+	 */
888
+	protected function _add_prices_to_ticket(
889
+		array $prices,
890
+		EE_Ticket $ticket,
891
+		bool $new_prices = false,
892
+		$base_price = false,
893
+		$base_price_id = false
894
+	): EE_Ticket {
895
+		$price_model = EEM_Price::instance();
896
+		// let's just get any current prices that may exist on the given ticket
897
+		// so we can remove any prices that got trashed in this session.
898
+		$current_prices_on_ticket = $base_price !== false
899
+			? $ticket->base_price(true)
900
+			: $ticket->price_modifiers();
901
+		$updated_prices           = [];
902
+		// if $base_price ! FALSE then updating a base price.
903
+		if ($base_price !== false) {
904
+			$prices[1] = [
905
+				'PRC_ID'     => $new_prices || $base_price_id === 1
906
+					? null
907
+					: $base_price_id,
908
+				'PRT_ID'     => 1,
909
+				'PRC_amount' => $base_price,
910
+				'PRC_name'   => $ticket->get('TKT_name'),
911
+				'PRC_desc'   => $ticket->get('TKT_description'),
912
+			];
913
+		}
914
+		// possibly need to save ticket
915
+		if (! $ticket->ID()) {
916
+			$ticket->save();
917
+		}
918
+		foreach ($prices as $row => $prc) {
919
+			$prt_id = ! empty($prc['PRT_ID'])
920
+				? $prc['PRT_ID']
921
+				: null;
922
+			if (empty($prt_id)) {
923
+				continue;
924
+			} //prices MUST have a price type id.
925
+			$PRC_values = [
926
+				'PRC_ID'         => ! empty($prc['PRC_ID'])
927
+					? $prc['PRC_ID']
928
+					: null,
929
+				'PRT_ID'         => $prt_id,
930
+				'PRC_amount'     => ! empty($prc['PRC_amount'])
931
+					? $prc['PRC_amount']
932
+					: 0,
933
+				'PRC_name'       => ! empty($prc['PRC_name'])
934
+					? $prc['PRC_name']
935
+					: '',
936
+				'PRC_desc'       => ! empty($prc['PRC_desc'])
937
+					? $prc['PRC_desc']
938
+					: '',
939
+				'PRC_is_default' => false,
940
+				// make sure we set PRC_is_default to false for all ticket saves from event_editor
941
+				'PRC_order'      => $row,
942
+			];
943
+			if ($new_prices || empty($PRC_values['PRC_ID'])) {
944
+				$PRC_values['PRC_ID'] = 0;
945
+				$price                = EE_Registry::instance()->load_class(
946
+					'Price',
947
+					[$PRC_values],
948
+					false,
949
+					false
950
+				);
951
+			} else {
952
+				$price = $price_model->get_one_by_ID($prc['PRC_ID']);
953
+				// update this price with new values
954
+				foreach ($PRC_values as $field => $value) {
955
+					$price->set($field, $value);
956
+				}
957
+			}
958
+			$price->save();
959
+			$updated_prices[ $price->ID() ] = $price;
960
+			$ticket->_add_relation_to($price, 'Price');
961
+		}
962
+		// now let's remove any prices that got removed from the ticket
963
+		if (! empty($current_prices_on_ticket)) {
964
+			$current          = array_keys($current_prices_on_ticket);
965
+			$updated          = array_keys($updated_prices);
966
+			$prices_to_remove = array_diff($current, $updated);
967
+			if (! empty($prices_to_remove)) {
968
+				foreach ($prices_to_remove as $prc_id) {
969
+					$p = $current_prices_on_ticket[ $prc_id ];
970
+					$ticket->_remove_relation_to($p, 'Price');
971
+					// delete permanently the price
972
+					$p->delete_or_restore();
973
+				}
974
+			}
975
+		}
976
+		return $ticket;
977
+	}
978
+
979
+
980
+	/**
981
+	 * @throws ReflectionException
982
+	 * @throws InvalidArgumentException
983
+	 * @throws InvalidInterfaceException
984
+	 * @throws InvalidDataTypeException
985
+	 * @throws DomainException
986
+	 * @throws EE_Error
987
+	 */
988
+	public function pricing_metabox()
989
+	{
990
+		$event          = $this->_adminpage_obj->get_cpt_model_obj();
991
+		$timezone       = $event instanceof EE_Event
992
+			? $event->timezone_string()
993
+			: null;
994
+		$price_model    = EEM_Price::instance($timezone);
995
+		$ticket_model   = EEM_Ticket::instance($timezone);
996
+		$datetime_model = EEM_Datetime::instance($timezone);
997
+		$all_tickets    = [];
998
+
999
+		// set is_creating_event property.
1000
+		$EVT_ID                   = $event->ID();
1001
+		$this->_is_creating_event = empty($this->_req_data['post']);
1002
+		$existing_datetime_ids    = $existing_ticket_ids = $datetime_tickets = $ticket_datetimes = [];
1003
+
1004
+		// default main template args
1005
+		$main_template_args = [
1006
+			'event_datetime_help_link' => EEH_Template::get_help_tab_link(
1007
+				'event_editor_event_datetimes_help_tab',
1008
+				$this->_adminpage_obj->page_slug,
1009
+				$this->_adminpage_obj->get_req_action()
1010
+			),
1011
+
1012
+			// todo need to add a filter to the template for the help text
1013
+			// in the Events_Admin_Page core file so we can add further help
1014
+			'add_new_dtt_help_link'    => EEH_Template::get_help_tab_link(
1015
+				'add_new_dtt_info',
1016
+				$this->_adminpage_obj->page_slug,
1017
+				$this->_adminpage_obj->get_req_action()
1018
+			),
1019
+			// todo need to add this help info id to the Events_Admin_Page core file so we can access it here.
1020
+			'datetime_rows'            => '',
1021
+			'show_tickets_container'   => '',
1022
+			'ticket_rows'              => '',
1023
+			'ee_collapsible_status'    => ' ee-collapsible-open',
1024
+			// $this->_adminpage_obj->get_cpt_model_obj()->ID() > 0 ? ' ee-collapsible-closed' : ' ee-collapsible-open'
1025
+		];
1026
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
1027
+
1028
+		/**
1029
+		 * 1. Start with retrieving Datetimes
1030
+		 * 2. For each datetime get related tickets
1031
+		 * 3. For each ticket get related prices
1032
+		 */
1033
+		$datetimes                            = $datetime_model->get_all_event_dates($EVT_ID);
1034
+		$main_template_args['total_dtt_rows'] = count($datetimes);
1035
+
1036
+		/**
1037
+		 * @see https://events.codebasehq.com/projects/event-espresso/tickets/9486
1038
+		 * for why we are counting $datetime_row and then setting that on the Datetime object
1039
+		 */
1040
+		$datetime_row = 1;
1041
+		foreach ($datetimes as $datetime) {
1042
+			$DTT_ID = $datetime->get('DTT_ID');
1043
+			$datetime->set('DTT_order', $datetime_row);
1044
+			$existing_datetime_ids[] = $DTT_ID;
1045
+			// tickets attached
1046
+			$related_tickets = $datetime->ID() > 0
1047
+				? $datetime->get_many_related(
1048
+					'Ticket',
1049
+					[
1050
+						[
1051
+							'OR' => ['TKT_deleted' => 1, 'TKT_deleted*' => 0],
1052
+						],
1053
+						'default_where_conditions' => 'none',
1054
+						'order_by'                 => ['TKT_order' => 'ASC'],
1055
+					]
1056
+				)
1057
+				: [];
1058
+			// if there are no related tickets this is likely a new event OR auto-draft
1059
+			// event so we need to generate the default tickets because datetimes
1060
+			// ALWAYS have at least one related ticket!!.  EXCEPT, we dont' do this if there is already more than one
1061
+			// datetime on the event.
1062
+			if (empty($related_tickets) && count($datetimes) < 2) {
1063
+				$related_tickets = $ticket_model->get_all_default_tickets();
1064
+				// this should be ordered by TKT_ID, so let's grab the first default ticket
1065
+				// (which will be the main default) and ensure it has any default prices added to it (but do NOT save).
1066
+				$default_prices      = $price_model->get_all_default_prices();
1067
+				$main_default_ticket = reset($related_tickets);
1068
+				if ($main_default_ticket instanceof EE_Ticket) {
1069
+					foreach ($default_prices as $default_price) {
1070
+						if ($default_price instanceof EE_Price && $default_price->is_base_price()) {
1071
+							continue;
1072
+						}
1073
+						$main_default_ticket->cache('Price', $default_price);
1074
+					}
1075
+				}
1076
+			}
1077
+			// we can't actually setup rows in this loop yet cause we don't know all
1078
+			// the unique tickets for this event yet (tickets are linked through all datetimes).
1079
+			// So we're going to temporarily cache some of that information.
1080
+			// loop through and setup the ticket rows and make sure the order is set.
1081
+			foreach ($related_tickets as $ticket) {
1082
+				$TKT_ID     = $ticket->get('TKT_ID');
1083
+				$ticket_row = $ticket->get('TKT_row');
1084
+				// we only want unique tickets in our final display!!
1085
+				if (! in_array($TKT_ID, $existing_ticket_ids, true)) {
1086
+					$existing_ticket_ids[] = $TKT_ID;
1087
+					$all_tickets[]         = $ticket;
1088
+				}
1089
+				// temporary cache of this ticket info for this datetime for later processing of datetime rows.
1090
+				$datetime_tickets[ $DTT_ID ][] = $ticket_row;
1091
+				// temporary cache of this datetime info for this ticket for later processing of ticket rows.
1092
+				if (
1093
+					! isset($ticket_datetimes[ $TKT_ID ])
1094
+					|| ! in_array($datetime_row, $ticket_datetimes[ $TKT_ID ], true)
1095
+				) {
1096
+					$ticket_datetimes[ $TKT_ID ][] = $datetime_row;
1097
+				}
1098
+			}
1099
+			$datetime_row++;
1100
+		}
1101
+		$main_template_args['total_ticket_rows']     = count($existing_ticket_ids);
1102
+		$main_template_args['existing_ticket_ids']   = implode(',', $existing_ticket_ids);
1103
+		$main_template_args['existing_datetime_ids'] = implode(',', $existing_datetime_ids);
1104
+		// sort $all_tickets by order
1105
+		usort(
1106
+			$all_tickets,
1107
+			function (EE_Ticket $a, EE_Ticket $b) {
1108
+				$a_order = (int) $a->get('TKT_order');
1109
+				$b_order = (int) $b->get('TKT_order');
1110
+				if ($a_order === $b_order) {
1111
+					return 0;
1112
+				}
1113
+				return ($a_order < $b_order)
1114
+					? -1
1115
+					: 1;
1116
+			}
1117
+		);
1118
+		// k NOW we have all the data we need for setting up the datetime rows
1119
+		// and ticket rows so we start our datetime loop again.
1120
+		$datetime_row = 1;
1121
+		foreach ($datetimes as $datetime) {
1122
+			$main_template_args['datetime_rows'] .= $this->_get_datetime_row(
1123
+				$datetime_row,
1124
+				$datetime,
1125
+				$datetime_tickets,
1126
+				$all_tickets,
1127
+				false,
1128
+				$datetimes
1129
+			);
1130
+			$datetime_row++;
1131
+		}
1132
+		// then loop through all tickets for the ticket rows.
1133
+		$ticket_row = 1;
1134
+		foreach ($all_tickets as $ticket) {
1135
+			$main_template_args['ticket_rows'] .= $this->_get_ticket_row(
1136
+				$ticket_row,
1137
+				$ticket,
1138
+				$ticket_datetimes,
1139
+				$datetimes,
1140
+				false,
1141
+				$all_tickets
1142
+			);
1143
+			$ticket_row++;
1144
+		}
1145
+		$main_template_args['ticket_js_structure'] = $this->_get_ticket_js_structure($datetimes, $all_tickets);
1146
+
1147
+		$status_change_notice = LoaderFactory::getLoader()->getShared(
1148
+			'EventEspresso\core\domain\services\admin\notices\status_change\StatusChangeNotice'
1149
+		);
1150
+
1151
+		$main_template_args['status_change_notice'] = $status_change_notice->display(
1152
+			'__event-editor',
1153
+			'espresso-events'
1154
+		);
1155
+
1156
+		EEH_Template::display_template(
1157
+			PRICING_TEMPLATE_PATH . 'event_tickets_metabox_main.template.php',
1158
+			$main_template_args
1159
+		);
1160
+	}
1161
+
1162
+
1163
+	/**
1164
+	 * @param int|string  $datetime_row
1165
+	 * @param EE_Datetime $datetime
1166
+	 * @param array       $datetime_tickets
1167
+	 * @param array       $all_tickets
1168
+	 * @param bool        $default
1169
+	 * @param array       $all_datetimes
1170
+	 * @return string
1171
+	 * @throws DomainException
1172
+	 * @throws EE_Error
1173
+	 * @throws ReflectionException
1174
+	 */
1175
+	protected function _get_datetime_row(
1176
+		$datetime_row,
1177
+		EE_Datetime $datetime,
1178
+		array $datetime_tickets = [],
1179
+		array $all_tickets = [],
1180
+		bool $default = false,
1181
+		array $all_datetimes = []
1182
+	): string {
1183
+		return EEH_Template::display_template(
1184
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_row_wrapper.template.php',
1185
+			[
1186
+				'dtt_edit_row'             => $this->_get_dtt_edit_row(
1187
+					$datetime_row,
1188
+					$datetime,
1189
+					$default,
1190
+					$all_datetimes
1191
+				),
1192
+				'dtt_attached_tickets_row' => $this->_get_dtt_attached_tickets_row(
1193
+					$datetime_row,
1194
+					$datetime,
1195
+					$datetime_tickets,
1196
+					$all_tickets,
1197
+					$default
1198
+				),
1199
+				'dtt_row'                  => $default
1200
+					? 'DTTNUM'
1201
+					: $datetime_row,
1202
+			],
1203
+			true
1204
+		);
1205
+	}
1206
+
1207
+
1208
+	/**
1209
+	 * This method is used to generate a datetime fields  edit row.
1210
+	 * The same row is used to generate a row with valid DTT objects
1211
+	 * and the default row that is used as the skeleton by the js.
1212
+	 *
1213
+	 * @param int|string       $datetime_row  The row number for the row being generated.
1214
+	 * @param EE_Datetime|null $datetime
1215
+	 * @param bool             $default       Whether a default row is being generated or not.
1216
+	 * @param EE_Datetime[]    $all_datetimes This is the array of all datetimes used in the editor.
1217
+	 * @return string
1218
+	 * @throws EE_Error
1219
+	 * @throws ReflectionException
1220
+	 */
1221
+	protected function _get_dtt_edit_row(
1222
+		$datetime_row,
1223
+		?EE_Datetime $datetime,
1224
+		bool $default,
1225
+		array $all_datetimes
1226
+	): string {
1227
+		// if the incoming $datetime object is NOT an instance of EE_Datetime then force default to true.
1228
+		$default                     = ! $datetime instanceof EE_Datetime
1229
+			? true
1230
+			: $default;
1231
+		$template_args               = [
1232
+			'dtt_row'              => $default
1233
+				? 'DTTNUM'
1234
+				: $datetime_row,
1235
+			'event_datetimes_name' => $default
1236
+				? 'DTTNAMEATTR'
1237
+				: 'edit_event_datetimes',
1238
+			'edit_dtt_expanded'    => '',
1239
+			'DTT_ID'               => $default
1240
+				? ''
1241
+				: $datetime->ID(),
1242
+			'DTT_name'             => $default
1243
+				? ''
1244
+				: $datetime->get_f('DTT_name'),
1245
+			'DTT_description'      => $default
1246
+				? ''
1247
+				: $datetime->get_raw('DTT_description'),
1248
+			'DTT_EVT_start'        => $default
1249
+				? ''
1250
+				: $datetime->start_date($this->_date_time_format),
1251
+			'DTT_EVT_end'          => $default
1252
+				? ''
1253
+				: $datetime->end_date($this->_date_time_format),
1254
+			'DTT_reg_limit'        => $default
1255
+				? ''
1256
+				: $datetime->get_pretty(
1257
+					'DTT_reg_limit',
1258
+					'input'
1259
+				),
1260
+			'DTT_order'            => $default
1261
+				? 'DTTNUM'
1262
+				: $datetime_row,
1263
+			'dtt_sold'             => $default
1264
+				? '0'
1265
+				: $datetime->get('DTT_sold'),
1266
+			'dtt_reserved'         => $default
1267
+				? '0'
1268
+				: $datetime->reserved(),
1269
+			'can_clone'            => $datetime instanceof EE_Datetime,
1270
+			'can_trash'            => count($all_datetimes) > 1
1271
+									  && $datetime instanceof EE_Datetime
1272
+									  && ! $datetime->get('DTT_sold'),
1273
+			'trash_icon'           => ! empty($datetime) && $datetime->get('DTT_sold') > 0
1274
+				? 'trash-entity dashicons dashicons-lock'
1275
+				: 'trash-entity dashicons dashicons-post-trash clickable',
1276
+			'reg_list_url'         => $default || ! $datetime->event() instanceof EE_Event
1277
+				? ''
1278
+				: EE_Admin_Page::add_query_args_and_nonce(
1279
+					[
1280
+						'event_id'    => $datetime->event()->ID(),
1281
+						'datetime_id' => $datetime->ID(),
1282
+						'use_filters' => true,
1283
+					],
1284
+					REG_ADMIN_URL
1285
+				),
1286
+		];
1287
+		$template_args['show_trash'] = count($all_datetimes) === 1
1288
+									   && $template_args['trash_icon'] !== 'dashicons dashicons-lock'
1289
+			? 'display:none'
1290
+			: '';
1291
+		// allow filtering of template args at this point.
1292
+		$template_args = apply_filters(
1293
+			'FHEE__espresso_events_Pricing_Hooks___get_dtt_edit_row__template_args',
1294
+			$template_args,
1295
+			$datetime_row,
1296
+			$datetime,
1297
+			$default,
1298
+			$all_datetimes,
1299
+			$this->_is_creating_event
1300
+		);
1301
+		return EEH_Template::display_template(
1302
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_edit_row.template.php',
1303
+			$template_args,
1304
+			true
1305
+		);
1306
+	}
1307
+
1308
+
1309
+	/**
1310
+	 * @param int|string       $datetime_row
1311
+	 * @param EE_Datetime|null $datetime
1312
+	 * @param array            $datetime_tickets
1313
+	 * @param array            $all_tickets
1314
+	 * @param bool             $default
1315
+	 * @return string
1316
+	 * @throws DomainException
1317
+	 * @throws EE_Error
1318
+	 * @throws ReflectionException
1319
+	 */
1320
+	protected function _get_dtt_attached_tickets_row(
1321
+		$datetime_row,
1322
+		?EE_Datetime $datetime,
1323
+		array $datetime_tickets = [],
1324
+		array $all_tickets = [],
1325
+		bool $default = false
1326
+	): string {
1327
+		$template_args = [
1328
+			'dtt_row'                           => $default
1329
+				? 'DTTNUM'
1330
+				: $datetime_row,
1331
+			'event_datetimes_name'              => $default
1332
+				? 'DTTNAMEATTR'
1333
+				: 'edit_event_datetimes',
1334
+			'DTT_description'                   => $default
1335
+				? ''
1336
+				: $datetime->get_raw('DTT_description'),
1337
+			'datetime_tickets_list'             => $default
1338
+				? '<li class="hidden"></li>'
1339
+				: '',
1340
+			'show_tickets_row'                  => 'display:none;',
1341
+			'add_new_datetime_ticket_help_link' => EEH_Template::get_help_tab_link(
1342
+				'add_new_ticket_via_datetime',
1343
+				$this->_adminpage_obj->page_slug,
1344
+				$this->_adminpage_obj->get_req_action()
1345
+			),
1346
+			// todo need to add this help info id to the Events_Admin_Page core file so we can access it here.
1347
+			'DTT_ID'                            => $default
1348
+				? ''
1349
+				: $datetime->ID(),
1350
+		];
1351
+		// need to setup the list items (but only if this isn't a default skeleton setup)
1352
+		if (! $default) {
1353
+			$ticket_row = 1;
1354
+			foreach ($all_tickets as $ticket) {
1355
+				$template_args['datetime_tickets_list'] .= $this->_get_datetime_tickets_list_item(
1356
+					$datetime_row,
1357
+					$ticket_row,
1358
+					$datetime,
1359
+					$ticket,
1360
+					$datetime_tickets
1361
+				);
1362
+				$ticket_row++;
1363
+			}
1364
+		}
1365
+		// filter template args at this point
1366
+		$template_args = apply_filters(
1367
+			'FHEE__espresso_events_Pricing_Hooks___get_dtt_attached_ticket_row__template_args',
1368
+			$template_args,
1369
+			$datetime_row,
1370
+			$datetime,
1371
+			$datetime_tickets,
1372
+			$all_tickets,
1373
+			$default,
1374
+			$this->_is_creating_event
1375
+		);
1376
+		return EEH_Template::display_template(
1377
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_attached_tickets_row.template.php',
1378
+			$template_args,
1379
+			true
1380
+		);
1381
+	}
1382
+
1383
+
1384
+	/**
1385
+	 * @param int|string       $datetime_row
1386
+	 * @param int|string       $ticket_row
1387
+	 * @param EE_Datetime|null $datetime
1388
+	 * @param EE_Ticket|null   $ticket
1389
+	 * @param array            $datetime_tickets
1390
+	 * @param bool             $default
1391
+	 * @return string
1392
+	 * @throws EE_Error
1393
+	 * @throws ReflectionException
1394
+	 */
1395
+	protected function _get_datetime_tickets_list_item(
1396
+		$datetime_row,
1397
+		$ticket_row,
1398
+		?EE_Datetime $datetime,
1399
+		?EE_Ticket $ticket,
1400
+		array $datetime_tickets = [],
1401
+		bool $default = false
1402
+	): string {
1403
+		$datetime_tickets = $datetime instanceof EE_Datetime && isset($datetime_tickets[ $datetime->ID() ])
1404
+			? $datetime_tickets[ $datetime->ID() ]
1405
+			: [];
1406
+		$display_row      = $ticket instanceof EE_Ticket
1407
+			? $ticket->get('TKT_row')
1408
+			: 0;
1409
+		$no_ticket        = $default && empty($ticket);
1410
+		$template_args    = [
1411
+			'dtt_row'                 => $default
1412
+				? 'DTTNUM'
1413
+				: $datetime_row,
1414
+			'tkt_row'                 => $no_ticket
1415
+				? 'TICKETNUM'
1416
+				: $ticket_row,
1417
+			'datetime_ticket_checked' => in_array($display_row, $datetime_tickets, true)
1418
+				? ' checked'
1419
+				: '',
1420
+			'ticket_selected'         => in_array($display_row, $datetime_tickets, true)
1421
+				? ' ticket-selected'
1422
+				: '',
1423
+			'TKT_name'                => $no_ticket
1424
+				? 'TKTNAME'
1425
+				: $ticket->get('TKT_name'),
1426
+			'tkt_status_class'        => $no_ticket || $this->_is_creating_event
1427
+				? ' tkt-status-' . EE_Ticket::onsale
1428
+				: ' tkt-status-' . $ticket->ticket_status(),
1429
+		];
1430
+		// filter template args
1431
+		$template_args = apply_filters(
1432
+			'FHEE__espresso_events_Pricing_Hooks___get_datetime_tickets_list_item__template_args',
1433
+			$template_args,
1434
+			$datetime_row,
1435
+			$ticket_row,
1436
+			$datetime,
1437
+			$ticket,
1438
+			$datetime_tickets,
1439
+			$default,
1440
+			$this->_is_creating_event
1441
+		);
1442
+		return EEH_Template::display_template(
1443
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_dtt_tickets_list.template.php',
1444
+			$template_args,
1445
+			true
1446
+		);
1447
+	}
1448
+
1449
+
1450
+	/**
1451
+	 * This generates the ticket row for tickets.
1452
+	 * This same method is used to generate both the actual rows and the js skeleton row
1453
+	 * (when default === true)
1454
+	 *
1455
+	 * @param int|string     $ticket_row       Represents the row number being generated.
1456
+	 * @param EE_Ticket|null $ticket
1457
+	 * @param EE_Datetime[]  $ticket_datetimes Either an array of all datetimes on all tickets indexed by each ticket
1458
+	 *                                         or empty for default
1459
+	 * @param EE_Datetime[]  $all_datetimes    All Datetimes on the event or empty for default.
1460
+	 * @param bool           $default          Whether default row being generated or not.
1461
+	 * @param EE_Ticket[]    $all_tickets      This is an array of all tickets attached to the event
1462
+	 *                                         (or empty in the case of defaults)
1463
+	 * @return string
1464
+	 * @throws InvalidArgumentException
1465
+	 * @throws InvalidInterfaceException
1466
+	 * @throws InvalidDataTypeException
1467
+	 * @throws DomainException
1468
+	 * @throws EE_Error
1469
+	 * @throws ReflectionException
1470
+	 */
1471
+	protected function _get_ticket_row(
1472
+		$ticket_row,
1473
+		?EE_Ticket $ticket,
1474
+		array $ticket_datetimes,
1475
+		array $all_datetimes,
1476
+		bool $default = false,
1477
+		array $all_tickets = []
1478
+	): string {
1479
+		// if $ticket is not an instance of EE_Ticket then force default to true.
1480
+		$default = ! $ticket instanceof EE_Ticket
1481
+			? true
1482
+			: $default;
1483
+		$prices  = ! empty($ticket) && ! $default
1484
+			? $ticket->get_many_related(
1485
+				'Price',
1486
+				['default_where_conditions' => 'none', 'order_by' => ['PRC_order' => 'ASC']]
1487
+			)
1488
+			: [];
1489
+		// if there is only one price (which would be the base price)
1490
+		// or NO prices and this ticket is a default ticket,
1491
+		// let's just make sure there are no cached default prices on the object.
1492
+		// This is done by not including any query_params.
1493
+		if ($ticket instanceof EE_Ticket && $ticket->is_default() && (count($prices) === 1 || empty($prices))) {
1494
+			$prices = $ticket->prices();
1495
+		}
1496
+		// check if we're dealing with a default ticket in which case
1497
+		// we don't want any starting_ticket_datetime_row values set
1498
+		// (otherwise there won't be any new relationships created for tickets based off of the default ticket).
1499
+		// This will future proof in case there is ever any behaviour change between what the primary_key defaults to.
1500
+		$default_datetime = $default || ($ticket instanceof EE_Ticket && $ticket->is_default());
1501
+		$tkt_datetimes    = $ticket instanceof EE_Ticket && isset($ticket_datetimes[ $ticket->ID() ])
1502
+			? $ticket_datetimes[ $ticket->ID() ]
1503
+			: [];
1504
+		$ticket_subtotal  = $default
1505
+			? 0
1506
+			: $ticket->get_ticket_subtotal();
1507
+		$base_price       = $default
1508
+			? null
1509
+			: $ticket->base_price();
1510
+		$count_price_mods = EEM_Price::instance()->get_all_default_prices(true);
1511
+		// breaking out complicated condition for ticket_status
1512
+		if ($default) {
1513
+			$ticket_status_class = ' tkt-status-' . EE_Ticket::onsale;
1514
+		} else {
1515
+			$ticket_status_class = $ticket->is_default()
1516
+				? ' tkt-status-' . EE_Ticket::onsale
1517
+				: ' tkt-status-' . $ticket->ticket_status();
1518
+		}
1519
+		// breaking out complicated condition for TKT_taxable
1520
+		if ($default) {
1521
+			$TKT_taxable = '';
1522
+		} else {
1523
+			$TKT_taxable = $ticket->taxable()
1524
+				? 'checked'
1525
+				: '';
1526
+		}
1527
+		if ($default) {
1528
+			$TKT_status = EEH_Template::pretty_status(EE_Ticket::onsale, false, 'sentence');
1529
+		} elseif ($ticket->is_default()) {
1530
+			$TKT_status = EEH_Template::pretty_status(EE_Ticket::onsale, false, 'sentence');
1531
+		} else {
1532
+			$TKT_status = $ticket->ticket_status(true);
1533
+		}
1534
+		if ($default) {
1535
+			$TKT_min = '';
1536
+		} else {
1537
+			$TKT_min = $ticket->min();
1538
+			if ($TKT_min === -1 || $TKT_min === 0) {
1539
+				$TKT_min = '';
1540
+			}
1541
+		}
1542
+		$template_args                 = [
1543
+			'tkt_row'                       => $default
1544
+				? 'TICKETNUM'
1545
+				: $ticket_row,
1546
+			'TKT_order'                     => $default
1547
+				? 'TICKETNUM'
1548
+				: $ticket_row,
1549
+			// on initial page load this will always be the correct order.
1550
+			'tkt_status_class'              => $ticket_status_class,
1551
+			'display_edit_tkt_row'          => 'display:none;',
1552
+			'edit_tkt_expanded'             => '',
1553
+			'edit_tickets_name'             => $default
1554
+				? 'TICKETNAMEATTR'
1555
+				: 'edit_tickets',
1556
+			'TKT_name'                      => $default
1557
+				? ''
1558
+				: $ticket->get_f('TKT_name'),
1559
+			'TKT_start_date'                => $default
1560
+				? ''
1561
+				: $ticket->get_date('TKT_start_date', $this->_date_time_format),
1562
+			'TKT_end_date'                  => $default
1563
+				? ''
1564
+				: $ticket->get_date('TKT_end_date', $this->_date_time_format),
1565
+			'TKT_status'                    => $TKT_status,
1566
+			'TKT_price'                     => $default
1567
+				? ''
1568
+				: EEH_Template::format_currency(
1569
+					$ticket->get_ticket_total_with_taxes(),
1570
+					false,
1571
+					false
1572
+				),
1573
+			'TKT_price_code'                => EE_Registry::instance()->CFG->currency->code,
1574
+			'TKT_price_amount'              => $default
1575
+				? 0
1576
+				: $ticket_subtotal,
1577
+			'TKT_qty'                       => $default
1578
+				? ''
1579
+				: $ticket->get_pretty('TKT_qty', 'symbol'),
1580
+			'TKT_qty_for_input'             => $default
1581
+				? ''
1582
+				: $ticket->get_pretty('TKT_qty', 'input'),
1583
+			'TKT_uses'                      => $default
1584
+				? ''
1585
+				: $ticket->get_pretty('TKT_uses', 'input'),
1586
+			'TKT_min'                       => $TKT_min,
1587
+			'TKT_max'                       => $default
1588
+				? ''
1589
+				: $ticket->get_pretty('TKT_max', 'input'),
1590
+			'TKT_sold'                      => $default
1591
+				? 0
1592
+				: $ticket->tickets_sold(),
1593
+			'TKT_reserved'                  => $default
1594
+				? 0
1595
+				: $ticket->reserved(),
1596
+			'TKT_registrations'             => $default
1597
+				? 0
1598
+				: $ticket->count_registrations(
1599
+					[
1600
+						[
1601
+							'STS_ID' => [
1602
+								'!=',
1603
+								RegStatus::INCOMPLETE,
1604
+							],
1605
+						],
1606
+					]
1607
+				),
1608
+			'TKT_ID'                        => $default
1609
+				? 0
1610
+				: $ticket->ID(),
1611
+			'TKT_description'               => $default
1612
+				? ''
1613
+				: $ticket->get_raw('TKT_description'),
1614
+			'TKT_is_default'                => $default
1615
+				? 0
1616
+				: $ticket->is_default(),
1617
+			'TKT_required'                  => $default
1618
+				? 0
1619
+				: $ticket->required(),
1620
+			'TKT_is_default_selector'       => '',
1621
+			'ticket_price_rows'             => '',
1622
+			'TKT_base_price'                => $default || ! $base_price instanceof EE_Price
1623
+				? ''
1624
+				: $base_price->get_pretty('PRC_amount', 'localized_float'),
1625
+			'TKT_base_price_ID'             => $default || ! $base_price instanceof EE_Price
1626
+				? 0
1627
+				: $base_price->ID(),
1628
+			'show_price_modifier'           => count($prices) > 1 || ($default && $count_price_mods > 0)
1629
+				? ''
1630
+				: 'display:none;',
1631
+			'show_price_mod_button'         => count($prices) > 1
1632
+											   || ($default && $count_price_mods > 0)
1633
+											   || (! $default && $ticket->deleted())
1634
+				? 'display:none;'
1635
+				: '',
1636
+			'total_price_rows'              => count($prices) > 1
1637
+				? count($prices)
1638
+				: 1,
1639
+			'ticket_datetimes_list'         => $default
1640
+				? '<li class="hidden"></li>'
1641
+				: '',
1642
+			'starting_ticket_datetime_rows' => $default || $default_datetime
1643
+				? ''
1644
+				: implode(',', $tkt_datetimes),
1645
+			'ticket_datetime_rows'          => $default
1646
+				? ''
1647
+				: implode(',', $tkt_datetimes),
1648
+			'existing_ticket_price_ids'     => $default
1649
+				? ''
1650
+				: implode(',', array_keys($prices)),
1651
+			'ticket_template_id'            => $default
1652
+				? 0
1653
+				: $ticket->get('TTM_ID'),
1654
+			'TKT_taxable'                   => $TKT_taxable,
1655
+			'display_subtotal'              => $ticket instanceof EE_Ticket && $ticket->taxable()
1656
+				? ''
1657
+				: 'display:none;',
1658
+			'price_currency_symbol'         => EE_Registry::instance()->CFG->currency->sign,
1659
+			'TKT_subtotal_amount_display'   => EEH_Template::format_currency(
1660
+				$ticket_subtotal,
1661
+				false,
1662
+				false
1663
+			),
1664
+			'TKT_subtotal_amount'           => $ticket_subtotal,
1665
+			'tax_rows'                      => $this->_get_tax_rows($ticket_row, $ticket),
1666
+			'disabled'                      => $ticket instanceof EE_Ticket && $ticket->deleted(),
1667
+			'ticket_archive_class'          => $ticket instanceof EE_Ticket && $ticket->deleted()
1668
+				? ' ticket-archived'
1669
+				: '',
1670
+			'trash_icon'                    => $ticket instanceof EE_Ticket
1671
+											   && $ticket->deleted()
1672
+											   && ! $ticket->is_permanently_deleteable()
1673
+				? 'dashicons dashicons-lock '
1674
+				: 'trash-entity dashicons dashicons-post-trash clickable',
1675
+
1676
+			'can_clone' => $ticket instanceof EE_Ticket && ! $ticket->deleted(),
1677
+			'can_trash' => $ticket instanceof EE_Ticket
1678
+						   && (! $ticket->deleted() && $ticket->is_permanently_deleteable()),
1679
+		];
1680
+		$template_args['trash_hidden'] = count($all_tickets) === 1
1681
+										 && $template_args['trash_icon'] !== 'dashicons dashicons-lock'
1682
+			? 'display:none'
1683
+			: '';
1684
+		// handle rows that should NOT be empty
1685
+		if (empty($template_args['TKT_start_date'])) {
1686
+			// if empty then the start date will be now.
1687
+			$template_args['TKT_start_date']   = date(
1688
+				$this->_date_time_format,
1689
+				current_time('timestamp')
1690
+			);
1691
+			$template_args['tkt_status_class'] = ' tkt-status-' . EE_Ticket::onsale;
1692
+		}
1693
+		if (empty($template_args['TKT_end_date'])) {
1694
+			// get the earliest datetime (if present);
1695
+			$earliest_datetime = $this->_adminpage_obj->get_cpt_model_obj()->ID() > 0
1696
+				? $this->_adminpage_obj->get_cpt_model_obj()->get_first_related(
1697
+					'Datetime',
1698
+					['order_by' => ['DTT_EVT_start' => 'ASC']]
1699
+				)
1700
+				: null;
1701
+			if (! empty($earliest_datetime)) {
1702
+				$template_args['TKT_end_date'] = $earliest_datetime->get_datetime(
1703
+					'DTT_EVT_start',
1704
+					$this->_date_time_format
1705
+				);
1706
+			} else {
1707
+				// default so let's just use what's been set for the default date-time which is 30 days from now.
1708
+				$template_args['TKT_end_date'] = date(
1709
+					$this->_date_time_format,
1710
+					mktime(
1711
+						24,
1712
+						0,
1713
+						0,
1714
+						date('m'),
1715
+						date('d') + 29,
1716
+						date('Y')
1717
+					)
1718
+				);
1719
+			}
1720
+			$template_args['tkt_status_class'] = ' tkt-status-' . EE_Ticket::onsale;
1721
+		}
1722
+		// generate ticket_datetime items
1723
+		if (! $default) {
1724
+			$datetime_row = 1;
1725
+			foreach ($all_datetimes as $datetime) {
1726
+				$template_args['ticket_datetimes_list'] .= $this->_get_ticket_datetime_list_item(
1727
+					$datetime_row,
1728
+					$ticket_row,
1729
+					$datetime,
1730
+					$ticket,
1731
+					$ticket_datetimes,
1732
+					$default
1733
+				);
1734
+				$datetime_row++;
1735
+			}
1736
+		}
1737
+		$price_row = 1;
1738
+		foreach ($prices as $price) {
1739
+			if (! $price instanceof EE_Price) {
1740
+				continue;
1741
+			}
1742
+			if ($price->is_base_price()) {
1743
+				$price_row++;
1744
+				continue;
1745
+			}
1746
+
1747
+			$show_trash  = ! ((count($prices) > 1 && $price_row === 1) || count($prices) === 1);
1748
+			$show_create = ! (count($prices) > 1 && count($prices) !== $price_row);
1749
+
1750
+			$template_args['ticket_price_rows'] .= $this->_get_ticket_price_row(
1751
+				$ticket_row,
1752
+				$price_row,
1753
+				$price,
1754
+				$default,
1755
+				$ticket,
1756
+				$show_trash,
1757
+				$show_create
1758
+			);
1759
+			$price_row++;
1760
+		}
1761
+		// filter $template_args
1762
+		$template_args = apply_filters(
1763
+			'FHEE__espresso_events_Pricing_Hooks___get_ticket_row__template_args',
1764
+			$template_args,
1765
+			$ticket_row,
1766
+			$ticket,
1767
+			$ticket_datetimes,
1768
+			$all_datetimes,
1769
+			$default,
1770
+			$all_tickets,
1771
+			$this->_is_creating_event
1772
+		);
1773
+		return EEH_Template::display_template(
1774
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_row.template.php',
1775
+			$template_args,
1776
+			true
1777
+		);
1778
+	}
1779
+
1780
+
1781
+	/**
1782
+	 * @param int|string     $ticket_row
1783
+	 * @param EE_Ticket|null $ticket
1784
+	 * @return string
1785
+	 * @throws DomainException
1786
+	 * @throws EE_Error
1787
+	 * @throws ReflectionException
1788
+	 */
1789
+	protected function _get_tax_rows($ticket_row, ?EE_Ticket $ticket): string
1790
+	{
1791
+		$tax_rows = '';
1792
+		/** @var EE_Price[] $taxes */
1793
+		$taxes = EE_Taxes::get_taxes_for_admin();
1794
+		foreach ($taxes as $tax) {
1795
+			$tax_added     = $this->_get_tax_added($tax, $ticket);
1796
+			$template_args = [
1797
+				'display_tax'       => ! empty($ticket) && $ticket->get('TKT_taxable')
1798
+					? ''
1799
+					: 'display:none;',
1800
+				'tax_id'            => $tax->ID(),
1801
+				'tkt_row'           => $ticket_row,
1802
+				'tax_label'         => $tax->get('PRC_name'),
1803
+				'tax_added'         => $tax_added,
1804
+				'tax_added_display' => EEH_Template::format_currency($tax_added, false, false),
1805
+				'tax_amount'        => $tax->get('PRC_amount'),
1806
+			];
1807
+			$template_args = apply_filters(
1808
+				'FHEE__espresso_events_Pricing_Hooks___get_tax_rows__template_args',
1809
+				$template_args,
1810
+				$ticket_row,
1811
+				$ticket,
1812
+				$this->_is_creating_event
1813
+			);
1814
+			$tax_rows      .= EEH_Template::display_template(
1815
+				PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_tax_row.template.php',
1816
+				$template_args,
1817
+				true
1818
+			);
1819
+		}
1820
+		return $tax_rows;
1821
+	}
1822
+
1823
+
1824
+	/**
1825
+	 * @param EE_Price       $tax
1826
+	 * @param EE_Ticket|null $ticket
1827
+	 * @return float|int
1828
+	 * @throws EE_Error
1829
+	 * @throws ReflectionException
1830
+	 */
1831
+	protected function _get_tax_added(EE_Price $tax, ?EE_Ticket $ticket)
1832
+	{
1833
+		$subtotal = empty($ticket)
1834
+			? 0
1835
+			: $ticket->get_ticket_subtotal();
1836
+		return $subtotal * $tax->get('PRC_amount') / 100;
1837
+	}
1838
+
1839
+
1840
+	/**
1841
+	 * @param int|string     $ticket_row
1842
+	 * @param int|string     $price_row
1843
+	 * @param EE_Price|null  $price
1844
+	 * @param bool           $default
1845
+	 * @param EE_Ticket|null $ticket
1846
+	 * @param bool           $show_trash
1847
+	 * @param bool           $show_create
1848
+	 * @return string
1849
+	 * @throws InvalidArgumentException
1850
+	 * @throws InvalidInterfaceException
1851
+	 * @throws InvalidDataTypeException
1852
+	 * @throws DomainException
1853
+	 * @throws EE_Error
1854
+	 * @throws ReflectionException
1855
+	 */
1856
+	protected function _get_ticket_price_row(
1857
+		$ticket_row,
1858
+		$price_row,
1859
+		?EE_Price $price,
1860
+		bool $default,
1861
+		?EE_Ticket $ticket,
1862
+		bool $show_trash = true,
1863
+		bool $show_create = true
1864
+	): string {
1865
+		$send_disabled = ! empty($ticket) && $ticket->get('TKT_deleted');
1866
+		$template_args = [
1867
+			'tkt_row'               => $default && empty($ticket)
1868
+				? 'TICKETNUM'
1869
+				: $ticket_row,
1870
+			'PRC_order'             => $default && empty($price)
1871
+				? 'PRICENUM'
1872
+				: $price_row,
1873
+			'edit_prices_name'      => $default && empty($price)
1874
+				? 'PRICENAMEATTR'
1875
+				: 'edit_prices',
1876
+			'price_type_selector'   => $this->_get_price_type_selector(
1877
+				$ticket_row,
1878
+				$price_row,
1879
+				$price,
1880
+				$default,
1881
+				$send_disabled
1882
+			),
1883
+			'PRC_ID'                => $default && empty($price)
1884
+				? 0
1885
+				: $price->ID(),
1886
+			'PRC_is_default'        => $default && empty($price)
1887
+				? 0
1888
+				: $price->get('PRC_is_default'),
1889
+			'PRC_name'              => $default && empty($price)
1890
+				? ''
1891
+				: $price->get('PRC_name'),
1892
+			'price_currency_symbol' => EE_Registry::instance()->CFG->currency->sign,
1893
+			'show_plus_or_minus'    => $default && empty($price)
1894
+				? ''
1895
+				: 'display:none;',
1896
+			'show_plus'             => ($default && empty($price)) || ($price->is_discount() || $price->is_base_price())
1897
+				? 'display:none;'
1898
+				: '',
1899
+			'show_minus'            => ($default && empty($price)) || ! $price->is_discount()
1900
+				? 'display:none;'
1901
+				: '',
1902
+			'show_currency_symbol'  => ($default && empty($price)) || $price->is_percent()
1903
+				? 'display:none'
1904
+				: '',
1905
+			'PRC_amount'            => $default && empty($price)
1906
+				? 0
1907
+				: $price->get_pretty('PRC_amount', 'localized_float'),
1908
+			'show_percentage'       => ($default && empty($price)) || ! $price->is_percent()
1909
+				? 'display:none;'
1910
+				: '',
1911
+			'show_trash_icon'       => $show_trash
1912
+				? ''
1913
+				: ' style="display:none;"',
1914
+			'show_create_button'    => $show_create
1915
+				? ''
1916
+				: ' style="display:none;"',
1917
+			'PRC_desc'              => $default && empty($price)
1918
+				? ''
1919
+				: $price->get('PRC_desc'),
1920
+			'disabled'              => ! empty($ticket) && $ticket->get('TKT_deleted'),
1921
+		];
1922
+		$template_args = apply_filters(
1923
+			'FHEE__espresso_events_Pricing_Hooks___get_ticket_price_row__template_args',
1924
+			$template_args,
1925
+			$ticket_row,
1926
+			$price_row,
1927
+			$price,
1928
+			$default,
1929
+			$ticket,
1930
+			$show_trash,
1931
+			$show_create,
1932
+			$this->_is_creating_event
1933
+		);
1934
+		return EEH_Template::display_template(
1935
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_price_row.template.php',
1936
+			$template_args,
1937
+			true
1938
+		);
1939
+	}
1940
+
1941
+
1942
+	/**
1943
+	 * @param int|string    $ticket_row
1944
+	 * @param int|string    $price_row
1945
+	 * @param EE_Price|null $price
1946
+	 * @param bool          $default
1947
+	 * @param bool          $disabled
1948
+	 * @return string
1949
+	 * @throws ReflectionException
1950
+	 * @throws InvalidArgumentException
1951
+	 * @throws InvalidInterfaceException
1952
+	 * @throws InvalidDataTypeException
1953
+	 * @throws DomainException
1954
+	 * @throws EE_Error
1955
+	 */
1956
+	protected function _get_price_type_selector(
1957
+		$ticket_row,
1958
+		$price_row,
1959
+		?EE_Price $price,
1960
+		bool $default,
1961
+		bool $disabled = false
1962
+	): string {
1963
+		if (($price instanceof EE_Price && $price->is_base_price()) || (! $price instanceof EE_Price && $default)) {
1964
+			return $this->_get_base_price_template(
1965
+				$ticket_row,
1966
+				$price_row,
1967
+				$price,
1968
+				$default
1969
+			);
1970
+		}
1971
+		return $this->_get_price_modifier_template(
1972
+			$ticket_row,
1973
+			$price_row,
1974
+			$price,
1975
+			$default,
1976
+			$disabled
1977
+		);
1978
+	}
1979
+
1980
+
1981
+	/**
1982
+	 * @param int|string    $ticket_row
1983
+	 * @param int|string    $price_row
1984
+	 * @param EE_Price|null $price
1985
+	 * @param bool          $default
1986
+	 * @return string
1987
+	 * @throws DomainException
1988
+	 * @throws EE_Error
1989
+	 * @throws ReflectionException
1990
+	 */
1991
+	protected function _get_base_price_template(
1992
+		$ticket_row,
1993
+		$price_row,
1994
+		?EE_Price $price,
1995
+		bool $default
1996
+	): string {
1997
+		$template_args = [
1998
+			'tkt_row'                   => $default
1999
+				? 'TICKETNUM'
2000
+				: $ticket_row,
2001
+			'PRC_order'                 => $default && empty($price)
2002
+				? 'PRICENUM'
2003
+				: $price_row,
2004
+			'PRT_ID'                    => $default && empty($price)
2005
+				? 1
2006
+				: $price->get('PRT_ID'),
2007
+			'PRT_name'                  => esc_html__('Price', 'event_espresso'),
2008
+			'price_selected_operator'   => '+',
2009
+			'price_selected_is_percent' => 0,
2010
+		];
2011
+		$template_args = apply_filters(
2012
+			'FHEE__espresso_events_Pricing_Hooks___get_base_price_template__template_args',
2013
+			$template_args,
2014
+			$ticket_row,
2015
+			$price_row,
2016
+			$price,
2017
+			$default,
2018
+			$this->_is_creating_event
2019
+		);
2020
+		return EEH_Template::display_template(
2021
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_type_base.template.php',
2022
+			$template_args,
2023
+			true
2024
+		);
2025
+	}
2026
+
2027
+
2028
+	/**
2029
+	 * @param int|string    $ticket_row
2030
+	 * @param int|string    $price_row
2031
+	 * @param EE_Price|null $price
2032
+	 * @param bool          $default
2033
+	 * @param bool          $disabled
2034
+	 * @return string
2035
+	 * @throws ReflectionException
2036
+	 * @throws InvalidArgumentException
2037
+	 * @throws InvalidInterfaceException
2038
+	 * @throws InvalidDataTypeException
2039
+	 * @throws DomainException
2040
+	 * @throws EE_Error
2041
+	 */
2042
+	protected function _get_price_modifier_template(
2043
+		$ticket_row,
2044
+		$price_row,
2045
+		?EE_Price $price,
2046
+		bool $default,
2047
+		bool $disabled = false
2048
+	): string {
2049
+		$use_default = $default && ! $price instanceof EE_Price;
2050
+		$selected_price_type_id =  $use_default ? 0 : $price->type();
2051
+
2052
+		$select_name = $use_default
2053
+			? 'edit_prices[TICKETNUM][PRICENUM][PRT_ID]'
2054
+			: 'edit_prices[' . esc_attr($ticket_row) . '][' . esc_attr($price_row) . '][PRT_ID]';
2055
+
2056
+		$price_type_model       = EEM_Price_Type::instance();
2057
+		$price_types = $price_type_model->get_all([['NOT' => ['PBT_ID' => '1']]]);
2058
+		$all_price_types        = $use_default
2059
+			? [esc_html__('Select Modifier', 'event_espresso')]
2060
+			: [];
2061
+		$price_option_spans     = '';
2062
+		// setup price types for selector
2063
+		foreach ($price_types as $price_type) {
2064
+			if (! $price_type instanceof EE_Price_Type) {
2065
+				continue;
2066
+			}
2067
+			$all_price_types[ $price_type->ID() ] = $price_type->get('PRT_name');
2068
+			// while we're in the loop lets set up the option spans used by js
2069
+			$span_args          = [
2070
+				'PRT_ID'         => $price_type->ID(),
2071
+				'PRT_operator'   => $price_type->is_discount()
2072
+					? '-'
2073
+					: '+',
2074
+				'PRT_is_percent' => $price_type->get('PRT_is_percent')
2075
+					? 1
2076
+					: 0,
2077
+			];
2078
+			$price_option_spans .= EEH_Template::display_template(
2079
+				PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_option_span.template.php',
2080
+				$span_args,
2081
+				true
2082
+			);
2083
+		}
2084
+
2085
+		$select_name = $disabled
2086
+			? 'archive_price[' . $ticket_row . '][' . $price_row . '][PRT_ID]'
2087
+			: $select_name;
2088
+
2089
+		$select_input = new EE_Select_Input(
2090
+			$all_price_types,
2091
+			[
2092
+				'default'               => $selected_price_type_id,
2093
+				'html_name'             => $select_name,
2094
+				'html_class'            => 'edit-price-PRT_ID',
2095
+				'other_html_attributes' => $disabled
2096
+					? 'style="width:auto;" disabled'
2097
+					: 'style="width:auto;"',
2098
+			]
2099
+		);
2100
+
2101
+		$price_selected_operator   = $price instanceof EE_Price && $price->is_discount()
2102
+			? '-'
2103
+			: '+';
2104
+		$price_selected_operator   = $use_default
2105
+			? ''
2106
+			: $price_selected_operator;
2107
+		$price_selected_is_percent = $price instanceof EE_Price && $price->is_percent()
2108
+			? 1
2109
+			: 0;
2110
+		$price_selected_is_percent = $use_default
2111
+			? ''
2112
+			: $price_selected_is_percent;
2113
+		$template_args             = [
2114
+			'tkt_row'                   => $default
2115
+				? 'TICKETNUM'
2116
+				: $ticket_row,
2117
+			'PRC_order'                 => $use_default
2118
+				? 'PRICENUM'
2119
+				: $price_row,
2120
+			'price_modifier_selector'   => $select_input->get_html_for_input(),
2121
+			'main_name'                 => $select_name,
2122
+			'selected_price_type_id'    => $selected_price_type_id,
2123
+			'price_option_spans'        => $price_option_spans,
2124
+			'price_selected_operator'   => $price_selected_operator,
2125
+			'price_selected_is_percent' => $price_selected_is_percent,
2126
+			'disabled'                  => $disabled,
2127
+		];
2128
+		$template_args             = apply_filters(
2129
+			'FHEE__espresso_events_Pricing_Hooks___get_price_modifier_template__template_args',
2130
+			$template_args,
2131
+			$ticket_row,
2132
+			$price_row,
2133
+			$price,
2134
+			$default,
2135
+			$disabled,
2136
+			$this->_is_creating_event
2137
+		);
2138
+		return EEH_Template::display_template(
2139
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_modifier_selector.template.php',
2140
+			$template_args,
2141
+			true
2142
+		);
2143
+	}
2144
+
2145
+
2146
+	/**
2147
+	 * @param int|string       $datetime_row
2148
+	 * @param int|string       $ticket_row
2149
+	 * @param EE_Datetime|null $datetime
2150
+	 * @param EE_Ticket|null   $ticket
2151
+	 * @param array            $ticket_datetimes
2152
+	 * @param bool             $default
2153
+	 * @return string
2154
+	 * @throws DomainException
2155
+	 * @throws EE_Error
2156
+	 * @throws ReflectionException
2157
+	 */
2158
+	protected function _get_ticket_datetime_list_item(
2159
+		$datetime_row,
2160
+		$ticket_row,
2161
+		?EE_Datetime $datetime,
2162
+		?EE_Ticket $ticket,
2163
+		array $ticket_datetimes = [],
2164
+		bool $default = false
2165
+	): string {
2166
+		$tkt_datetimes = $ticket instanceof EE_Ticket && isset($ticket_datetimes[ $ticket->ID() ])
2167
+			? $ticket_datetimes[ $ticket->ID() ]
2168
+			: [];
2169
+		$template_args = [
2170
+			'dtt_row'                  => $default && ! $datetime instanceof EE_Datetime
2171
+				? 'DTTNUM'
2172
+				: $datetime_row,
2173
+			'tkt_row'                  => $default
2174
+				? 'TICKETNUM'
2175
+				: $ticket_row,
2176
+			'ticket_datetime_selected' => in_array($datetime_row, $tkt_datetimes, true)
2177
+				? ' ticket-selected'
2178
+				: '',
2179
+			'ticket_datetime_checked'  => in_array($datetime_row, $tkt_datetimes, true)
2180
+				? ' checked'
2181
+				: '',
2182
+			'DTT_name'                 => $default && empty($datetime)
2183
+				? 'DTTNAME'
2184
+				: $datetime->get_dtt_display_name(true),
2185
+			'tkt_status_class'         => '',
2186
+		];
2187
+		$template_args = apply_filters(
2188
+			'FHEE__espresso_events_Pricing_Hooks___get_ticket_datetime_list_item__template_args',
2189
+			$template_args,
2190
+			$datetime_row,
2191
+			$ticket_row,
2192
+			$datetime,
2193
+			$ticket,
2194
+			$ticket_datetimes,
2195
+			$default,
2196
+			$this->_is_creating_event
2197
+		);
2198
+		return EEH_Template::display_template(
2199
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_datetimes_list_item.template.php',
2200
+			$template_args,
2201
+			true
2202
+		);
2203
+	}
2204
+
2205
+
2206
+	/**
2207
+	 * @param array $all_datetimes
2208
+	 * @param array $all_tickets
2209
+	 * @return string
2210
+	 * @throws ReflectionException
2211
+	 * @throws InvalidArgumentException
2212
+	 * @throws InvalidInterfaceException
2213
+	 * @throws InvalidDataTypeException
2214
+	 * @throws DomainException
2215
+	 * @throws EE_Error
2216
+	 */
2217
+	protected function _get_ticket_js_structure(array $all_datetimes = [], array $all_tickets = []): string
2218
+	{
2219
+		$template_args = [
2220
+			'default_datetime_edit_row' => $this->_get_dtt_edit_row(
2221
+				'DTTNUM',
2222
+				null,
2223
+				true,
2224
+				$all_datetimes
2225
+			),
2226
+			'default_ticket_row'        => $this->_get_ticket_row(
2227
+				'TICKETNUM',
2228
+				null,
2229
+				[],
2230
+				[],
2231
+				true
2232
+			),
2233
+			'default_price_row'         => $this->_get_ticket_price_row(
2234
+				'TICKETNUM',
2235
+				'PRICENUM',
2236
+				null,
2237
+				true,
2238
+				null
2239
+			),
2240
+
2241
+			'default_price_rows'                       => '',
2242
+			'default_base_price_amount'                => 0,
2243
+			'default_base_price_name'                  => '',
2244
+			'default_base_price_description'           => '',
2245
+			'default_price_modifier_selector_row'      => $this->_get_price_modifier_template(
2246
+				'TICKETNUM',
2247
+				'PRICENUM',
2248
+				null,
2249
+				true
2250
+			),
2251
+			'default_available_tickets_for_datetime'   => $this->_get_dtt_attached_tickets_row(
2252
+				'DTTNUM',
2253
+				null,
2254
+				[],
2255
+				[],
2256
+				true
2257
+			),
2258
+			'existing_available_datetime_tickets_list' => '',
2259
+			'existing_available_ticket_datetimes_list' => '',
2260
+			'new_available_datetime_ticket_list_item'  => $this->_get_datetime_tickets_list_item(
2261
+				'DTTNUM',
2262
+				'TICKETNUM',
2263
+				null,
2264
+				null,
2265
+				[],
2266
+				true
2267
+			),
2268
+			'new_available_ticket_datetime_list_item'  => $this->_get_ticket_datetime_list_item(
2269
+				'DTTNUM',
2270
+				'TICKETNUM',
2271
+				null,
2272
+				null,
2273
+				[],
2274
+				true
2275
+			),
2276
+		];
2277
+		$ticket_row    = 1;
2278
+		foreach ($all_tickets as $ticket) {
2279
+			$template_args['existing_available_datetime_tickets_list'] .= $this->_get_datetime_tickets_list_item(
2280
+				'DTTNUM',
2281
+				$ticket_row,
2282
+				null,
2283
+				$ticket,
2284
+				[],
2285
+				true
2286
+			);
2287
+			$ticket_row++;
2288
+		}
2289
+		$datetime_row = 1;
2290
+		foreach ($all_datetimes as $datetime) {
2291
+			$template_args['existing_available_ticket_datetimes_list'] .= $this->_get_ticket_datetime_list_item(
2292
+				$datetime_row,
2293
+				'TICKETNUM',
2294
+				$datetime,
2295
+				null,
2296
+				[],
2297
+				true
2298
+			);
2299
+			$datetime_row++;
2300
+		}
2301
+		$price_model    = EEM_Price::instance();
2302
+		$default_prices = $price_model->get_all_default_prices();
2303
+		$price_row      = 1;
2304
+		foreach ($default_prices as $price) {
2305
+			if (! $price instanceof EE_Price) {
2306
+				continue;
2307
+			}
2308
+			if ($price->is_base_price()) {
2309
+				$template_args['default_base_price_amount']      = $price->get_pretty(
2310
+					'PRC_amount',
2311
+					'localized_float'
2312
+				);
2313
+				$template_args['default_base_price_name']        = $price->get('PRC_name');
2314
+				$template_args['default_base_price_description'] = $price->get('PRC_desc');
2315
+				$price_row++;
2316
+				continue;
2317
+			}
2318
+
2319
+			$show_trash  = ! ((count($default_prices) > 1 && $price_row === 1) || count($default_prices) === 1);
2320
+			$show_create = ! (count($default_prices) > 1 && count($default_prices) !== $price_row);
2321
+
2322
+			$template_args['default_price_rows'] .= $this->_get_ticket_price_row(
2323
+				'TICKETNUM',
2324
+				$price_row,
2325
+				$price,
2326
+				true,
2327
+				null,
2328
+				$show_trash,
2329
+				$show_create
2330
+			);
2331
+			$price_row++;
2332
+		}
2333
+		$template_args = apply_filters(
2334
+			'FHEE__espresso_events_Pricing_Hooks___get_ticket_js_structure__template_args',
2335
+			$template_args,
2336
+			$all_datetimes,
2337
+			$all_tickets,
2338
+			$this->_is_creating_event
2339
+		);
2340
+		return EEH_Template::display_template(
2341
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_js_structure.template.php',
2342
+			$template_args,
2343
+			true
2344
+		);
2345
+	}
2346 2346
 }
Please login to merge, or discard this patch.
core/EE_Data_Mapper.core.php 1 patch
Indentation   +92 added lines, -92 removed lines patch added patch discarded remove patch
@@ -14,96 +14,96 @@
 block discarded – undo
14 14
  */
15 15
 class EE_Data_Mapper
16 16
 {
17
-    /**
18
-     * instance of the EE_Data_Mapper Object
19
-     */
20
-    private static $_instance = null;
21
-
22
-
23
-    public $data = array();
24
-
25
-
26
-    /**
27
-     * private constructor to prevent direct creation
28
-     *
29
-     * @return void
30
-     */
31
-    private function __construct()
32
-    {
33
-    }
34
-
35
-
36
-    /**
37
-     * singleton method used to instantiate class object
38
-     *
39
-     * @return class instance
40
-     */
41
-    public function &instance()
42
-    {
43
-        // check if class object is instantiated
44
-        if (
45
-            self::$_instance === null
46
-            || ! is_object(self::$_instance)
47
-            || ! self::$_instance instanceof EE_Data_Mapper
48
-        ) {
49
-            self::$_instance = new self();
50
-        }
51
-        return self::$_instance;
52
-    }
53
-
54
-
55
-    /**
56
-     * override magic methods
57
-     *
58
-     * @return void
59
-     */
60
-    final public function __destruct()
61
-    {
62
-    }
63
-
64
-    final public function __call($a, $b)
65
-    {
66
-    }
67
-
68
-    public static function __callStatic($a, $b)
69
-    {
70
-    }
71
-
72
-    final public function __get($a)
73
-    {
74
-    }
75
-
76
-    final public function __set($a, $b)
77
-    {
78
-    }
79
-
80
-    final public function __isset($a)
81
-    {
82
-    }
83
-
84
-    final public function __unset($a)
85
-    {
86
-    }
87
-
88
-    final public function __sleep()
89
-    {
90
-        return array();
91
-    }
92
-
93
-    final public function __wakeup()
94
-    {
95
-    }
96
-
97
-    final public function __toString()
98
-    {
99
-        return '';
100
-    }
101
-
102
-    final public function __invoke()
103
-    {
104
-    }
105
-
106
-    final public function __clone()
107
-    {
108
-    }
17
+	/**
18
+	 * instance of the EE_Data_Mapper Object
19
+	 */
20
+	private static $_instance = null;
21
+
22
+
23
+	public $data = array();
24
+
25
+
26
+	/**
27
+	 * private constructor to prevent direct creation
28
+	 *
29
+	 * @return void
30
+	 */
31
+	private function __construct()
32
+	{
33
+	}
34
+
35
+
36
+	/**
37
+	 * singleton method used to instantiate class object
38
+	 *
39
+	 * @return class instance
40
+	 */
41
+	public function &instance()
42
+	{
43
+		// check if class object is instantiated
44
+		if (
45
+			self::$_instance === null
46
+			|| ! is_object(self::$_instance)
47
+			|| ! self::$_instance instanceof EE_Data_Mapper
48
+		) {
49
+			self::$_instance = new self();
50
+		}
51
+		return self::$_instance;
52
+	}
53
+
54
+
55
+	/**
56
+	 * override magic methods
57
+	 *
58
+	 * @return void
59
+	 */
60
+	final public function __destruct()
61
+	{
62
+	}
63
+
64
+	final public function __call($a, $b)
65
+	{
66
+	}
67
+
68
+	public static function __callStatic($a, $b)
69
+	{
70
+	}
71
+
72
+	final public function __get($a)
73
+	{
74
+	}
75
+
76
+	final public function __set($a, $b)
77
+	{
78
+	}
79
+
80
+	final public function __isset($a)
81
+	{
82
+	}
83
+
84
+	final public function __unset($a)
85
+	{
86
+	}
87
+
88
+	final public function __sleep()
89
+	{
90
+		return array();
91
+	}
92
+
93
+	final public function __wakeup()
94
+	{
95
+	}
96
+
97
+	final public function __toString()
98
+	{
99
+		return '';
100
+	}
101
+
102
+	final public function __invoke()
103
+	{
104
+	}
105
+
106
+	final public function __clone()
107
+	{
108
+	}
109 109
 }
Please login to merge, or discard this patch.
4_10_0_stages/EE_DMS_4_10_0_Event_Question_Group.dmsstage.php 2 patches
Indentation   +134 added lines, -134 removed lines patch added patch discarded remove patch
@@ -9,144 +9,144 @@
 block discarded – undo
9 9
  */
10 10
 class EE_DMS_4_10_0_Event_Question_Group extends EE_Data_Migration_Script_Stage_Table
11 11
 {
12
-    /**
13
-     * Just initializes the status of the migration
14
-     */
15
-    public function __construct()
16
-    {
17
-        global $wpdb;
18
-        $this->_pretty_name     = esc_html__('Event-Question Group Relations', 'event_espresso');
19
-        $this->_old_table       = $wpdb->prefix . 'esp_event_question_group';
20
-        $this->_extra_where_sql = "WHERE EQG_primary = 0 AND EQG_additional=0";
21
-        parent::__construct();
22
-    }
12
+	/**
13
+	 * Just initializes the status of the migration
14
+	 */
15
+	public function __construct()
16
+	{
17
+		global $wpdb;
18
+		$this->_pretty_name     = esc_html__('Event-Question Group Relations', 'event_espresso');
19
+		$this->_old_table       = $wpdb->prefix . 'esp_event_question_group';
20
+		$this->_extra_where_sql = "WHERE EQG_primary = 0 AND EQG_additional=0";
21
+		parent::__construct();
22
+	}
23 23
 
24 24
 
25
-    /**
26
-     * Removes the duplicate event_question_group rows that only had EQG_primary=0. Now we just have one row
27
-     * joining event-to-question-groups with two columns: EQG_primary and EQG_additional, indicating which question
28
-     * groups apply to which category of registrant.
29
-     *
30
-     * @param array $old_row an associative array where keys are column names and values are their values.
31
-     * @return void
32
-     */
33
-    protected function _migrate_old_row($old_row)
34
-    {
35
-        if (isset($old_row['EVT_ID'], $old_row['QSG_ID'])) {
36
-            global $wpdb;
37
-            // If the question group was also for primary attendees, we should just update that row.
38
-            // And we delete this row.
39
-            // Updating all the rows could be slow on massive DBs, so do the slow selection first, then a quick update
40
-            // in order to avoid locking the table for too long.
41
-            $ids_to_update = $wpdb->get_col(
42
-                $wpdb->prepare(
43
-                    'SELECT EQG_ID FROM ' . $this->_old_table . ' WHERE EQG_primary=1 AND EVT_ID=%d AND QSG_ID=%d',
44
-                    $old_row['EVT_ID'],
45
-                    $old_row['QSG_ID']
46
-                )
47
-            );
48
-            $success       = false;
49
-            if ($ids_to_update) {
50
-                $success = $wpdb->query(
51
-                    'UPDATE ' .
52
-                    $this->_old_table .
53
-                    ' SET EQG_additional=1 WHERE EQG_ID IN (' .
54
-                    implode(',', array_map('intval', $ids_to_update)) .
55
-                    ') LIMIT ' .
56
-                    count($ids_to_update)
57
-                );
58
-            }
59
-            if ($success) {
60
-                // Ok it's confirmed: the question group WAS for the primary attendee group too. So
61
-                // now we just need to delete this row.
62
-                $successful_delete = $wpdb->delete(
63
-                    $this->_old_table,
64
-                    [
65
-                        'EQG_ID' => $old_row['EQG_ID'],
66
-                    ],
67
-                    ['%d']
68
-                );
69
-                if (! $successful_delete) {
70
-                    $this->add_error(
71
-                        sprintf(
72
-                            esc_html__(
73
-                                'Could not delete old event-question group relation row "%1$s" because "%2$s"',
74
-                                'event_espresso'
75
-                            ),
76
-                            wp_json_encode($old_row),
77
-                            $wpdb->last_error
78
-                        )
79
-                    );
80
-                }
81
-            } else {
82
-                // Oh, the question group actually was NOT for the primary attendee. So we just need to update this row
83
-                // Let's do the selection separately from the deletion, this way we don't lock big tables for too long.
84
-                $ids_to_update2 = $wpdb->get_col(
85
-                    $wpdb->prepare(
86
-                        'SELECT EQG_ID FROM ' . $this->_old_table . ' WHERE EVT_ID=%d AND QSG_ID=%d',
87
-                        $old_row['EVT_ID'],
88
-                        $old_row['QSG_ID']
89
-                    )
90
-                );
91
-                if ($ids_to_update2) {
92
-                    $wpdb->query(
93
-                        'UPDATE ' .
94
-                        $this->_old_table .
95
-                        ' SET EQG_additional=1 WHERE EQG_ID IN (' .
96
-                        implode(',', array_map('intval', $ids_to_update2)) .
97
-                        ') LIMIT ' .
98
-                        count($ids_to_update2)
99
-                    );
100
-                }
101
-            }
102
-        }
103
-    }
25
+	/**
26
+	 * Removes the duplicate event_question_group rows that only had EQG_primary=0. Now we just have one row
27
+	 * joining event-to-question-groups with two columns: EQG_primary and EQG_additional, indicating which question
28
+	 * groups apply to which category of registrant.
29
+	 *
30
+	 * @param array $old_row an associative array where keys are column names and values are their values.
31
+	 * @return void
32
+	 */
33
+	protected function _migrate_old_row($old_row)
34
+	{
35
+		if (isset($old_row['EVT_ID'], $old_row['QSG_ID'])) {
36
+			global $wpdb;
37
+			// If the question group was also for primary attendees, we should just update that row.
38
+			// And we delete this row.
39
+			// Updating all the rows could be slow on massive DBs, so do the slow selection first, then a quick update
40
+			// in order to avoid locking the table for too long.
41
+			$ids_to_update = $wpdb->get_col(
42
+				$wpdb->prepare(
43
+					'SELECT EQG_ID FROM ' . $this->_old_table . ' WHERE EQG_primary=1 AND EVT_ID=%d AND QSG_ID=%d',
44
+					$old_row['EVT_ID'],
45
+					$old_row['QSG_ID']
46
+				)
47
+			);
48
+			$success       = false;
49
+			if ($ids_to_update) {
50
+				$success = $wpdb->query(
51
+					'UPDATE ' .
52
+					$this->_old_table .
53
+					' SET EQG_additional=1 WHERE EQG_ID IN (' .
54
+					implode(',', array_map('intval', $ids_to_update)) .
55
+					') LIMIT ' .
56
+					count($ids_to_update)
57
+				);
58
+			}
59
+			if ($success) {
60
+				// Ok it's confirmed: the question group WAS for the primary attendee group too. So
61
+				// now we just need to delete this row.
62
+				$successful_delete = $wpdb->delete(
63
+					$this->_old_table,
64
+					[
65
+						'EQG_ID' => $old_row['EQG_ID'],
66
+					],
67
+					['%d']
68
+				);
69
+				if (! $successful_delete) {
70
+					$this->add_error(
71
+						sprintf(
72
+							esc_html__(
73
+								'Could not delete old event-question group relation row "%1$s" because "%2$s"',
74
+								'event_espresso'
75
+							),
76
+							wp_json_encode($old_row),
77
+							$wpdb->last_error
78
+						)
79
+					);
80
+				}
81
+			} else {
82
+				// Oh, the question group actually was NOT for the primary attendee. So we just need to update this row
83
+				// Let's do the selection separately from the deletion, this way we don't lock big tables for too long.
84
+				$ids_to_update2 = $wpdb->get_col(
85
+					$wpdb->prepare(
86
+						'SELECT EQG_ID FROM ' . $this->_old_table . ' WHERE EVT_ID=%d AND QSG_ID=%d',
87
+						$old_row['EVT_ID'],
88
+						$old_row['QSG_ID']
89
+					)
90
+				);
91
+				if ($ids_to_update2) {
92
+					$wpdb->query(
93
+						'UPDATE ' .
94
+						$this->_old_table .
95
+						' SET EQG_additional=1 WHERE EQG_ID IN (' .
96
+						implode(',', array_map('intval', $ids_to_update2)) .
97
+						') LIMIT ' .
98
+						count($ids_to_update2)
99
+					);
100
+				}
101
+			}
102
+		}
103
+	}
104 104
 
105 105
 
106
-    /**
107
-     * Gets the rows for the existing table that shouldn't exist in 4.10.
108
-     * Specifically the rows where EQG_primary=false and EQG_additional=false.
109
-     * Gotcha: because the migration is REMOVING rows as it goes, we shouldn't use the offset.
110
-     *
111
-     * @param int   $limit
112
-     * @return array of arrays like $wpdb->get_results($sql, ARRAY_A)
113
-     * @global wpdb $wpdb
114
-     */
115
-    protected function _get_rows($limit)
116
-    {
117
-        global $wpdb;
118
-        $query = "SELECT * FROM $this->_old_table $this->_extra_where_sql " . $wpdb->prepare(
119
-            "LIMIT %d",
120
-            $limit
121
-        );
122
-        return $wpdb->get_results($query, ARRAY_A);
123
-    }
106
+	/**
107
+	 * Gets the rows for the existing table that shouldn't exist in 4.10.
108
+	 * Specifically the rows where EQG_primary=false and EQG_additional=false.
109
+	 * Gotcha: because the migration is REMOVING rows as it goes, we shouldn't use the offset.
110
+	 *
111
+	 * @param int   $limit
112
+	 * @return array of arrays like $wpdb->get_results($sql, ARRAY_A)
113
+	 * @global wpdb $wpdb
114
+	 */
115
+	protected function _get_rows($limit)
116
+	{
117
+		global $wpdb;
118
+		$query = "SELECT * FROM $this->_old_table $this->_extra_where_sql " . $wpdb->prepare(
119
+			"LIMIT %d",
120
+			$limit
121
+		);
122
+		return $wpdb->get_results($query, ARRAY_A);
123
+	}
124 124
 
125 125
 
126
-    /**
127
-     * Slight departure from the normal procedure here: because this removes rows from the DB, we need to ensure
128
-     * we count the records first, then do the migration.
129
-     *
130
-     * @param int $num_items_to_migrate
131
-     * @return int number of items ACTUALLY migrated
132
-     */
133
-    public function _migration_step($num_items_to_migrate = 50)
134
-    {
135
-        // Count the items right away. This migration step will be removing those rows, so we need to count them
136
-        // right away to get an accurate count.
137
-        $this->count_records_to_migrate();
138
-        $rows                    = $this->_get_rows($num_items_to_migrate);
139
-        $items_actually_migrated = 0;
140
-        foreach ($rows as $old_row) {
141
-            $this->_migrate_old_row($old_row);
142
-            $items_actually_migrated++;
143
-        }
144
-        if (
145
-            empty($rows) ||
146
-            ($this->count_records_migrated() + $items_actually_migrated >= $this->count_records_to_migrate())
147
-        ) {
148
-            $this->set_completed();
149
-        }
150
-        return $items_actually_migrated;
151
-    }
126
+	/**
127
+	 * Slight departure from the normal procedure here: because this removes rows from the DB, we need to ensure
128
+	 * we count the records first, then do the migration.
129
+	 *
130
+	 * @param int $num_items_to_migrate
131
+	 * @return int number of items ACTUALLY migrated
132
+	 */
133
+	public function _migration_step($num_items_to_migrate = 50)
134
+	{
135
+		// Count the items right away. This migration step will be removing those rows, so we need to count them
136
+		// right away to get an accurate count.
137
+		$this->count_records_to_migrate();
138
+		$rows                    = $this->_get_rows($num_items_to_migrate);
139
+		$items_actually_migrated = 0;
140
+		foreach ($rows as $old_row) {
141
+			$this->_migrate_old_row($old_row);
142
+			$items_actually_migrated++;
143
+		}
144
+		if (
145
+			empty($rows) ||
146
+			($this->count_records_migrated() + $items_actually_migrated >= $this->count_records_to_migrate())
147
+		) {
148
+			$this->set_completed();
149
+		}
150
+		return $items_actually_migrated;
151
+	}
152 152
 }
Please login to merge, or discard this patch.
Spacing   +16 added lines, -16 removed lines patch added patch discarded remove patch
@@ -16,7 +16,7 @@  discard block
 block discarded – undo
16 16
     {
17 17
         global $wpdb;
18 18
         $this->_pretty_name     = esc_html__('Event-Question Group Relations', 'event_espresso');
19
-        $this->_old_table       = $wpdb->prefix . 'esp_event_question_group';
19
+        $this->_old_table       = $wpdb->prefix.'esp_event_question_group';
20 20
         $this->_extra_where_sql = "WHERE EQG_primary = 0 AND EQG_additional=0";
21 21
         parent::__construct();
22 22
     }
@@ -40,19 +40,19 @@  discard block
 block discarded – undo
40 40
             // in order to avoid locking the table for too long.
41 41
             $ids_to_update = $wpdb->get_col(
42 42
                 $wpdb->prepare(
43
-                    'SELECT EQG_ID FROM ' . $this->_old_table . ' WHERE EQG_primary=1 AND EVT_ID=%d AND QSG_ID=%d',
43
+                    'SELECT EQG_ID FROM '.$this->_old_table.' WHERE EQG_primary=1 AND EVT_ID=%d AND QSG_ID=%d',
44 44
                     $old_row['EVT_ID'],
45 45
                     $old_row['QSG_ID']
46 46
                 )
47 47
             );
48
-            $success       = false;
48
+            $success = false;
49 49
             if ($ids_to_update) {
50 50
                 $success = $wpdb->query(
51
-                    'UPDATE ' .
52
-                    $this->_old_table .
53
-                    ' SET EQG_additional=1 WHERE EQG_ID IN (' .
54
-                    implode(',', array_map('intval', $ids_to_update)) .
55
-                    ') LIMIT ' .
51
+                    'UPDATE '.
52
+                    $this->_old_table.
53
+                    ' SET EQG_additional=1 WHERE EQG_ID IN ('.
54
+                    implode(',', array_map('intval', $ids_to_update)).
55
+                    ') LIMIT '.
56 56
                     count($ids_to_update)
57 57
                 );
58 58
             }
@@ -66,7 +66,7 @@  discard block
 block discarded – undo
66 66
                     ],
67 67
                     ['%d']
68 68
                 );
69
-                if (! $successful_delete) {
69
+                if ( ! $successful_delete) {
70 70
                     $this->add_error(
71 71
                         sprintf(
72 72
                             esc_html__(
@@ -83,18 +83,18 @@  discard block
 block discarded – undo
83 83
                 // Let's do the selection separately from the deletion, this way we don't lock big tables for too long.
84 84
                 $ids_to_update2 = $wpdb->get_col(
85 85
                     $wpdb->prepare(
86
-                        'SELECT EQG_ID FROM ' . $this->_old_table . ' WHERE EVT_ID=%d AND QSG_ID=%d',
86
+                        'SELECT EQG_ID FROM '.$this->_old_table.' WHERE EVT_ID=%d AND QSG_ID=%d',
87 87
                         $old_row['EVT_ID'],
88 88
                         $old_row['QSG_ID']
89 89
                     )
90 90
                 );
91 91
                 if ($ids_to_update2) {
92 92
                     $wpdb->query(
93
-                        'UPDATE ' .
94
-                        $this->_old_table .
95
-                        ' SET EQG_additional=1 WHERE EQG_ID IN (' .
96
-                        implode(',', array_map('intval', $ids_to_update2)) .
97
-                        ') LIMIT ' .
93
+                        'UPDATE '.
94
+                        $this->_old_table.
95
+                        ' SET EQG_additional=1 WHERE EQG_ID IN ('.
96
+                        implode(',', array_map('intval', $ids_to_update2)).
97
+                        ') LIMIT '.
98 98
                         count($ids_to_update2)
99 99
                     );
100 100
                 }
@@ -115,7 +115,7 @@  discard block
 block discarded – undo
115 115
     protected function _get_rows($limit)
116 116
     {
117 117
         global $wpdb;
118
-        $query = "SELECT * FROM $this->_old_table $this->_extra_where_sql " . $wpdb->prepare(
118
+        $query = "SELECT * FROM $this->_old_table $this->_extra_where_sql ".$wpdb->prepare(
119 119
             "LIMIT %d",
120 120
             $limit
121 121
         );
Please login to merge, or discard this patch.
core/data_migration_scripts/EE_DMS_Core_4_1_0.dms.php 1 patch
Indentation   +1256 added lines, -1256 removed lines patch added patch discarded remove patch
@@ -10,11 +10,11 @@  discard block
 block discarded – undo
10 10
 $stages            = glob(EE_CORE . 'data_migration_scripts/4_1_0_stages/*');
11 11
 $class_to_filepath = [];
12 12
 if (! empty($stages)) {
13
-    foreach ($stages as $filepath) {
14
-        $matches = [];
15
-        preg_match('~4_1_0_stages/(.*).dmsstage.php~', $filepath, $matches);
16
-        $class_to_filepath[ $matches[1] ] = $filepath;
17
-    }
13
+	foreach ($stages as $filepath) {
14
+		$matches = [];
15
+		preg_match('~4_1_0_stages/(.*).dmsstage.php~', $filepath, $matches);
16
+		$class_to_filepath[ $matches[1] ] = $filepath;
17
+	}
18 18
 }
19 19
 // give addons a chance to autoload their stages too
20 20
 $class_to_filepath = apply_filters('FHEE__EE_DMS_4_1_0__autoloaded_stages', $class_to_filepath);
@@ -38,92 +38,92 @@  discard block
 block discarded – undo
38 38
  */
39 39
 class EE_DMS_Core_4_1_0 extends EE_Data_Migration_Script_Base
40 40
 {
41
-    /**
42
-     * EE_DMS_Core_4_1_0 constructor.
43
-     *
44
-     * @param TableManager|null  $table_manager
45
-     * @param TableAnalysis|null $table_analysis
46
-     */
47
-    public function __construct(TableManager $table_manager = null, TableAnalysis $table_analysis = null)
48
-    {
49
-        $this->_pretty_name      =
50
-            esc_html__("Data Migration from Event Espresso 3 to Event Espresso 4.1.0", "event_espresso");
51
-        $this->_priority         = 10;
52
-        $this->_migration_stages = [
53
-            new EE_DMS_4_1_0_org_options(),
54
-            new EE_DMS_4_1_0_shortcodes(),
55
-            new EE_DMS_4_1_0_gateways(),
56
-            new EE_DMS_4_1_0_events(),
57
-            new EE_DMS_4_1_0_prices(),
58
-            new EE_DMS_4_1_0_category_details(),
59
-            new EE_DMS_4_1_0_event_category(),
60
-            new EE_DMS_4_1_0_venues(),
61
-            new EE_DMS_4_1_0_event_venue(),
62
-            new EE_DMS_4_1_0_question_groups(),
63
-            new EE_DMS_4_1_0_questions(),
64
-            new EE_DMS_4_1_0_question_group_question(),
65
-            new EE_DMS_4_1_0_event_question_group(),
66
-            new EE_DMS_4_1_0_attendees(),
67
-            new EE_DMS_4_1_0_line_items(),
68
-            new EE_DMS_4_1_0_answers(),
69
-            new EE_DMS_4_1_0_checkins(),
70
-        ];
71
-        parent::__construct($table_manager, $table_analysis);
72
-    }
73
-
74
-
75
-    /**
76
-     * Checks if this 3.1 Check-in table exists. If it doesn't we can't migrate Check-ins
77
-     *
78
-     * @return boolean
79
-     * @global wpdb $wpdb
80
-     */
81
-    private function _checkin_table_exists(): bool
82
-    {
83
-        global $wpdb;
84
-        return (bool) $wpdb->get_results(
85
-            "SHOW TABLES LIKE '" . $wpdb->prefix . "events_attendee_checkin" . "'"
86
-        );
87
-    }
88
-
89
-
90
-    public function can_migrate_from_version($version_array)
91
-    {
92
-        $version_string = $version_array['Core'];
93
-        if (version_compare($version_string, '4.0.0.decaf', '<') && version_compare($version_string, '3.1.26', '>=')) {
94
-            //          echo "$version_string can be migrated fro";
95
-            return true;
96
-        } elseif (! $version_string) {
97
-            //          echo "no version string provided: $version_string";
98
-            // no version string provided... this must be pre 4.1
99
-            // because since 4.1 we're
100
-            return false;// changed mind. dont want people thinking they should migrate yet because they cant
101
-        } else {
102
-            //          echo "$version_string doesnt apply";
103
-            return false;
104
-        }
105
-    }
106
-
107
-
108
-    /**
109
-     * @throws EE_Error
110
-     * @throws ReflectionException
111
-     */
112
-    public function schema_changes_before_migration()
113
-    {
114
-        // relies on 4.1's EEH_Activation::create_table
115
-        require_once(EE_HELPERS . 'EEH_Activation.helper.php');
116
-
117
-        $table_name = 'esp_answer';
118
-        $sql        = "ANS_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
41
+	/**
42
+	 * EE_DMS_Core_4_1_0 constructor.
43
+	 *
44
+	 * @param TableManager|null  $table_manager
45
+	 * @param TableAnalysis|null $table_analysis
46
+	 */
47
+	public function __construct(TableManager $table_manager = null, TableAnalysis $table_analysis = null)
48
+	{
49
+		$this->_pretty_name      =
50
+			esc_html__("Data Migration from Event Espresso 3 to Event Espresso 4.1.0", "event_espresso");
51
+		$this->_priority         = 10;
52
+		$this->_migration_stages = [
53
+			new EE_DMS_4_1_0_org_options(),
54
+			new EE_DMS_4_1_0_shortcodes(),
55
+			new EE_DMS_4_1_0_gateways(),
56
+			new EE_DMS_4_1_0_events(),
57
+			new EE_DMS_4_1_0_prices(),
58
+			new EE_DMS_4_1_0_category_details(),
59
+			new EE_DMS_4_1_0_event_category(),
60
+			new EE_DMS_4_1_0_venues(),
61
+			new EE_DMS_4_1_0_event_venue(),
62
+			new EE_DMS_4_1_0_question_groups(),
63
+			new EE_DMS_4_1_0_questions(),
64
+			new EE_DMS_4_1_0_question_group_question(),
65
+			new EE_DMS_4_1_0_event_question_group(),
66
+			new EE_DMS_4_1_0_attendees(),
67
+			new EE_DMS_4_1_0_line_items(),
68
+			new EE_DMS_4_1_0_answers(),
69
+			new EE_DMS_4_1_0_checkins(),
70
+		];
71
+		parent::__construct($table_manager, $table_analysis);
72
+	}
73
+
74
+
75
+	/**
76
+	 * Checks if this 3.1 Check-in table exists. If it doesn't we can't migrate Check-ins
77
+	 *
78
+	 * @return boolean
79
+	 * @global wpdb $wpdb
80
+	 */
81
+	private function _checkin_table_exists(): bool
82
+	{
83
+		global $wpdb;
84
+		return (bool) $wpdb->get_results(
85
+			"SHOW TABLES LIKE '" . $wpdb->prefix . "events_attendee_checkin" . "'"
86
+		);
87
+	}
88
+
89
+
90
+	public function can_migrate_from_version($version_array)
91
+	{
92
+		$version_string = $version_array['Core'];
93
+		if (version_compare($version_string, '4.0.0.decaf', '<') && version_compare($version_string, '3.1.26', '>=')) {
94
+			//          echo "$version_string can be migrated fro";
95
+			return true;
96
+		} elseif (! $version_string) {
97
+			//          echo "no version string provided: $version_string";
98
+			// no version string provided... this must be pre 4.1
99
+			// because since 4.1 we're
100
+			return false;// changed mind. dont want people thinking they should migrate yet because they cant
101
+		} else {
102
+			//          echo "$version_string doesnt apply";
103
+			return false;
104
+		}
105
+	}
106
+
107
+
108
+	/**
109
+	 * @throws EE_Error
110
+	 * @throws ReflectionException
111
+	 */
112
+	public function schema_changes_before_migration()
113
+	{
114
+		// relies on 4.1's EEH_Activation::create_table
115
+		require_once(EE_HELPERS . 'EEH_Activation.helper.php');
116
+
117
+		$table_name = 'esp_answer';
118
+		$sql        = "ANS_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
119 119
 					REG_ID int(10) unsigned NOT NULL,
120 120
 					QST_ID int(10) unsigned NOT NULL,
121 121
 					ANS_value text NOT NULL,
122 122
 					PRIMARY KEY  (ANS_ID)";
123
-        $this->_table_is_new_in_this_version($table_name, $sql);
123
+		$this->_table_is_new_in_this_version($table_name, $sql);
124 124
 
125
-        $table_name = 'esp_attendee_meta';
126
-        $sql        = "ATTM_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
125
+		$table_name = 'esp_attendee_meta';
126
+		$sql        = "ATTM_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
127 127
 						ATT_ID bigint(20) unsigned NOT NULL,
128 128
 						ATT_fname varchar(45) NOT NULL,
129 129
 						ATT_lname varchar(45) NOT NULL,
@@ -139,10 +139,10 @@  discard block
 block discarded – undo
139 139
 								KEY ATT_fname (ATT_fname),
140 140
 								KEY ATT_lname (ATT_lname),
141 141
 								KEY ATT_email (ATT_email(191))";
142
-        $this->_table_is_new_in_this_version($table_name, $sql);
142
+		$this->_table_is_new_in_this_version($table_name, $sql);
143 143
 
144
-        $table_name = 'esp_country';
145
-        $sql        = "CNT_ISO varchar(2) COLLATE utf8_bin NOT NULL,
144
+		$table_name = 'esp_country';
145
+		$sql        = "CNT_ISO varchar(2) COLLATE utf8_bin NOT NULL,
146 146
 					  CNT_ISO3 varchar(3) COLLATE utf8_bin NOT NULL,
147 147
 					  RGN_ID tinyint(3) unsigned DEFAULT NULL,
148 148
 					  CNT_name varchar(45) COLLATE utf8_bin NOT NULL,
@@ -158,10 +158,10 @@  discard block
 block discarded – undo
158 158
 					  CNT_is_EU tinyint(1) DEFAULT '0',
159 159
 					  CNT_active tinyint(1) DEFAULT '0',
160 160
 					  PRIMARY KEY  (CNT_ISO)";
161
-        $this->_table_is_new_in_this_version($table_name, $sql);
161
+		$this->_table_is_new_in_this_version($table_name, $sql);
162 162
 
163
-        $table_name = 'esp_datetime';
164
-        $sql        = "DTT_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
163
+		$table_name = 'esp_datetime';
164
+		$sql        = "DTT_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
165 165
 				  EVT_ID bigint(20) unsigned NOT NULL,
166 166
 				  DTT_EVT_start datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
167 167
 				  DTT_EVT_end datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
@@ -174,10 +174,10 @@  discard block
 block discarded – undo
174 174
 						PRIMARY KEY  (DTT_ID),
175 175
 						KEY EVT_ID (EVT_ID),
176 176
 						KEY DTT_is_primary (DTT_is_primary)";
177
-        $this->_table_is_new_in_this_version($table_name, $sql);
177
+		$this->_table_is_new_in_this_version($table_name, $sql);
178 178
 
179
-        $table_name = 'esp_event_meta';
180
-        $sql        = "
179
+		$table_name = 'esp_event_meta';
180
+		$sql        = "
181 181
 			EVTM_ID int(10) NOT NULL AUTO_INCREMENT,
182 182
 			EVT_ID bigint(20) unsigned NOT NULL,
183 183
 			EVT_display_desc tinyint(1) unsigned NOT NULL DEFAULT 1,
@@ -192,35 +192,35 @@  discard block
 block discarded – undo
192 192
 			EVT_external_URL varchar(200) NULL,
193 193
 			EVT_donations tinyint(1) NULL,
194 194
 			PRIMARY KEY  (EVTM_ID)";
195
-        $this->_table_is_new_in_this_version($table_name, $sql);
195
+		$this->_table_is_new_in_this_version($table_name, $sql);
196 196
 
197
-        $table_name = 'esp_event_question_group';
198
-        $sql        = "EQG_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
197
+		$table_name = 'esp_event_question_group';
198
+		$sql        = "EQG_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
199 199
 					EVT_ID bigint(20) unsigned NOT NULL,
200 200
 					QSG_ID int(10) unsigned NOT NULL,
201 201
 					EQG_primary tinyint(1) unsigned NOT NULL DEFAULT 0,
202 202
 					PRIMARY KEY  (EQG_ID)";
203
-        $this->_table_is_new_in_this_version($table_name, $sql);
203
+		$this->_table_is_new_in_this_version($table_name, $sql);
204 204
 
205
-        $table_name = 'esp_event_venue';
206
-        $sql        = "EVV_ID int(11) NOT NULL AUTO_INCREMENT,
205
+		$table_name = 'esp_event_venue';
206
+		$sql        = "EVV_ID int(11) NOT NULL AUTO_INCREMENT,
207 207
 				EVT_ID bigint(20) unsigned NOT NULL,
208 208
 				VNU_ID bigint(20) unsigned NOT NULL,
209 209
 				EVV_primary tinyint(1) unsigned NOT NULL DEFAULT 0,
210 210
 				PRIMARY KEY  (EVV_ID)";
211
-        $this->_table_is_new_in_this_version($table_name, $sql);
211
+		$this->_table_is_new_in_this_version($table_name, $sql);
212 212
 
213
-        $table_name = 'esp_extra_meta';
214
-        $sql        = "EXM_ID int(11) NOT NULL AUTO_INCREMENT,
213
+		$table_name = 'esp_extra_meta';
214
+		$sql        = "EXM_ID int(11) NOT NULL AUTO_INCREMENT,
215 215
 				OBJ_ID int(11) DEFAULT NULL,
216 216
 				EXM_type varchar(45) DEFAULT NULL,
217 217
 				EXM_key varchar(45) DEFAULT NULL,
218 218
 				EXM_value text,
219 219
 				PRIMARY KEY  (EXM_ID)";
220
-        $this->_table_is_new_in_this_version($table_name, $sql);
220
+		$this->_table_is_new_in_this_version($table_name, $sql);
221 221
 
222
-        $table_name = 'esp_line_item';
223
-        $sql        = "LIN_ID int(11) NOT NULL AUTO_INCREMENT,
222
+		$table_name = 'esp_line_item';
223
+		$sql        = "LIN_ID int(11) NOT NULL AUTO_INCREMENT,
224 224
 				LIN_code varchar(245) NOT NULL DEFAULT '',
225 225
 				TXN_ID int(11) DEFAULT NULL,
226 226
 				LIN_name varchar(245) NOT NULL DEFAULT '',
@@ -236,20 +236,20 @@  discard block
 block discarded – undo
236 236
 				OBJ_ID int(11) DEFAULT NULL,
237 237
 				OBJ_type varchar(45)DEFAULT NULL,
238 238
 				PRIMARY KEY  (LIN_ID)";
239
-        $this->_table_is_new_in_this_version($table_name, $sql);
239
+		$this->_table_is_new_in_this_version($table_name, $sql);
240 240
 
241
-        $table_name = 'esp_message_template';
242
-        $sql        = "MTP_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
241
+		$table_name = 'esp_message_template';
242
+		$sql        = "MTP_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
243 243
 					GRP_ID int(10) unsigned NOT NULL,
244 244
 					MTP_context varchar(50) NOT NULL,
245 245
 					MTP_template_field varchar(30) NOT NULL,
246 246
 					MTP_content text NOT NULL,
247 247
 					PRIMARY KEY  (MTP_ID),
248 248
 					KEY GRP_ID (GRP_ID)";
249
-        $this->_table_is_new_in_this_version($table_name, $sql);
249
+		$this->_table_is_new_in_this_version($table_name, $sql);
250 250
 
251
-        $table_name = 'esp_message_template_group';
252
-        $sql        = "GRP_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
251
+		$table_name = 'esp_message_template_group';
252
+		$sql        = "GRP_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
253 253
 					EVT_ID bigint(20) unsigned DEFAULT NULL,
254 254
 					MTP_user_id int(10) NOT NULL DEFAULT '1',
255 255
 					MTP_messenger varchar(30) NOT NULL,
@@ -261,10 +261,10 @@  discard block
 block discarded – undo
261 261
 					PRIMARY KEY  (GRP_ID),
262 262
 					KEY EVT_ID (EVT_ID),
263 263
 					KEY MTP_user_id (MTP_user_id)";
264
-        $this->_table_is_new_in_this_version($table_name, $sql);
264
+		$this->_table_is_new_in_this_version($table_name, $sql);
265 265
 
266
-        $table_name = 'esp_payment';
267
-        $sql        = "PAY_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
266
+		$table_name = 'esp_payment';
267
+		$sql        = "PAY_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
268 268
 					TXN_ID int(10) unsigned DEFAULT NULL,
269 269
 					STS_ID varchar(3) COLLATE utf8_bin DEFAULT NULL,
270 270
 					PAY_timestamp datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
@@ -280,10 +280,10 @@  discard block
 block discarded – undo
280 280
 					PRIMARY KEY  (PAY_ID),
281 281
 					KEY TXN_ID (TXN_ID),
282 282
 					KEY PAY_timestamp (PAY_timestamp)";
283
-        $this->_table_is_new_in_this_version($table_name, $sql);
283
+		$this->_table_is_new_in_this_version($table_name, $sql);
284 284
 
285
-        $table_name = "esp_ticket";
286
-        $sql        = "TKT_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
285
+		$table_name = "esp_ticket";
286
+		$sql        = "TKT_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
287 287
 					  TTM_ID int(10) unsigned NOT NULL,
288 288
 					  TKT_name varchar(245) NOT NULL DEFAULT '',
289 289
 					  TKT_description text NOT NULL,
@@ -302,32 +302,32 @@  discard block
 block discarded – undo
302 302
 					  TKT_parent int(10) unsigned DEFAULT '0',
303 303
 					  TKT_deleted tinyint(1) NOT NULL DEFAULT '0',
304 304
 					  PRIMARY KEY  (TKT_ID)";
305
-        $this->_table_is_new_in_this_version($table_name, $sql);
305
+		$this->_table_is_new_in_this_version($table_name, $sql);
306 306
 
307
-        $table_name = "esp_ticket_price";
308
-        $sql        = "TKP_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
307
+		$table_name = "esp_ticket_price";
308
+		$sql        = "TKP_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
309 309
 					  TKT_ID int(10) unsigned NOT NULL,
310 310
 					  PRC_ID int(10) unsigned NOT NULL,
311 311
 					  PRIMARY KEY  (TKP_ID)";
312
-        $this->_table_is_new_in_this_version($table_name, $sql);
312
+		$this->_table_is_new_in_this_version($table_name, $sql);
313 313
 
314
-        $table_name = "esp_datetime_ticket";
315
-        $sql        = "DTK_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
314
+		$table_name = "esp_datetime_ticket";
315
+		$sql        = "DTK_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
316 316
 					  DTT_ID int(10) unsigned NOT NULL,
317 317
 					  TKT_ID int(10) unsigned NOT NULL,
318 318
 					  PRIMARY KEY  (DTK_ID)";
319
-        $this->_table_is_new_in_this_version($table_name, $sql);
319
+		$this->_table_is_new_in_this_version($table_name, $sql);
320 320
 
321
-        $table_name = "esp_ticket_template";
322
-        $sql        = "TTM_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
321
+		$table_name = "esp_ticket_template";
322
+		$sql        = "TTM_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
323 323
 					  TTM_name varchar(45) NOT NULL,
324 324
 					  TTM_description text,
325 325
 					  TTM_file varchar(45),
326 326
 					  PRIMARY KEY  (TTM_ID)";
327
-        $this->_table_is_new_in_this_version($table_name, $sql);
327
+		$this->_table_is_new_in_this_version($table_name, $sql);
328 328
 
329
-        $table_name = "esp_price";
330
-        $sql        = "PRC_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
329
+		$table_name = "esp_price";
330
+		$sql        = "PRC_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
331 331
 					  PRT_ID tinyint(3) unsigned NOT NULL,
332 332
 					  PRC_amount decimal(10,3) NOT NULL DEFAULT '0.00',
333 333
 					  PRC_name varchar(245) NOT NULL,
@@ -338,10 +338,10 @@  discard block
 block discarded – undo
338 338
 					  PRC_order tinyint(3) unsigned NOT NULL DEFAULT '0',
339 339
 					  PRC_parent int(10) unsigned DEFAULT 0,
340 340
 					  PRIMARY KEY  (PRC_ID)";
341
-        $this->_table_is_new_in_this_version($table_name, $sql);
341
+		$this->_table_is_new_in_this_version($table_name, $sql);
342 342
 
343
-        $table_name = "esp_price_type";
344
-        $sql        = "PRT_ID tinyint(3) unsigned NOT NULL AUTO_INCREMENT,
343
+		$table_name = "esp_price_type";
344
+		$sql        = "PRT_ID tinyint(3) unsigned NOT NULL AUTO_INCREMENT,
345 345
 				  PRT_name varchar(45) NOT NULL,
346 346
 				  PBT_ID tinyint(3) unsigned NOT NULL DEFAULT '1',
347 347
 				  PRT_is_percent tinyint(1) NOT NULL DEFAULT '0',
@@ -349,10 +349,10 @@  discard block
 block discarded – undo
349 349
 				  PRT_deleted tinyint(1) NOT NULL DEFAULT '0',
350 350
 				  UNIQUE KEY PRT_name_UNIQUE (PRT_name),
351 351
 				  PRIMARY KEY  (PRT_ID)";
352
-        $this->_table_is_new_in_this_version($table_name, $sql);
352
+		$this->_table_is_new_in_this_version($table_name, $sql);
353 353
 
354
-        $table_name = 'esp_question';
355
-        $sql        = 'QST_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
354
+		$table_name = 'esp_question';
355
+		$sql        = 'QST_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
356 356
 					QST_display_text text NOT NULL,
357 357
 					QST_admin_label varchar(255) NOT NULL,
358 358
 					QST_system varchar(25) DEFAULT NULL,
@@ -364,11 +364,11 @@  discard block
 block discarded – undo
364 364
 					QST_wp_user bigint(20) unsigned NULL,
365 365
 					QST_deleted tinyint(1) unsigned NOT NULL DEFAULT 0,
366 366
 					PRIMARY KEY  (QST_ID)';
367
-        $this->_table_is_new_in_this_version($table_name, $sql);
368
-        $this->_get_table_manager()->dropIndex('esp_question_group', 'QSG_identifier_UNIQUE');
367
+		$this->_table_is_new_in_this_version($table_name, $sql);
368
+		$this->_get_table_manager()->dropIndex('esp_question_group', 'QSG_identifier_UNIQUE');
369 369
 
370
-        $table_name = 'esp_question_group';
371
-        $sql        = 'QSG_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
370
+		$table_name = 'esp_question_group';
371
+		$sql        = 'QSG_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
372 372
 					QSG_name varchar(255) NOT NULL,
373 373
 					QSG_identifier varchar(100) NOT NULL,
374 374
 					QSG_desc text NULL,
@@ -379,26 +379,26 @@  discard block
 block discarded – undo
379 379
 					QSG_deleted tinyint(1) unsigned NOT NULL DEFAULT 0,
380 380
 					PRIMARY KEY  (QSG_ID),
381 381
 					UNIQUE KEY QSG_identifier_UNIQUE (QSG_identifier ASC)';
382
-        $this->_table_is_new_in_this_version($table_name, $sql);
382
+		$this->_table_is_new_in_this_version($table_name, $sql);
383 383
 
384
-        $table_name = 'esp_question_group_question';
385
-        $sql        = "QGQ_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
384
+		$table_name = 'esp_question_group_question';
385
+		$sql        = "QGQ_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
386 386
 					QSG_ID int(10) unsigned NOT NULL,
387 387
 					QST_ID int(10) unsigned NOT NULL,
388 388
 					PRIMARY KEY  (QGQ_ID) ";
389
-        $this->_table_is_new_in_this_version($table_name, $sql);
389
+		$this->_table_is_new_in_this_version($table_name, $sql);
390 390
 
391
-        $table_name = 'esp_question_option';
392
-        $sql        = "QSO_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
391
+		$table_name = 'esp_question_option';
392
+		$sql        = "QSO_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
393 393
 					QSO_value varchar(255) NOT NULL,
394 394
 					QSO_desc text NOT NULL,
395 395
 					QST_ID int(10) unsigned NOT NULL,
396 396
 					QSO_deleted tinyint(1) unsigned NOT NULL DEFAULT 0,
397 397
 					PRIMARY KEY  (QSO_ID)";
398
-        $this->_table_is_new_in_this_version($table_name, $sql);
398
+		$this->_table_is_new_in_this_version($table_name, $sql);
399 399
 
400
-        $table_name = 'esp_registration';
401
-        $sql        = "REG_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
400
+		$table_name = 'esp_registration';
401
+		$sql        = "REG_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
402 402
 					  EVT_ID bigint(20) unsigned NOT NULL,
403 403
 					  ATT_ID bigint(20) unsigned NOT NULL,
404 404
 					  TXN_ID int(10) unsigned NOT NULL,
@@ -421,28 +421,28 @@  discard block
 block discarded – undo
421 421
 					  KEY STS_ID (STS_ID),
422 422
 					  KEY REG_url_link (REG_url_link),
423 423
 					  KEY REG_code (REG_code)";
424
-        $this->_table_is_new_in_this_version($table_name, $sql);
424
+		$this->_table_is_new_in_this_version($table_name, $sql);
425 425
 
426
-        $table_name = 'esp_checkin';
427
-        $sql        = "CHK_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
426
+		$table_name = 'esp_checkin';
427
+		$sql        = "CHK_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
428 428
 					REG_ID int(10) unsigned NOT NULL,
429 429
 					DTT_ID int(10) unsigned NOT NULL,
430 430
 					CHK_in tinyint(1) unsigned NOT NULL DEFAULT 1,
431 431
 					CHK_timestamp datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
432 432
 					PRIMARY KEY  (CHK_ID)";
433
-        $this->_table_is_new_in_this_version($table_name, $sql);
433
+		$this->_table_is_new_in_this_version($table_name, $sql);
434 434
 
435
-        $table_name = 'esp_state';
436
-        $sql        = "STA_ID smallint(5) unsigned NOT NULL AUTO_INCREMENT,
435
+		$table_name = 'esp_state';
436
+		$sql        = "STA_ID smallint(5) unsigned NOT NULL AUTO_INCREMENT,
437 437
 					  CNT_ISO varchar(2) COLLATE utf8_bin NOT NULL,
438 438
 					  STA_abbrev varchar(6) COLLATE utf8_bin NOT NULL,
439 439
 					  STA_name varchar(100) COLLATE utf8_bin NOT NULL,
440 440
 					  STA_active tinyint(1) DEFAULT '1',
441 441
 					  PRIMARY KEY  (STA_ID)";
442
-        $this->_table_is_new_in_this_version($table_name, $sql);
442
+		$this->_table_is_new_in_this_version($table_name, $sql);
443 443
 
444
-        $table_name = 'esp_status';
445
-        $sql        = "STS_ID varchar(3) COLLATE utf8_bin NOT NULL,
444
+		$table_name = 'esp_status';
445
+		$sql        = "STS_ID varchar(3) COLLATE utf8_bin NOT NULL,
446 446
 					  STS_code varchar(45) COLLATE utf8_bin NOT NULL,
447 447
 					  STS_type set('event','registration','transaction','payment','email') COLLATE utf8_bin NOT NULL,
448 448
 					  STS_can_edit tinyint(1) NOT NULL DEFAULT 0,
@@ -450,10 +450,10 @@  discard block
 block discarded – undo
450 450
 					  STS_open tinyint(1) NOT NULL DEFAULT 1,
451 451
 					  UNIQUE KEY STS_ID_UNIQUE (STS_ID),
452 452
 					  KEY STS_type (STS_type)";
453
-        $this->_table_is_new_in_this_version($table_name, $sql);
453
+		$this->_table_is_new_in_this_version($table_name, $sql);
454 454
 
455
-        $table_name = 'esp_transaction';
456
-        $sql        = "TXN_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
455
+		$table_name = 'esp_transaction';
456
+		$sql        = "TXN_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
457 457
 					  TXN_timestamp datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
458 458
 					  TXN_total decimal(10,3) DEFAULT '0.00',
459 459
 					  TXN_paid decimal(10,3) NOT NULL DEFAULT '0.00',
@@ -463,10 +463,10 @@  discard block
 block discarded – undo
463 463
 					  PRIMARY KEY  (TXN_ID),
464 464
 					  KEY TXN_timestamp (TXN_timestamp),
465 465
 					  KEY STS_ID (STS_ID)";
466
-        $this->_table_is_new_in_this_version($table_name, $sql);
466
+		$this->_table_is_new_in_this_version($table_name, $sql);
467 467
 
468
-        $table_name = 'esp_venue_meta';
469
-        $sql        = "VNUM_ID int(11) NOT NULL AUTO_INCREMENT,
468
+		$table_name = 'esp_venue_meta';
469
+		$sql        = "VNUM_ID int(11) NOT NULL AUTO_INCREMENT,
470 470
 			VNU_ID bigint(20) unsigned NOT NULL DEFAULT 0,
471 471
 			VNU_address varchar(255) DEFAULT NULL,
472 472
 			VNU_address2 varchar(255) DEFAULT NULL,
@@ -484,51 +484,51 @@  discard block
 block discarded – undo
484 484
 			PRIMARY KEY  (VNUM_ID),
485 485
 			KEY STA_ID (STA_ID),
486 486
 			KEY CNT_ISO (CNT_ISO)";
487
-        $this->_table_is_new_in_this_version($table_name, $sql);
488
-        // setting up the default stats and countries is also essential for the data migrations to run
489
-        // (because many need to convert old string states to foreign keys into the states table)
490
-        $this->insert_default_states();
491
-        $this->insert_default_countries();
492
-        // setting up default prices, price types, and tickets is also essential for the price migrations
493
-        $this->insert_default_price_types();
494
-        $this->insert_default_prices();
495
-        $this->insert_default_tickets();
496
-        // setting up the config wp option pretty well counts as a 'schema change', or at least should happen here
497
-        EE_Config::instance()->update_espresso_config();
498
-        return true;
499
-    }
500
-
501
-
502
-    /**
503
-     * Yes we could have cleaned up the ee3 tables here. But just in case someone
504
-     * didn't backup their DB, and decides they want ot keep using EE3, we'll
505
-     * leave them for now. Maybe remove them in 4.5 or something.
506
-     *
507
-     * @return boolean
508
-     */
509
-    public function schema_changes_after_migration()
510
-    {
511
-        return true;
512
-    }
513
-
514
-
515
-    /**
516
-     * insert_default_states
517
-     *
518
-     * @access public
519
-     * @static
520
-     * @return void
521
-     * @throws EE_Error
522
-     */
523
-    public function insert_default_states()
524
-    {
525
-        global $wpdb;
526
-        $state_table = $wpdb->prefix . "esp_state";
527
-        if ($this->_get_table_analysis()->tableExists($state_table)) {
528
-            $SQL    = "SELECT COUNT('STA_ID') FROM " . $state_table;
529
-            $states = $wpdb->get_var($SQL);
530
-            if (! $states) {
531
-                $SQL = "INSERT INTO " . $state_table . "
487
+		$this->_table_is_new_in_this_version($table_name, $sql);
488
+		// setting up the default stats and countries is also essential for the data migrations to run
489
+		// (because many need to convert old string states to foreign keys into the states table)
490
+		$this->insert_default_states();
491
+		$this->insert_default_countries();
492
+		// setting up default prices, price types, and tickets is also essential for the price migrations
493
+		$this->insert_default_price_types();
494
+		$this->insert_default_prices();
495
+		$this->insert_default_tickets();
496
+		// setting up the config wp option pretty well counts as a 'schema change', or at least should happen here
497
+		EE_Config::instance()->update_espresso_config();
498
+		return true;
499
+	}
500
+
501
+
502
+	/**
503
+	 * Yes we could have cleaned up the ee3 tables here. But just in case someone
504
+	 * didn't backup their DB, and decides they want ot keep using EE3, we'll
505
+	 * leave them for now. Maybe remove them in 4.5 or something.
506
+	 *
507
+	 * @return boolean
508
+	 */
509
+	public function schema_changes_after_migration()
510
+	{
511
+		return true;
512
+	}
513
+
514
+
515
+	/**
516
+	 * insert_default_states
517
+	 *
518
+	 * @access public
519
+	 * @static
520
+	 * @return void
521
+	 * @throws EE_Error
522
+	 */
523
+	public function insert_default_states()
524
+	{
525
+		global $wpdb;
526
+		$state_table = $wpdb->prefix . "esp_state";
527
+		if ($this->_get_table_analysis()->tableExists($state_table)) {
528
+			$SQL    = "SELECT COUNT('STA_ID') FROM " . $state_table;
529
+			$states = $wpdb->get_var($SQL);
530
+			if (! $states) {
531
+				$SQL = "INSERT INTO " . $state_table . "
532 532
 				(STA_ID, CNT_ISO, STA_abbrev, STA_name, STA_active) VALUES
533 533
 				(1, 'US', 'AK', 'Alaska', 1),
534 534
 				(2, 'US', 'AL', 'Alabama', 1),
@@ -602,29 +602,29 @@  discard block
 block discarded – undo
602 602
 				(70, 'CA', 'NT', 'Northwest Territories', 1),
603 603
 				(71, 'CA', 'NU', 'Nunavut', 1),
604 604
 				(72, 'CA', 'YT', 'Yukon', 1);";
605
-                $wpdb->query($SQL);
606
-            }
607
-        }
608
-    }
609
-
610
-
611
-    /**
612
-     * insert_default_countries
613
-     *
614
-     * @access public
615
-     * @static
616
-     * @return void
617
-     * @throws EE_Error
618
-     */
619
-    public function insert_default_countries()
620
-    {
621
-        global $wpdb;
622
-        $country_table = $wpdb->prefix . "esp_country";
623
-        if ($this->_get_table_analysis()->tableExists($country_table)) {
624
-            $SQL       = "SELECT COUNT('CNT_ISO') FROM " . $country_table;
625
-            $countries = $wpdb->get_var($SQL);
626
-            if (! $countries) {
627
-                $SQL = "INSERT INTO " . $country_table . "
605
+				$wpdb->query($SQL);
606
+			}
607
+		}
608
+	}
609
+
610
+
611
+	/**
612
+	 * insert_default_countries
613
+	 *
614
+	 * @access public
615
+	 * @static
616
+	 * @return void
617
+	 * @throws EE_Error
618
+	 */
619
+	public function insert_default_countries()
620
+	{
621
+		global $wpdb;
622
+		$country_table = $wpdb->prefix . "esp_country";
623
+		if ($this->_get_table_analysis()->tableExists($country_table)) {
624
+			$SQL       = "SELECT COUNT('CNT_ISO') FROM " . $country_table;
625
+			$countries = $wpdb->get_var($SQL);
626
+			if (! $countries) {
627
+				$SQL = "INSERT INTO " . $country_table . "
628 628
 				(CNT_ISO, CNT_ISO3, RGN_ID, CNT_name, CNT_cur_code, CNT_cur_single, CNT_cur_plural, CNT_cur_sign, CNT_cur_sign_b4, CNT_cur_dec_plc, CNT_tel_code, CNT_is_EU, CNT_active) VALUES
629 629
 				('AD', 'AND', 0, 'Andorra', 'EUR', 'Euro', 'Euros', '€', 1, 2, '+376', 0, 0),
630 630
 				('AE', 'ARE', 0, 'United Arab Emirates', 'AED', 'Dirham', 'Dirhams', 'د.إ', 1, 2, '+971', 0, 0),
@@ -852,1051 +852,1051 @@  discard block
 block discarded – undo
852 852
 				('ZA', 'ZAF', 0, 'South Africa', 'ZAR', 'Rand', 'Rands', 'R', 1, 2, '+27', 0, 0),
853 853
 				('ZM', 'ZMB', 0, 'Zambia', 'ZMK', 'Kwacha', 'Kwachas', '', 1, 2, '+260', 0, 0),
854 854
 				('ZW', 'ZWE', 0, 'Zimbabwe', 'ZWD', 'Dollar', 'Dollars', 'Z$', 1, 2, '+263', 0, 0);";
855
-                $wpdb->query($SQL);
856
-            }
857
-        }
858
-    }
859
-
860
-
861
-    /**
862
-     * insert_default_price_types
863
-     *
864
-     * @access public
865
-     * @static
866
-     * @return void
867
-     * @throws EE_Error
868
-     */
869
-    public function insert_default_price_types()
870
-    {
871
-        global $wpdb;
872
-        $price_type_table = $wpdb->prefix . "esp_price_type";
873
-        if ($this->_get_table_analysis()->tableExists($price_type_table)) {
874
-            $SQL               = 'SELECT COUNT(PRT_ID) FROM ' . $price_type_table;
875
-            $price_types_exist = $wpdb->get_var($SQL);
876
-            if (! $price_types_exist) {
877
-                $SQL = "INSERT INTO $price_type_table ( PRT_ID, PRT_name, PBT_ID, PRT_is_percent, PRT_order, PRT_deleted ) VALUES
855
+				$wpdb->query($SQL);
856
+			}
857
+		}
858
+	}
859
+
860
+
861
+	/**
862
+	 * insert_default_price_types
863
+	 *
864
+	 * @access public
865
+	 * @static
866
+	 * @return void
867
+	 * @throws EE_Error
868
+	 */
869
+	public function insert_default_price_types()
870
+	{
871
+		global $wpdb;
872
+		$price_type_table = $wpdb->prefix . "esp_price_type";
873
+		if ($this->_get_table_analysis()->tableExists($price_type_table)) {
874
+			$SQL               = 'SELECT COUNT(PRT_ID) FROM ' . $price_type_table;
875
+			$price_types_exist = $wpdb->get_var($SQL);
876
+			if (! $price_types_exist) {
877
+				$SQL = "INSERT INTO $price_type_table ( PRT_ID, PRT_name, PBT_ID, PRT_is_percent, PRT_order, PRT_deleted ) VALUES
878 878
 							(1, '" . esc_html__('Base Price', 'event_espresso') . "', 1,  0, 0, 0),
879 879
 							(2, '" . esc_html__('Percent Discount', 'event_espresso') . "', 2,  1, 20, 0),
880 880
 							(3, '" . esc_html__('Fixed Discount', 'event_espresso') . "', 2,  0, 30, 0),
881 881
 							(4, '" . esc_html__('Percent Surcharge', 'event_espresso') . "', 3,  1, 40, 0),
882 882
 							(5, '" . esc_html__('Fixed Surcharge', 'event_espresso') . "', 3,  0, 50, 0);";
883
-                $SQL = apply_filters('FHEE__EE_DMS_4_1_0__insert_default_price_types__SQL', $SQL);
884
-                $wpdb->query($SQL);
885
-            }
886
-        }
887
-    }
888
-
889
-
890
-    /**
891
-     * insert_default_prices. We assume we're upgrading to regular here.
892
-     * If we're INSTALLING 4.1 CAF, then we add a few extra default prices
893
-     * when EEH_Activation's initialize_db_content is called via a hook in
894
-     * EE_Brewing_regular
895
-     *
896
-     * @access public
897
-     * @static
898
-     * @return void
899
-     * @throws EE_Error
900
-     */
901
-    public function insert_default_prices()
902
-    {
903
-        global $wpdb;
904
-        $price_table = $wpdb->prefix . "esp_price";
905
-        if ($this->_get_table_analysis()->tableExists($price_table)) {
906
-            $SQL          = 'SELECT COUNT(PRC_ID) FROM ' . $price_table;
907
-            $prices_exist = $wpdb->get_var($SQL);
908
-            if (! $prices_exist) {
909
-                $SQL = "INSERT INTO $price_table
883
+				$SQL = apply_filters('FHEE__EE_DMS_4_1_0__insert_default_price_types__SQL', $SQL);
884
+				$wpdb->query($SQL);
885
+			}
886
+		}
887
+	}
888
+
889
+
890
+	/**
891
+	 * insert_default_prices. We assume we're upgrading to regular here.
892
+	 * If we're INSTALLING 4.1 CAF, then we add a few extra default prices
893
+	 * when EEH_Activation's initialize_db_content is called via a hook in
894
+	 * EE_Brewing_regular
895
+	 *
896
+	 * @access public
897
+	 * @static
898
+	 * @return void
899
+	 * @throws EE_Error
900
+	 */
901
+	public function insert_default_prices()
902
+	{
903
+		global $wpdb;
904
+		$price_table = $wpdb->prefix . "esp_price";
905
+		if ($this->_get_table_analysis()->tableExists($price_table)) {
906
+			$SQL          = 'SELECT COUNT(PRC_ID) FROM ' . $price_table;
907
+			$prices_exist = $wpdb->get_var($SQL);
908
+			if (! $prices_exist) {
909
+				$SQL = "INSERT INTO $price_table
910 910
 							(PRC_ID, PRT_ID, PRC_amount, PRC_name, PRC_desc,  PRC_is_default, PRC_overrides, PRC_order, PRC_deleted, PRC_parent ) VALUES
911 911
 							(1, 1, '0.00', 'Admission', '', 1, null, 0, 0, 0);";
912
-                $SQL = apply_filters('FHEE__EE_DMS_4_1_0__insert_default_prices__SQL', $SQL);
913
-                $wpdb->query($SQL);
914
-            }
915
-        }
916
-    }
917
-
918
-
919
-    /**
920
-     * insert default ticket
921
-     *
922
-     * @access public
923
-     * @static
924
-     * @return void
925
-     * @throws EE_Error
926
-     * @throws EE_Error
927
-     */
928
-    public function insert_default_tickets()
929
-    {
930
-        global $wpdb;
931
-        $ticket_table = $wpdb->prefix . "esp_ticket";
932
-        if ($this->_get_table_analysis()->tableExists($ticket_table)) {
933
-            $SQL           = 'SELECT COUNT(TKT_ID) FROM ' . $ticket_table;
934
-            $tickets_exist = $wpdb->get_var($SQL);
935
-            if (! $tickets_exist) {
936
-                $SQL = "INSERT INTO $ticket_table
912
+				$SQL = apply_filters('FHEE__EE_DMS_4_1_0__insert_default_prices__SQL', $SQL);
913
+				$wpdb->query($SQL);
914
+			}
915
+		}
916
+	}
917
+
918
+
919
+	/**
920
+	 * insert default ticket
921
+	 *
922
+	 * @access public
923
+	 * @static
924
+	 * @return void
925
+	 * @throws EE_Error
926
+	 * @throws EE_Error
927
+	 */
928
+	public function insert_default_tickets()
929
+	{
930
+		global $wpdb;
931
+		$ticket_table = $wpdb->prefix . "esp_ticket";
932
+		if ($this->_get_table_analysis()->tableExists($ticket_table)) {
933
+			$SQL           = 'SELECT COUNT(TKT_ID) FROM ' . $ticket_table;
934
+			$tickets_exist = $wpdb->get_var($SQL);
935
+			if (! $tickets_exist) {
936
+				$SQL = "INSERT INTO $ticket_table
937 937
 					( TKT_ID, TTM_ID, TKT_name, TKT_description, TKT_qty, TKT_sold, TKT_uses, TKT_min, TKT_max, TKT_price, TKT_start_date, TKT_end_date, TKT_taxable, TKT_order, TKT_row, TKT_is_default, TKT_parent, TKT_deleted ) VALUES
938 938
 					( 1, 0, '" .
939
-                       esc_html__("Free Ticket", "event_espresso") .
940
-                       "', '', 100, 0, -1, 0, -1, 0.00, '0000-00-00 00:00:00', '0000-00-00 00:00:00', 0, 0, 1, 1, 0, 0);";
941
-                $SQL = apply_filters('FHEE__EE_DMS_4_1_0__insert_default_tickets__SQL', $SQL);
942
-                $wpdb->query($SQL);
943
-            }
944
-        }
945
-        $ticket_price_table = $wpdb->prefix . "esp_ticket_price";
946
-        if ($this->_get_table_analysis()->tableExists($ticket_price_table)) {
947
-            $SQL              = 'SELECT COUNT(TKP_ID) FROM ' . $ticket_price_table;
948
-            $ticket_prc_exist = $wpdb->get_var($SQL);
949
-            if (! $ticket_prc_exist) {
950
-                $SQL = "INSERT INTO $ticket_price_table
939
+					   esc_html__("Free Ticket", "event_espresso") .
940
+					   "', '', 100, 0, -1, 0, -1, 0.00, '0000-00-00 00:00:00', '0000-00-00 00:00:00', 0, 0, 1, 1, 0, 0);";
941
+				$SQL = apply_filters('FHEE__EE_DMS_4_1_0__insert_default_tickets__SQL', $SQL);
942
+				$wpdb->query($SQL);
943
+			}
944
+		}
945
+		$ticket_price_table = $wpdb->prefix . "esp_ticket_price";
946
+		if ($this->_get_table_analysis()->tableExists($ticket_price_table)) {
947
+			$SQL              = 'SELECT COUNT(TKP_ID) FROM ' . $ticket_price_table;
948
+			$ticket_prc_exist = $wpdb->get_var($SQL);
949
+			if (! $ticket_prc_exist) {
950
+				$SQL = "INSERT INTO $ticket_price_table
951 951
 				( TKP_ID, TKT_ID, PRC_ID ) VALUES
952 952
 				( 1, 1, 1 )
953 953
 				";
954
-                $SQL = apply_filters('FHEE__EE_DMS_4_1_0__insert_default_tickets__SQL__ticket_price', $SQL);
955
-                $wpdb->query($SQL);
956
-            }
957
-        }
958
-    }
959
-
960
-
961
-    /**
962
-     * Gets a country entry as an array, or creates one if none is found. Much like EEM_Country::instance()->get_one(),
963
-     * but is independent of outside code which can change in future versions of EE. Also, $country_name CAN be a 3.1
964
-     * country ID (int), a 2-letter ISO, 3-letter ISO, or name
965
-     *
966
-     * @param int|string $country_name or country ID
967
-     * @return array where keys are columns, values are column values
968
-     * @throws EE_Error
969
-     * @throws EE_Error
970
-     * @global wpdb      $wpdb
971
-     */
972
-    public function get_or_create_country($country_name): array
973
-    {
974
-        if (! $country_name) {
975
-            throw new EE_Error(esc_html__("Could not get a country because country name is blank", "event_espresso"));
976
-        }
977
-        global $wpdb;
978
-        $country_table = $wpdb->prefix . "esp_country";
979
-        if (is_int($country_name)) {
980
-            $country_name = $this->get_iso_from_3_1_country_id($country_name);
981
-        }
982
-        $country = $wpdb->get_row(
983
-            $wpdb->prepare(
984
-                "SELECT * FROM $country_table WHERE
954
+				$SQL = apply_filters('FHEE__EE_DMS_4_1_0__insert_default_tickets__SQL__ticket_price', $SQL);
955
+				$wpdb->query($SQL);
956
+			}
957
+		}
958
+	}
959
+
960
+
961
+	/**
962
+	 * Gets a country entry as an array, or creates one if none is found. Much like EEM_Country::instance()->get_one(),
963
+	 * but is independent of outside code which can change in future versions of EE. Also, $country_name CAN be a 3.1
964
+	 * country ID (int), a 2-letter ISO, 3-letter ISO, or name
965
+	 *
966
+	 * @param int|string $country_name or country ID
967
+	 * @return array where keys are columns, values are column values
968
+	 * @throws EE_Error
969
+	 * @throws EE_Error
970
+	 * @global wpdb      $wpdb
971
+	 */
972
+	public function get_or_create_country($country_name): array
973
+	{
974
+		if (! $country_name) {
975
+			throw new EE_Error(esc_html__("Could not get a country because country name is blank", "event_espresso"));
976
+		}
977
+		global $wpdb;
978
+		$country_table = $wpdb->prefix . "esp_country";
979
+		if (is_int($country_name)) {
980
+			$country_name = $this->get_iso_from_3_1_country_id($country_name);
981
+		}
982
+		$country = $wpdb->get_row(
983
+			$wpdb->prepare(
984
+				"SELECT * FROM $country_table WHERE
985 985
 			CNT_ISO LIKE %s OR
986 986
 			CNT_ISO3 LIKE %s OR
987 987
 			CNT_name LIKE %s LIMIT 1",
988
-                $country_name,
989
-                $country_name,
990
-                $country_name
991
-            ),
992
-            ARRAY_A
993
-        );
994
-        if (! $country) {
995
-            // insert a new one then
996
-            $cols_n_values = [
997
-                'CNT_ISO'         => $this->_find_available_country_iso(),
998
-                'CNT_ISO3'        => $this->_find_available_country_iso(3),
999
-                'RGN_ID'          => 0,
1000
-                'CNT_name'        => $country_name,
1001
-                'CNT_cur_code'    => 'USD',
1002
-                'CNT_cur_single'  => 'Dollar',
1003
-                'CNT_cur_plural'  => 'Dollars',
1004
-                'CNT_cur_sign'    => '&#36;',
1005
-                'CNT_cur_sign_b4' => true,
1006
-                'CNT_cur_dec_plc' => 2,
1007
-                'CNT_cur_dec_mrk' => '.',
1008
-                'CNT_cur_thsnds'  => ',',
1009
-                'CNT_tel_code'    => '+1',
1010
-                'CNT_is_EU'       => false,
1011
-                'CNT_active'      => true,
1012
-            ];
1013
-            $data_types    = [
1014
-                '%s',// CNT_ISO
1015
-                '%s',// CNT_ISO3
1016
-                '%d',// RGN_ID
1017
-                '%s',// CNT_name
1018
-                '%s',// CNT_cur_code
1019
-                '%s',// CNT_cur_single
1020
-                '%s',// CNT_cur_plural
1021
-                '%s',// CNT_cur_sign
1022
-                '%d',// CNT_cur_sign_b4
1023
-                '%d',// CNT_cur_dec_plc
1024
-                '%s',// CNT_cur_dec_mrk
1025
-                '%s',// CNT_cur_thsnds
1026
-                '%s',// CNT_tel_code
1027
-                '%d',// CNT_is_EU
1028
-                '%d',// CNT_active
1029
-            ];
1030
-            $success       = $wpdb->insert(
1031
-                $country_table,
1032
-                $cols_n_values,
1033
-                $data_types
1034
-            );
1035
-            if (! $success) {
1036
-                throw new EE_Error(
1037
-                    $this->_create_error_message_for_db_insertion(
1038
-                        'N/A',
1039
-                        ['country_id' => $country_name],
1040
-                        $country_table,
1041
-                        $cols_n_values,
1042
-                        $data_types
1043
-                    )
1044
-                );
1045
-            }
1046
-            $country = $cols_n_values;
1047
-        }
1048
-        return $country;
1049
-    }
1050
-
1051
-
1052
-    /**
1053
-     * finds a country iso which hasn't been used yet
1054
-     *
1055
-     * @param int   $num_letters
1056
-     * @return string
1057
-     * @global wpdb $wpdb
1058
-     */
1059
-    private function _find_available_country_iso(int $num_letters = 2): string
1060
-    {
1061
-        global $wpdb;
1062
-        $country_table = $wpdb->prefix . "esp_country";
1063
-        $attempts      = 0;
1064
-        do {
1065
-            $current_iso           = strtoupper(wp_generate_password($num_letters, false));
1066
-            $country_with_that_iso = $wpdb->get_var(
1067
-                $wpdb->prepare(
1068
-                    "SELECT count(CNT_ISO) FROM " . $country_table . " WHERE CNT_ISO=%s",
1069
-                    $current_iso
1070
-                )
1071
-            );
1072
-            $attempts++;
1073
-            // keep going until we find an available country code, or we arbitrarily
1074
-            // decide we've tried this enough. Somehow they have way too many countries
1075
-            // (probably because they're mis-using the EE3 country_id like a custom question)
1076
-        } while (intval($country_with_that_iso) && $attempts < 200);
1077
-        return $current_iso;
1078
-    }
1079
-
1080
-
1081
-    /**
1082
-     * Gets a state entry as an array, or creates one if none is found. Much like EEM_State::instance()->get_one(), but
1083
-     * is independent of outside code which can change in future versions of EE
1084
-     *
1085
-     * @param string     $state_name
1086
-     * @param int|string $country_name
1087
-     * @return array where keys are columns, values are column values
1088
-     * @throws EE_Error
1089
-     * @global wpdb      $wpdb
1090
-     */
1091
-    public function get_or_create_state(string $state_name, $country_name = ''): array
1092
-    {
1093
-        if (! $state_name) {
1094
-            throw new EE_Error(
1095
-                esc_html__(
1096
-                    "Could not get-or-create state because no state name was provided",
1097
-                    "event_espresso"
1098
-                )
1099
-            );
1100
-        }
1101
-        try {
1102
-            $country     = $this->get_or_create_country($country_name);
1103
-            $country_iso = $country['CNT_ISO'];
1104
-        } catch (EE_Error $e) {
1105
-            $country_iso = $this->get_default_country_iso();
1106
-        }
1107
-        global $wpdb;
1108
-        $state_table = $wpdb->prefix . "esp_state";
1109
-        $state       = $wpdb->get_row(
1110
-            $wpdb->prepare(
1111
-                "SELECT * FROM $state_table WHERE
988
+				$country_name,
989
+				$country_name,
990
+				$country_name
991
+			),
992
+			ARRAY_A
993
+		);
994
+		if (! $country) {
995
+			// insert a new one then
996
+			$cols_n_values = [
997
+				'CNT_ISO'         => $this->_find_available_country_iso(),
998
+				'CNT_ISO3'        => $this->_find_available_country_iso(3),
999
+				'RGN_ID'          => 0,
1000
+				'CNT_name'        => $country_name,
1001
+				'CNT_cur_code'    => 'USD',
1002
+				'CNT_cur_single'  => 'Dollar',
1003
+				'CNT_cur_plural'  => 'Dollars',
1004
+				'CNT_cur_sign'    => '&#36;',
1005
+				'CNT_cur_sign_b4' => true,
1006
+				'CNT_cur_dec_plc' => 2,
1007
+				'CNT_cur_dec_mrk' => '.',
1008
+				'CNT_cur_thsnds'  => ',',
1009
+				'CNT_tel_code'    => '+1',
1010
+				'CNT_is_EU'       => false,
1011
+				'CNT_active'      => true,
1012
+			];
1013
+			$data_types    = [
1014
+				'%s',// CNT_ISO
1015
+				'%s',// CNT_ISO3
1016
+				'%d',// RGN_ID
1017
+				'%s',// CNT_name
1018
+				'%s',// CNT_cur_code
1019
+				'%s',// CNT_cur_single
1020
+				'%s',// CNT_cur_plural
1021
+				'%s',// CNT_cur_sign
1022
+				'%d',// CNT_cur_sign_b4
1023
+				'%d',// CNT_cur_dec_plc
1024
+				'%s',// CNT_cur_dec_mrk
1025
+				'%s',// CNT_cur_thsnds
1026
+				'%s',// CNT_tel_code
1027
+				'%d',// CNT_is_EU
1028
+				'%d',// CNT_active
1029
+			];
1030
+			$success       = $wpdb->insert(
1031
+				$country_table,
1032
+				$cols_n_values,
1033
+				$data_types
1034
+			);
1035
+			if (! $success) {
1036
+				throw new EE_Error(
1037
+					$this->_create_error_message_for_db_insertion(
1038
+						'N/A',
1039
+						['country_id' => $country_name],
1040
+						$country_table,
1041
+						$cols_n_values,
1042
+						$data_types
1043
+					)
1044
+				);
1045
+			}
1046
+			$country = $cols_n_values;
1047
+		}
1048
+		return $country;
1049
+	}
1050
+
1051
+
1052
+	/**
1053
+	 * finds a country iso which hasn't been used yet
1054
+	 *
1055
+	 * @param int   $num_letters
1056
+	 * @return string
1057
+	 * @global wpdb $wpdb
1058
+	 */
1059
+	private function _find_available_country_iso(int $num_letters = 2): string
1060
+	{
1061
+		global $wpdb;
1062
+		$country_table = $wpdb->prefix . "esp_country";
1063
+		$attempts      = 0;
1064
+		do {
1065
+			$current_iso           = strtoupper(wp_generate_password($num_letters, false));
1066
+			$country_with_that_iso = $wpdb->get_var(
1067
+				$wpdb->prepare(
1068
+					"SELECT count(CNT_ISO) FROM " . $country_table . " WHERE CNT_ISO=%s",
1069
+					$current_iso
1070
+				)
1071
+			);
1072
+			$attempts++;
1073
+			// keep going until we find an available country code, or we arbitrarily
1074
+			// decide we've tried this enough. Somehow they have way too many countries
1075
+			// (probably because they're mis-using the EE3 country_id like a custom question)
1076
+		} while (intval($country_with_that_iso) && $attempts < 200);
1077
+		return $current_iso;
1078
+	}
1079
+
1080
+
1081
+	/**
1082
+	 * Gets a state entry as an array, or creates one if none is found. Much like EEM_State::instance()->get_one(), but
1083
+	 * is independent of outside code which can change in future versions of EE
1084
+	 *
1085
+	 * @param string     $state_name
1086
+	 * @param int|string $country_name
1087
+	 * @return array where keys are columns, values are column values
1088
+	 * @throws EE_Error
1089
+	 * @global wpdb      $wpdb
1090
+	 */
1091
+	public function get_or_create_state(string $state_name, $country_name = ''): array
1092
+	{
1093
+		if (! $state_name) {
1094
+			throw new EE_Error(
1095
+				esc_html__(
1096
+					"Could not get-or-create state because no state name was provided",
1097
+					"event_espresso"
1098
+				)
1099
+			);
1100
+		}
1101
+		try {
1102
+			$country     = $this->get_or_create_country($country_name);
1103
+			$country_iso = $country['CNT_ISO'];
1104
+		} catch (EE_Error $e) {
1105
+			$country_iso = $this->get_default_country_iso();
1106
+		}
1107
+		global $wpdb;
1108
+		$state_table = $wpdb->prefix . "esp_state";
1109
+		$state       = $wpdb->get_row(
1110
+			$wpdb->prepare(
1111
+				"SELECT * FROM $state_table WHERE
1112 1112
 			(STA_abbrev LIKE %s OR
1113 1113
 			STA_name LIKE %s) AND
1114 1114
 			CNT_ISO LIKE %s LIMIT 1",
1115
-                $state_name,
1116
-                $state_name,
1117
-                $country_iso
1118
-            ),
1119
-            ARRAY_A
1120
-        );
1121
-        if (! $state) {
1122
-            // insert a new one then
1123
-            $cols_n_values = [
1124
-                'CNT_ISO'    => $country_iso,
1125
-                'STA_abbrev' => substr($state_name, 0, 6),
1126
-                'STA_name'   => $state_name,
1127
-                'STA_active' => true,
1128
-            ];
1129
-            $data_types    = [
1130
-                '%s',// CNT_ISO
1131
-                '%s',// STA_abbrev
1132
-                '%s',// STA_name
1133
-                '%d',// STA_active
1134
-            ];
1135
-            $success       = $wpdb->insert($state_table, $cols_n_values, $data_types);
1136
-            if (! $success) {
1137
-                throw new EE_Error(
1138
-                    $this->_create_error_message_for_db_insertion(
1139
-                        'N/A',
1140
-                        ['state' => $state_name, 'country_id' => $country_name],
1141
-                        $state_table,
1142
-                        $cols_n_values,
1143
-                        $data_types
1144
-                    )
1145
-                );
1146
-            }
1147
-            $state           = $cols_n_values;
1148
-            $state['STA_ID'] = $wpdb->insert_id;
1149
-        }
1150
-        return $state;
1151
-    }
1152
-
1153
-
1154
-    /**
1155
-     * Fixes times like "5:00 PM" into the expected 24-hour format "17:00".
1156
-     * THis is actually just copied from the 3.1 JSON API because it needed to do the exact same thing
1157
-     *
1158
-     * @param string|null $timeString
1159
-     * @return string in the php DATETIME format: "G:i" (24-hour format hour with leading zeros, a colon, and minutes
1160
-     *                with leading zeros)
1161
-     */
1162
-    public function convertTimeFromAMPM(?string $timeString): string
1163
-    {
1164
-        $matches = [];
1165
-        preg_match("~(\\d*):(\\d*)~", $timeString, $matches);
1166
-        if (! $matches || count($matches) < 3) {
1167
-            $hour    = '00';
1168
-            $minutes = '00';
1169
-        } else {
1170
-            $hour    = intval($matches[1]);
1171
-            $minutes = $matches[2];
1172
-        }
1173
-        if (strpos($timeString, 'PM') || strpos($timeString, 'pm')) {
1174
-            $hour = intval($hour) + 12;
1175
-        }
1176
-        $hour    = str_pad("$hour", 2, '0', STR_PAD_LEFT);
1177
-        $minutes = str_pad("$minutes", 2, '0', STR_PAD_LEFT);
1178
-        return "$hour:$minutes";
1179
-    }
1180
-
1181
-
1182
-    /**
1183
-     * Gets the ISO3 fora country given its 3.1 country ID.
1184
-     *
1185
-     * @param int $country_id
1186
-     * @return string the country's ISO3 code
1187
-     */
1188
-    public function get_iso_from_3_1_country_id(int $country_id): string
1189
-    {
1190
-        $old_countries = [
1191
-            [64, 'United States', 'US', 'USA', 1],
1192
-            [15, 'Australia', 'AU', 'AUS', 1],
1193
-            [39, 'Canada', 'CA', 'CAN', 1],
1194
-            [171, 'United Kingdom', 'GB', 'GBR', 1],
1195
-            [70, 'France', 'FR', 'FRA', 2],
1196
-            [111, 'Italy', 'IT', 'ITA', 2],
1197
-            [63, 'Spain', 'ES', 'ESP', 2],
1198
-            [1, 'Afghanistan', 'AF', 'AFG', 1],
1199
-            [2, 'Albania', 'AL', 'ALB', 1],
1200
-            [3, 'Germany', 'DE', 'DEU', 2],
1201
-            [198, 'Switzerland', 'CH', 'CHE', 1],
1202
-            [87, 'Netherlands', 'NL', 'NLD', 2],
1203
-            [197, 'Sweden', 'SE', 'SWE', 1],
1204
-            [230, 'Akrotiri and Dhekelia', 'CY', 'CYP', 2],
1205
-            [4, 'Andorra', 'AD', 'AND', 2],
1206
-            [5, 'Angola', 'AO', 'AGO', 1],
1207
-            [6, 'Anguilla', 'AI', 'AIA', 1],
1208
-            [7, 'Antarctica', 'AQ', 'ATA', 1],
1209
-            [8, 'Antigua and Barbuda', 'AG', 'ATG', 1],
1210
-            [10, 'Saudi Arabia', 'SA', 'SAU', 1],
1211
-            [11, 'Algeria', 'DZ', 'DZA', 1],
1212
-            [12, 'Argentina', 'AR', 'ARG', 1],
1213
-            [13, 'Armenia', 'AM', 'ARM', 1],
1214
-            [14, 'Aruba', 'AW', 'ABW', 1],
1215
-            [16, 'Austria', 'AT', 'AUT', 2],
1216
-            [17, 'Azerbaijan', 'AZ', 'AZE', 1],
1217
-            [18, 'Bahamas', 'BS', 'BHS', 1],
1218
-            [19, 'Bahrain', 'BH', 'BHR', 1],
1219
-            [20, 'Bangladesh', 'BD', 'BGD', 1],
1220
-            [21, 'Barbados', 'BB', 'BRB', 1],
1221
-            [22, 'Belgium ', 'BE', 'BEL', 2],
1222
-            [23, 'Belize', 'BZ', 'BLZ', 1],
1223
-            [24, 'Benin', 'BJ', 'BEN', 1],
1224
-            [25, 'Bermudas', 'BM', 'BMU', 1],
1225
-            [26, 'Belarus', 'BY', 'BLR', 1],
1226
-            [27, 'Bolivia', 'BO', 'BOL', 1],
1227
-            [28, 'Bosnia and Herzegovina', 'BA', 'BIH', 1],
1228
-            [29, 'Botswana', 'BW', 'BWA', 1],
1229
-            [96, 'Bouvet Island', 'BV', 'BVT', 1],
1230
-            [30, 'Brazil', 'BR', 'BRA', 1],
1231
-            [31, 'Brunei', 'BN', 'BRN', 1],
1232
-            [32, 'Bulgaria', 'BG', 'BGR', 1],
1233
-            [33, 'Burkina Faso', 'BF', 'BFA', 1],
1234
-            [34, 'Burundi', 'BI', 'BDI', 1],
1235
-            [35, 'Bhutan', 'BT', 'BTN', 1],
1236
-            [36, 'Cape Verde', 'CV', 'CPV', 1],
1237
-            [37, 'Cambodia', 'KH', 'KHM', 1],
1238
-            [38, 'Cameroon', 'CM', 'CMR', 1],
1239
-            [98, 'Cayman Islands', 'KY', 'CYM', 1],
1240
-            [172, 'Central African Republic', 'CF', 'CAF', 1],
1241
-            [40, 'Chad', 'TD', 'TCD', 1],
1242
-            [41, 'Chile', 'CL', 'CHL', 1],
1243
-            [42, 'China', 'CN', 'CHN', 1],
1244
-            [105, 'Christmas Island', 'CX', 'CXR', 1],
1245
-            [43, 'Cyprus', 'CY', 'CYP', 2],
1246
-            [99, 'Cocos Island', 'CC', 'CCK', 1],
1247
-            [100, 'Cook Islands', 'CK', 'COK', 1],
1248
-            [44, 'Colombia', 'CO', 'COL', 1],
1249
-            [45, 'Comoros', 'KM', 'COM', 1],
1250
-            [46, 'Congo', 'CG', 'COG', 1],
1251
-            [47, 'North Korea', 'KP', 'PRK', 1],
1252
-            [50, 'Costa Rica', 'CR', 'CRI', 1],
1253
-            [51, 'Croatia', 'HR', 'HRV', 1],
1254
-            [52, 'Cuba', 'CU', 'CUB', 1],
1255
-            [173, 'Czech Republic', 'CZ', 'CZE', 1],
1256
-            [53, 'Denmark', 'DK', 'DNK', 1],
1257
-            [54, 'Djibouti', 'DJ', 'DJI', 1],
1258
-            [55, 'Dominica', 'DM', 'DMA', 1],
1259
-            [174, 'Dominican Republic', 'DO', 'DOM', 1],
1260
-            [56, 'Ecuador', 'EC', 'ECU', 1],
1261
-            [57, 'Egypt', 'EG', 'EGY', 1],
1262
-            [58, 'El Salvador', 'SV', 'SLV', 1],
1263
-            [60, 'Eritrea', 'ER', 'ERI', 1],
1264
-            [61, 'Slovakia', 'SK', 'SVK', 2],
1265
-            [62, 'Slovenia', 'SI', 'SVN', 2],
1266
-            [65, 'Estonia', 'EE', 'EST', 2],
1267
-            [66, 'Ethiopia', 'ET', 'ETH', 1],
1268
-            [102, 'Faroe islands', 'FO', 'FRO', 1],
1269
-            [103, 'Falkland Islands', 'FK', 'FLK', 1],
1270
-            [67, 'Fiji', 'FJ', 'FJI', 1],
1271
-            [69, 'Finland', 'FI', 'FIN', 2],
1272
-            [71, 'Gabon', 'GA', 'GAB', 1],
1273
-            [72, 'Gambia', 'GM', 'GMB', 1],
1274
-            [73, 'Georgia', 'GE', 'GEO', 1],
1275
-            [74, 'Ghana', 'GH', 'GHA', 1],
1276
-            [75, 'Gibraltar', 'GI', 'GIB', 1],
1277
-            [76, 'Greece', 'GR', 'GRC', 2],
1278
-            [77, 'Grenada', 'GD', 'GRD', 1],
1279
-            [78, 'Greenland', 'GL', 'GRL', 1],
1280
-            [79, 'Guadeloupe', 'GP', 'GLP', 1],
1281
-            [80, 'Guam', 'GU', 'GUM', 1],
1282
-            [81, 'Guatemala', 'GT', 'GTM', 1],
1283
-            [82, 'Guinea', 'GN', 'GIN', 1],
1284
-            [83, 'Equatorial Guinea', 'GQ', 'GNQ', 1],
1285
-            [84, 'Guinea-Bissau', 'GW', 'GNB', 1],
1286
-            [85, 'Guyana', 'GY', 'GUY', 1],
1287
-            [86, 'Haiti', 'HT', 'HTI', 1],
1288
-            [88, 'Honduras', 'HN', 'HND', 1],
1289
-            [89, 'Hong Kong', 'HK', 'HKG', 1],
1290
-            [90, 'Hungary', 'HU', 'HUN', 1],
1291
-            [91, 'India', 'IN', 'IND', 1],
1292
-            [205, 'British Indian Ocean Territory', 'IO', 'IOT', 1],
1293
-            [92, 'Indonesia', 'ID', 'IDN', 1],
1294
-            [93, 'Iraq', 'IQ', 'IRQ', 1],
1295
-            [94, 'Iran', 'IR', 'IRN', 1],
1296
-            [95, 'Ireland', 'IE', 'IRL', 2],
1297
-            [97, 'Iceland', 'IS', 'ISL', 1],
1298
-            [110, 'Israel', 'IL', 'ISR', 1],
1299
-            [49, 'Ivory Coast ', 'CI', 'CIV', 1],
1300
-            [112, 'Jamaica', 'JM', 'JAM', 1],
1301
-            [113, 'Japan', 'JP', 'JPN', 1],
1302
-            [114, 'Jordan', 'JO', 'JOR', 1],
1303
-            [115, 'Kazakhstan', 'KZ', 'KAZ', 1],
1304
-            [116, 'Kenya', 'KE', 'KEN', 1],
1305
-            [117, 'Kyrgyzstan', 'KG', 'KGZ', 1],
1306
-            [118, 'Kiribati', 'KI', 'KIR', 1],
1307
-            [48, 'South Korea', 'KR', 'KOR', 1],
1308
-            [228, 'Kosovo', 'XK', 'XKV', 2],
1309
-            // there is no official ISO code for Kosovo yet (http://geonames.wordpress.com/2010/03/08/xk-country-code-for-kosovo/) so using a temporary country code and a modified 3 character code for ISO code -- this should be updated if/when Kosovo gets its own ISO code
1310
-            [119, 'Kuwait', 'KW', 'KWT', 1],
1311
-            [120, 'Laos', 'LA', 'LAO', 1],
1312
-            [121, 'Latvia', 'LV', 'LVA', 2],
1313
-            [122, 'Lesotho', 'LS', 'LSO', 1],
1314
-            [123, 'Lebanon', 'LB', 'LBN', 1],
1315
-            [124, 'Liberia', 'LR', 'LBR', 1],
1316
-            [125, 'Libya', 'LY', 'LBY', 1],
1317
-            [126, 'Liechtenstein', 'LI', 'LIE', 1],
1318
-            [127, 'Lithuania', 'LT', 'LTU', 2],
1319
-            [128, 'Luxemburg', 'LU', 'LUX', 2],
1320
-            [129, 'Macao', 'MO', 'MAC', 1],
1321
-            [130, 'Macedonia', 'MK', 'MKD', 1],
1322
-            [131, 'Madagascar', 'MG', 'MDG', 1],
1323
-            [132, 'Malaysia', 'MY', 'MYS', 1],
1324
-            [133, 'Malawi', 'MW', 'MWI', 1],
1325
-            [134, 'Maldivas', 'MV', 'MDV', 1],
1326
-            [135, 'Mali', 'ML', 'MLI', 1],
1327
-            [136, 'Malta', 'MT', 'MLT', 2],
1328
-            [101, 'Northern Marianas', 'MP', 'MNP', 1],
1329
-            [137, 'Morocco', 'MA', 'MAR', 1],
1330
-            [104, 'Marshall islands', 'MH', 'MHL', 1],
1331
-            [138, 'Martinique', 'MQ', 'MTQ', 1],
1332
-            [139, 'Mauritius', 'MU', 'MUS', 1],
1333
-            [140, 'Mauritania', 'MR', 'MRT', 1],
1334
-            [141, 'Mayote', 'YT', 'MYT', 2],
1335
-            [142, 'Mexico', 'MX', 'MEX', 1],
1336
-            [143, 'Micronesia', 'FM', 'FSM', 1],
1337
-            [144, 'Moldova', 'MD', 'MDA', 1],
1338
-            [145, 'Monaco', 'MC', 'MCO', 2],
1339
-            [146, 'Mongolia', 'MN', 'MNG', 1],
1340
-            [147, 'Montserrat', 'MS', 'MSR', 1],
1341
-            [227, 'Montenegro', 'ME', 'MNE', 2],
1342
-            [148, 'Mozambique', 'MZ', 'MOZ', 1],
1343
-            [149, 'Myanmar', 'MM', 'MMR', 1],
1344
-            [150, 'Namibia', 'NA', 'NAM', 1],
1345
-            [151, 'Nauru', 'NR', 'NRU', 1],
1346
-            [152, 'Nepal', 'NP', 'NPL', 1],
1347
-            [9, 'Netherlands Antilles', 'AN', 'ANT', 1],
1348
-            [153, 'Nicaragua', 'NI', 'NIC', 1],
1349
-            [154, 'Niger', 'NE', 'NER', 1],
1350
-            [155, 'Nigeria', 'NG', 'NGA', 1],
1351
-            [156, 'Niue', 'NU', 'NIU', 1],
1352
-            [157, 'Norway', 'NO', 'NOR', 1],
1353
-            [158, 'New Caledonia', 'NC', 'NCL', 1],
1354
-            [159, 'New Zealand', 'NZ', 'NZL', 1],
1355
-            [160, 'Oman', 'OM', 'OMN', 1],
1356
-            [161, 'Pakistan', 'PK', 'PAK', 1],
1357
-            [162, 'Palau', 'PW', 'PLW', 1],
1358
-            [163, 'Panama', 'PA', 'PAN', 1],
1359
-            [164, 'Papua New Guinea', 'PG', 'PNG', 1],
1360
-            [165, 'Paraguay', 'PY', 'PRY', 1],
1361
-            [166, 'Peru', 'PE', 'PER', 1],
1362
-            [68, 'Philippines', 'PH', 'PHL', 1],
1363
-            [167, 'Poland', 'PL', 'POL', 1],
1364
-            [168, 'Portugal', 'PT', 'PRT', 2],
1365
-            [169, 'Puerto Rico', 'PR', 'PRI', 1],
1366
-            [170, 'Qatar', 'QA', 'QAT', 1],
1367
-            [176, 'Rwanda', 'RW', 'RWA', 1],
1368
-            [177, 'Romania', 'RO', 'ROM', 2],
1369
-            [178, 'Russia', 'RU', 'RUS', 1],
1370
-            [229, 'Saint Pierre and Miquelon', 'PM', 'SPM', 2],
1371
-            [180, 'Samoa', 'WS', 'WSM', 1],
1372
-            [181, 'American Samoa', 'AS', 'ASM', 1],
1373
-            [183, 'San Marino', 'SM', 'SMR', 2],
1374
-            [184, 'Saint Vincent and the Grenadines', 'VC', 'VCT', 1],
1375
-            [185, 'Saint Helena', 'SH', 'SHN', 1],
1376
-            [186, 'Saint Lucia', 'LC', 'LCA', 1],
1377
-            [188, 'Senegal', 'SN', 'SEN', 1],
1378
-            [189, 'Seychelles', 'SC', 'SYC', 1],
1379
-            [190, 'Sierra Leona', 'SL', 'SLE', 1],
1380
-            [191, 'Singapore', 'SG', 'SGP', 1],
1381
-            [192, 'Syria', 'SY', 'SYR', 1],
1382
-            [193, 'Somalia', 'SO', 'SOM', 1],
1383
-            [194, 'Sri Lanka', 'LK', 'LKA', 1],
1384
-            [195, 'South Africa', 'ZA', 'ZAF', 1],
1385
-            [196, 'Sudan', 'SD', 'SDN', 1],
1386
-            [199, 'Suriname', 'SR', 'SUR', 1],
1387
-            [200, 'Swaziland', 'SZ', 'SWZ', 1],
1388
-            [201, 'Thailand', 'TH', 'THA', 1],
1389
-            [202, 'Taiwan', 'TW', 'TWN', 1],
1390
-            [203, 'Tanzania', 'TZ', 'TZA', 1],
1391
-            [204, 'Tajikistan', 'TJ', 'TJK', 1],
1392
-            [206, 'Timor-Leste', 'TL', 'TLS', 1],
1393
-            [207, 'Togo', 'TG', 'TGO', 1],
1394
-            [208, 'Tokelau', 'TK', 'TKL', 1],
1395
-            [209, 'Tonga', 'TO', 'TON', 1],
1396
-            [210, 'Trinidad and Tobago', 'TT', 'TTO', 1],
1397
-            [211, 'Tunisia', 'TN', 'TUN', 1],
1398
-            [212, 'Turkmenistan', 'TM', 'TKM', 1],
1399
-            [213, 'Turkey', 'TR', 'TUR', 1],
1400
-            [214, 'Tuvalu', 'TV', 'TUV', 1],
1401
-            [215, 'Ukraine', 'UA', 'UKR', 1],
1402
-            [216, 'Uganda', 'UG', 'UGA', 1],
1403
-            [59, 'United Arab Emirates', 'AE', 'ARE', 1],
1404
-            [217, 'Uruguay', 'UY', 'URY', 1],
1405
-            [218, 'Uzbekistan', 'UZ', 'UZB', 1],
1406
-            [219, 'Vanuatu', 'VU', 'VUT', 1],
1407
-            [220, 'Vatican City', 'VA', 'VAT', 2],
1408
-            [221, 'Venezuela', 'VE', 'VEN', 1],
1409
-            [222, 'Vietnam', 'VN', 'VNM', 1],
1410
-            [108, 'Virgin Islands', 'VI', 'VIR', 1],
1411
-            [223, 'Yemen', 'YE', 'YEM', 1],
1412
-            [225, 'Zambia', 'ZM', 'ZMB', 1],
1413
-            [226, 'Zimbabwe', 'ZW', 'ZWE', 1],
1414
-        ];
1415
-        $country_iso   = 'US';
1416
-        foreach ($old_countries as $country_array) {
1417
-            // note: index 0 is the 3.1 country ID
1418
-            if ($country_array[0] == $country_id) {
1419
-                // note: index 2 is the ISO
1420
-                $country_iso = $country_array[2];
1421
-                break;
1422
-            }
1423
-        }
1424
-        return $country_iso;
1425
-    }
1426
-
1427
-
1428
-    /**
1429
-     * Gets the ISO3 for the
1430
-     *
1431
-     * @return string
1432
-     */
1433
-    public function get_default_country_iso(): string
1434
-    {
1435
-        $old_org_options = get_option('events_organization_settings');
1436
-        return $this->get_iso_from_3_1_country_id($old_org_options['organization_country']);
1437
-    }
1438
-
1439
-
1440
-    /**
1441
-     * Converts a 3.1 payment status to its equivalent 4.1 registration status
1442
-     *
1443
-     * @param string  $payment_status                   possible value for 3.1's evens_attendee.payment_status
1444
-     * @param boolean $this_thing_required_pre_approval whether the thing we're considering (the general setting's
1445
-     *                                                  default payment status, the event's default payment status, or
1446
-     *                                                  the attendee's payment status) required pre-approval.
1447
-     * @return string STS_ID for use in 4.1
1448
-     */
1449
-    public function convert_3_1_payment_status_to_4_1_STS_ID(
1450
-        string $payment_status,
1451
-        bool $this_thing_required_pre_approval = false
1452
-    ): string {
1453
-        // EE team can read the related discussion: https://app.asana.com/0/2400967562914/9418495544455
1454
-        if ($this_thing_required_pre_approval) {
1455
-            return 'RNA';
1456
-        } else {
1457
-            $mapping = [
1458
-                'Completed'        => 'RAP',
1459
-                ''                 => 'RPP',
1460
-                'Incomplete'       => 'RPP',
1461
-                'Pending'          => 'RAP',
1462
-                // stati that only occurred on 3.1 attendees:
1463
-                'Payment Declined' => 'RPP',
1464
-                'Not Completed'    => 'RPP',
1465
-                'Cancelled'        => 'RPP',
1466
-                'Declined'         => 'RPP',
1467
-            ];
1468
-        }
1469
-        return $mapping[ $payment_status ] ?? 'RNA';
1470
-    }
1471
-
1472
-
1473
-    /**
1474
-     * Makes sure the 3.1's image url is converted to an image attachment post to the 4.1 CPT event
1475
-     * and sets it as the featured image on the CPT event
1476
-     *
1477
-     * @param string                         $guid
1478
-     * @param int                            $new_cpt_id
1479
-     * @param EE_Data_Migration_Script_Stage $migration_stage the stage which called this, where errors should be added
1480
-     * @return boolean whether we had to do the big job of creating an image attachment
1481
-     */
1482
-    public function convert_image_url_to_attachment_and_attach_to_post(
1483
-        string $guid,
1484
-        int $new_cpt_id,
1485
-        EE_Data_Migration_Script_Stage $migration_stage
1486
-    ): bool {
1487
-        $created_attachment_post = false;
1488
-        $guid                    = $this->_get_original_guid($guid);
1489
-        if ($guid) {
1490
-            // check for an existing attachment post with this guid
1491
-            $attachment_post_id = $this->_get_image_attachment_id_by_GUID($guid);
1492
-            if (! $attachment_post_id) {
1493
-                // post thumbnail with that GUID doesn't exist, we should create one
1494
-                $attachment_post_id      = $this->_create_image_attachment_from_GUID($guid, $migration_stage);
1495
-                $created_attachment_post = true;
1496
-            }
1497
-            // double-check we actually have an attachment post
1498
-            if ($attachment_post_id) {
1499
-                update_post_meta($new_cpt_id, '_thumbnail_id', $attachment_post_id);
1500
-            } else {
1501
-                $migration_stage->add_error(
1502
-                    sprintf(
1503
-                        esc_html__(
1504
-                            "Could not update event image %s for CPT with ID %d, but attachments post ID is %d",
1505
-                            "event_espresso"
1506
-                        ),
1507
-                        $guid,
1508
-                        $new_cpt_id,
1509
-                        $attachment_post_id
1510
-                    )
1511
-                );
1512
-            }
1513
-        }
1514
-        return $created_attachment_post;
1515
-    }
1516
-
1517
-
1518
-    /**
1519
-     * In 3.1, the event thumbnail image DOESN'T point to the original image, but instead
1520
-     * to a large thumbnail (which has nearly the same GUID, except it adds "-{width}x{height}" before the filetype,
1521
-     * or whatever dimensions it is. Eg 'http://mysite.com/image1-300x400.jpg' instead of
1522
-     * 'http://mysite.com/image1.jpg' ). This function attempts to strip that off and get the original file, if it
1523
-     * exists
1524
-     *
1525
-     * @param string $guid_in_old_event
1526
-     * @return string either the original guid, or $guid_in_old_event if we couldn't figure out what the original was
1527
-     */
1528
-    private function _get_original_guid(string $guid_in_old_event): string
1529
-    {
1530
-        $original_guid = preg_replace('~-\d*x\d*\.~', '.', $guid_in_old_event, 1);
1531
-        // do a head request to verify the file exists
1532
-        $head_response = wp_remote_head($original_guid);
1533
-        if (! $head_response instanceof WP_Error && $head_response['response']['message'] == 'OK') {
1534
-            return $original_guid;
1535
-        }
1536
-        return $guid_in_old_event;
1537
-    }
1538
-
1539
-
1540
-    /**
1541
-     * Creates an image attachment post for the GUID. If the GUID points to a remote image,
1542
-     * we download it to our uploads directory so that it can be properly processed (eg, creates different sizes of
1543
-     * thumbnails)
1544
-     *
1545
-     * @param string                         $guid
1546
-     * @param EE_Data_Migration_Script_Stage $migration_stage
1547
-     * @return int
1548
-     */
1549
-    private function _create_image_attachment_from_GUID(string $guid, EE_Data_Migration_Script_Stage $migration_stage)
1550
-    {
1551
-        if (! $guid) {
1552
-            $migration_stage->add_error(
1553
-                esc_html__(
1554
-                    "Cannot create image attachment for a blank GUID!",
1555
-                    "event_espresso"
1556
-                )
1557
-            );
1558
-            return 0;
1559
-        }
1560
-        $wp_filetype   = wp_check_filetype(basename($guid));
1561
-        $wp_upload_dir = wp_upload_dir();
1562
-        // if the file is located remotely, download it to our uploads DIR, because wp_generate_attachment_metadata
1563
-        // needs the file to be local
1564
-        if (strpos($guid, $wp_upload_dir['url']) === false) {
1565
-            // image is located remotely. download it and place it in the uploads directory
1566
-            if (! is_readable($guid)) {
1567
-                $migration_stage->add_error(
1568
-                    sprintf(
1569
-                        esc_html__(
1570
-                            "Could not create image attachment from non-existent file: %s",
1571
-                            "event_espresso"
1572
-                        ),
1573
-                        $guid
1574
-                    )
1575
-                );
1576
-                return 0;
1577
-            }
1578
-            $contents = file_get_contents($guid);
1579
-            if ($contents === false) {
1580
-                $migration_stage->add_error(
1581
-                    sprintf(
1582
-                        esc_html__(
1583
-                            "Could not read image at %s, and therefore couldn't create an attachment post for it.",
1584
-                            "event_espresso"
1585
-                        ),
1586
-                        $guid
1587
-                    )
1588
-                );
1589
-                return false;
1590
-            }
1591
-            $local_filepath = $wp_upload_dir['path'] . '/' . basename($guid);
1592
-            $save_file      = fopen($local_filepath, 'w');
1593
-            fwrite($save_file, $contents);
1594
-            fclose($save_file);
1595
-            $guid = str_replace($wp_upload_dir['path'], $wp_upload_dir['url'], $local_filepath);
1596
-        } else {
1597
-            $local_filepath = str_replace($wp_upload_dir['url'], $wp_upload_dir['path'], $guid);
1598
-        }
1599
-        $attachment = [
1600
-            'guid'           => $guid,
1601
-            'post_mime_type' => $wp_filetype['type'],
1602
-            'post_title'     => preg_replace('/\.[^.]+$/', '', basename($guid)),
1603
-            'post_content'   => '',
1604
-            'post_status'    => 'inherit',
1605
-        ];
1606
-        $attach_id  = wp_insert_attachment($attachment, $guid);
1607
-        if (! $attach_id) {
1608
-            $migration_stage->add_error(
1609
-                sprintf(
1610
-                    esc_html__(
1611
-                        "Could not create image attachment post from image '%s'. Attachment data was %s.",
1612
-                        "event_espresso"
1613
-                    ),
1614
-                    $guid,
1615
-                    $this->_json_encode($attachment)
1616
-                )
1617
-            );
1618
-            return $attach_id;
1619
-        }
1620
-        // you must first include the image.php file
1621
-        // for the function wp_generate_attachment_metadata() to work
1622
-        require_once(ABSPATH . 'wp-admin/includes/image.php');
1623
-        $attach_data = wp_generate_attachment_metadata($attach_id, $local_filepath);
1624
-        if (! $attach_data) {
1625
-            $migration_stage->add_error(
1626
-                sprintf(
1627
-                    esc_html__(
1628
-                        "Could not generate attachment metadata for attachment post %d with filepath %s and GUID %s. Please check the file was downloaded properly.",
1629
-                        "event_espresso"
1630
-                    ),
1631
-                    $attach_id,
1632
-                    $local_filepath,
1633
-                    $guid
1634
-                )
1635
-            );
1636
-            return $attach_id;
1637
-        }
1638
-        $metadata_save_result = wp_update_attachment_metadata($attach_id, $attach_data);
1639
-        if (! $metadata_save_result) {
1640
-            $migration_stage->add_error(
1641
-                sprintf(
1642
-                    esc_html__(
1643
-                        "Could not update attachment metadata for attachment %d with data %s",
1644
-                        "event_espresso"
1645
-                    ),
1646
-                    $attach_id,
1647
-                    $this->_json_encode($attach_data)
1648
-                )
1649
-            );
1650
-        }
1651
-        return $attach_id;
1652
-    }
1653
-
1654
-
1655
-    /**
1656
-     * Finds the attachment post containing info about an image attachment given the GUID (link to the image itself),
1657
-     * and returns its ID.
1658
-     *
1659
-     * @param string $guid
1660
-     * @return int
1661
-     * @global wpdb  $wpdb
1662
-     */
1663
-    private function _get_image_attachment_id_by_GUID(string $guid): int
1664
-    {
1665
-        global $wpdb;
1666
-        return (int) $wpdb->get_var($wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE guid=%s LIMIT 1", $guid));
1667
-    }
1668
-
1669
-
1670
-    /**
1671
-     * Returns a mysql-formatted DATETIME in UTC time, given a $DATETIME_string
1672
-     * (and optionally a timezone; if none is given, the wp default is used)
1673
-     *
1674
-     * @param EE_Data_Migration_Script_Stage $stage
1675
-     * @param array                          $row_of_data , the row from the DB (as an array) we're trying to find the
1676
-     *                                                    UTC time for
1677
-     * @param string                         $DATETIME_string
1678
-     * @param string|null                    $timezone
1679
-     * @return string
1680
-     */
1681
-    public function convert_date_string_to_utc(
1682
-        EE_Data_Migration_Script_Stage $stage,
1683
-        array $row_of_data,
1684
-        string $DATETIME_string,
1685
-        ?string $timezone = null
1686
-    ): string {
1687
-        $original_tz = $timezone;
1688
-        if (! $timezone) {
1689
-            $timezone = $this->_get_wp_timezone();
1690
-        }
1691
-        if (! $timezone) {
1692
-            $stage->add_error(
1693
-                sprintf(
1694
-                    esc_html__("Could not find timezone given %s for %s", "event_espresso"),
1695
-                    $original_tz,
1696
-                    $row_of_data
1697
-                )
1698
-            );
1699
-            $timezone = 'UTC';
1700
-        }
1701
-        try {
1702
-            $date_obj = new DateTime($DATETIME_string, new DateTimeZone($timezone));
1703
-            EEH_DTT_Helper::setTimezone($date_obj, new DateTimeZone('UTC'));
1704
-        } catch (Exception $e) {
1705
-            $stage->add_error(
1706
-                sprintf(
1707
-                    esc_html__(
1708
-                        "Could not convert time string '%s' using timezone '%s' into a proper DATETIME. Using current time instead.",
1709
-                        "event_espresso"
1710
-                    ),
1711
-                    $DATETIME_string,
1712
-                    $timezone
1713
-                )
1714
-            );
1715
-            $date_obj = new DateTime();
1716
-        }
1717
-        return $date_obj->format('Y-m-d H:i:s');
1718
-    }
1719
-
1720
-
1721
-    /**
1722
-     * Gets the default timezone string from wordpress (even if they set a gmt offset)
1723
-     *
1724
-     * @return string
1725
-     */
1726
-    private function _get_wp_timezone()
1727
-    {
1728
-        $timezone = empty($timezone) ? get_option('timezone_string') : $timezone;
1729
-        // if timezone is STILL empty then let's get the GMT offset and then set the timezone_string using our converter
1730
-        if (empty($timezone)) {
1731
-            // let's get a the WordPress UTC offset
1732
-            $offset   = (int) get_option('gmt_offset');
1733
-            $timezone = $this->timezone_convert_to_string_from_offset($offset);
1734
-        }
1735
-        return $timezone;
1736
-    }
1737
-
1738
-
1739
-    /**
1740
-     * Gets the wordpress timezone string from a UTC offset
1741
-     *
1742
-     * @param int $offset
1743
-     * @return boolean
1744
-     */
1745
-    private function timezone_convert_to_string_from_offset(int $offset): bool
1746
-    {
1747
-        // shamelessly taken from bottom comment at http://ca1.php.net/manual/en/function.timezone-name-from-abbr.php because timezone_name_from_abbr() did not work as expected - its not reliable
1748
-        $offset        *= 3600; // convert hour offset to seconds
1749
-        $abbreviations = timezone_abbreviations_list();
1750
-        foreach ($abbreviations as $abbreviation) {
1751
-            foreach ($abbreviation as $city) {
1752
-                if ($city['offset'] == $offset) {
1753
-                    return $city['timezone_id'];
1754
-                }
1755
-            }
1756
-        }
1757
-        return false;
1758
-    }
1759
-
1760
-
1761
-    public function migration_page_hooks()
1762
-    {
1763
-        add_filter(
1764
-            'FHEE__ee_migration_page__header',
1765
-            [$this, '_migrate_page_hook_simplify_version_strings'],
1766
-            10,
1767
-            3
1768
-        );
1769
-        add_filter(
1770
-            'FHEE__ee_migration_page__p_after_header',
1771
-            [$this, '_migration_page_hook_simplify_next_db_state'],
1772
-            10,
1773
-            2
1774
-        );
1775
-        add_filter(
1776
-            'FHEE__ee_migration_page__option_1_main',
1777
-            [$this, '_migrate_page_hook_simplify_version_strings'],
1778
-            10,
1779
-            3
1780
-        );
1781
-        add_filter(
1782
-            'FHEE__ee_migration_page__option_1_button_text',
1783
-            [$this, '_migrate_page_hook_simplify_version_strings'],
1784
-            10,
1785
-            3
1786
-        );
1787
-        add_action(
1788
-            'AHEE__ee_migration_page__option_1_extra_details',
1789
-            [$this, '_migration_page_hook_option_1_extra_details'],
1790
-            10,
1791
-            3
1792
-        );
1793
-        add_filter(
1794
-            'FHEE__ee_migration_page__option_2_main',
1795
-            [$this, '_migrate_page_hook_simplify_version_strings'],
1796
-            10,
1797
-            4
1798
-        );
1799
-        add_filter(
1800
-            'FHEE__ee_migration_page__option_2_button_text',
1801
-            [$this, '_migration_page_hook_simplify_next_db_state'],
1802
-            10,
1803
-            2
1804
-        );
1805
-        add_filter(
1806
-            'FHEE__ee_migration_page__option_2_details',
1807
-            [$this, '_migration_page_hook_simplify_next_db_state'],
1808
-            10,
1809
-            2
1810
-        );
1811
-        add_action(
1812
-            'AHEE__ee_migration_page__after_migration_options_table',
1813
-            [$this, '_migration_page_hook_after_migration_options_table']
1814
-        );
1815
-        add_filter(
1816
-            'FHEE__ee_migration_page__done_migration_header',
1817
-            [$this, '_migration_page_hook_simplify_next_db_state'],
1818
-            10,
1819
-            2
1820
-        );
1821
-        add_filter(
1822
-            'FHEE__ee_migration_page__p_after_done_migration_header',
1823
-            [$this, '_migration_page_hook_simplify_next_db_state'],
1824
-            10,
1825
-            2
1826
-        );
1827
-        add_filter(
1828
-            'FHEE__ee_migration_page__migration_options_template',
1829
-            [$this, 'use_migration_options_from_ee3_template']
1830
-        );
1831
-    }
1832
-
1833
-
1834
-    public function _migrate_page_hook_simplify_version_strings(
1835
-        $old_content,
1836
-        $current_db_state,
1837
-        $next_db_state,
1838
-        $ultimate_db_state = null
1839
-    ) {
1840
-        return str_replace(
1841
-            [$current_db_state, $next_db_state, $ultimate_db_state],
1842
-            [
1843
-                esc_html__('EE3', 'event_espresso'),
1844
-                esc_html__('EE4', 'event_espresso'),
1845
-                esc_html__("EE4", 'event_espresso'),
1846
-            ],
1847
-            $old_content
1848
-        );
1849
-    }
1850
-
1851
-
1852
-    public function _migration_page_hook_simplify_next_db_state($old_content, $next_db_state)
1853
-    {
1854
-        return str_replace($next_db_state, esc_html__("EE4", 'event_espresso'), $old_content);
1855
-    }
1856
-
1857
-
1858
-    public function _migration_page_hook_option_1_extra_details()
1859
-    {
1860
-        ?>
1115
+				$state_name,
1116
+				$state_name,
1117
+				$country_iso
1118
+			),
1119
+			ARRAY_A
1120
+		);
1121
+		if (! $state) {
1122
+			// insert a new one then
1123
+			$cols_n_values = [
1124
+				'CNT_ISO'    => $country_iso,
1125
+				'STA_abbrev' => substr($state_name, 0, 6),
1126
+				'STA_name'   => $state_name,
1127
+				'STA_active' => true,
1128
+			];
1129
+			$data_types    = [
1130
+				'%s',// CNT_ISO
1131
+				'%s',// STA_abbrev
1132
+				'%s',// STA_name
1133
+				'%d',// STA_active
1134
+			];
1135
+			$success       = $wpdb->insert($state_table, $cols_n_values, $data_types);
1136
+			if (! $success) {
1137
+				throw new EE_Error(
1138
+					$this->_create_error_message_for_db_insertion(
1139
+						'N/A',
1140
+						['state' => $state_name, 'country_id' => $country_name],
1141
+						$state_table,
1142
+						$cols_n_values,
1143
+						$data_types
1144
+					)
1145
+				);
1146
+			}
1147
+			$state           = $cols_n_values;
1148
+			$state['STA_ID'] = $wpdb->insert_id;
1149
+		}
1150
+		return $state;
1151
+	}
1152
+
1153
+
1154
+	/**
1155
+	 * Fixes times like "5:00 PM" into the expected 24-hour format "17:00".
1156
+	 * THis is actually just copied from the 3.1 JSON API because it needed to do the exact same thing
1157
+	 *
1158
+	 * @param string|null $timeString
1159
+	 * @return string in the php DATETIME format: "G:i" (24-hour format hour with leading zeros, a colon, and minutes
1160
+	 *                with leading zeros)
1161
+	 */
1162
+	public function convertTimeFromAMPM(?string $timeString): string
1163
+	{
1164
+		$matches = [];
1165
+		preg_match("~(\\d*):(\\d*)~", $timeString, $matches);
1166
+		if (! $matches || count($matches) < 3) {
1167
+			$hour    = '00';
1168
+			$minutes = '00';
1169
+		} else {
1170
+			$hour    = intval($matches[1]);
1171
+			$minutes = $matches[2];
1172
+		}
1173
+		if (strpos($timeString, 'PM') || strpos($timeString, 'pm')) {
1174
+			$hour = intval($hour) + 12;
1175
+		}
1176
+		$hour    = str_pad("$hour", 2, '0', STR_PAD_LEFT);
1177
+		$minutes = str_pad("$minutes", 2, '0', STR_PAD_LEFT);
1178
+		return "$hour:$minutes";
1179
+	}
1180
+
1181
+
1182
+	/**
1183
+	 * Gets the ISO3 fora country given its 3.1 country ID.
1184
+	 *
1185
+	 * @param int $country_id
1186
+	 * @return string the country's ISO3 code
1187
+	 */
1188
+	public function get_iso_from_3_1_country_id(int $country_id): string
1189
+	{
1190
+		$old_countries = [
1191
+			[64, 'United States', 'US', 'USA', 1],
1192
+			[15, 'Australia', 'AU', 'AUS', 1],
1193
+			[39, 'Canada', 'CA', 'CAN', 1],
1194
+			[171, 'United Kingdom', 'GB', 'GBR', 1],
1195
+			[70, 'France', 'FR', 'FRA', 2],
1196
+			[111, 'Italy', 'IT', 'ITA', 2],
1197
+			[63, 'Spain', 'ES', 'ESP', 2],
1198
+			[1, 'Afghanistan', 'AF', 'AFG', 1],
1199
+			[2, 'Albania', 'AL', 'ALB', 1],
1200
+			[3, 'Germany', 'DE', 'DEU', 2],
1201
+			[198, 'Switzerland', 'CH', 'CHE', 1],
1202
+			[87, 'Netherlands', 'NL', 'NLD', 2],
1203
+			[197, 'Sweden', 'SE', 'SWE', 1],
1204
+			[230, 'Akrotiri and Dhekelia', 'CY', 'CYP', 2],
1205
+			[4, 'Andorra', 'AD', 'AND', 2],
1206
+			[5, 'Angola', 'AO', 'AGO', 1],
1207
+			[6, 'Anguilla', 'AI', 'AIA', 1],
1208
+			[7, 'Antarctica', 'AQ', 'ATA', 1],
1209
+			[8, 'Antigua and Barbuda', 'AG', 'ATG', 1],
1210
+			[10, 'Saudi Arabia', 'SA', 'SAU', 1],
1211
+			[11, 'Algeria', 'DZ', 'DZA', 1],
1212
+			[12, 'Argentina', 'AR', 'ARG', 1],
1213
+			[13, 'Armenia', 'AM', 'ARM', 1],
1214
+			[14, 'Aruba', 'AW', 'ABW', 1],
1215
+			[16, 'Austria', 'AT', 'AUT', 2],
1216
+			[17, 'Azerbaijan', 'AZ', 'AZE', 1],
1217
+			[18, 'Bahamas', 'BS', 'BHS', 1],
1218
+			[19, 'Bahrain', 'BH', 'BHR', 1],
1219
+			[20, 'Bangladesh', 'BD', 'BGD', 1],
1220
+			[21, 'Barbados', 'BB', 'BRB', 1],
1221
+			[22, 'Belgium ', 'BE', 'BEL', 2],
1222
+			[23, 'Belize', 'BZ', 'BLZ', 1],
1223
+			[24, 'Benin', 'BJ', 'BEN', 1],
1224
+			[25, 'Bermudas', 'BM', 'BMU', 1],
1225
+			[26, 'Belarus', 'BY', 'BLR', 1],
1226
+			[27, 'Bolivia', 'BO', 'BOL', 1],
1227
+			[28, 'Bosnia and Herzegovina', 'BA', 'BIH', 1],
1228
+			[29, 'Botswana', 'BW', 'BWA', 1],
1229
+			[96, 'Bouvet Island', 'BV', 'BVT', 1],
1230
+			[30, 'Brazil', 'BR', 'BRA', 1],
1231
+			[31, 'Brunei', 'BN', 'BRN', 1],
1232
+			[32, 'Bulgaria', 'BG', 'BGR', 1],
1233
+			[33, 'Burkina Faso', 'BF', 'BFA', 1],
1234
+			[34, 'Burundi', 'BI', 'BDI', 1],
1235
+			[35, 'Bhutan', 'BT', 'BTN', 1],
1236
+			[36, 'Cape Verde', 'CV', 'CPV', 1],
1237
+			[37, 'Cambodia', 'KH', 'KHM', 1],
1238
+			[38, 'Cameroon', 'CM', 'CMR', 1],
1239
+			[98, 'Cayman Islands', 'KY', 'CYM', 1],
1240
+			[172, 'Central African Republic', 'CF', 'CAF', 1],
1241
+			[40, 'Chad', 'TD', 'TCD', 1],
1242
+			[41, 'Chile', 'CL', 'CHL', 1],
1243
+			[42, 'China', 'CN', 'CHN', 1],
1244
+			[105, 'Christmas Island', 'CX', 'CXR', 1],
1245
+			[43, 'Cyprus', 'CY', 'CYP', 2],
1246
+			[99, 'Cocos Island', 'CC', 'CCK', 1],
1247
+			[100, 'Cook Islands', 'CK', 'COK', 1],
1248
+			[44, 'Colombia', 'CO', 'COL', 1],
1249
+			[45, 'Comoros', 'KM', 'COM', 1],
1250
+			[46, 'Congo', 'CG', 'COG', 1],
1251
+			[47, 'North Korea', 'KP', 'PRK', 1],
1252
+			[50, 'Costa Rica', 'CR', 'CRI', 1],
1253
+			[51, 'Croatia', 'HR', 'HRV', 1],
1254
+			[52, 'Cuba', 'CU', 'CUB', 1],
1255
+			[173, 'Czech Republic', 'CZ', 'CZE', 1],
1256
+			[53, 'Denmark', 'DK', 'DNK', 1],
1257
+			[54, 'Djibouti', 'DJ', 'DJI', 1],
1258
+			[55, 'Dominica', 'DM', 'DMA', 1],
1259
+			[174, 'Dominican Republic', 'DO', 'DOM', 1],
1260
+			[56, 'Ecuador', 'EC', 'ECU', 1],
1261
+			[57, 'Egypt', 'EG', 'EGY', 1],
1262
+			[58, 'El Salvador', 'SV', 'SLV', 1],
1263
+			[60, 'Eritrea', 'ER', 'ERI', 1],
1264
+			[61, 'Slovakia', 'SK', 'SVK', 2],
1265
+			[62, 'Slovenia', 'SI', 'SVN', 2],
1266
+			[65, 'Estonia', 'EE', 'EST', 2],
1267
+			[66, 'Ethiopia', 'ET', 'ETH', 1],
1268
+			[102, 'Faroe islands', 'FO', 'FRO', 1],
1269
+			[103, 'Falkland Islands', 'FK', 'FLK', 1],
1270
+			[67, 'Fiji', 'FJ', 'FJI', 1],
1271
+			[69, 'Finland', 'FI', 'FIN', 2],
1272
+			[71, 'Gabon', 'GA', 'GAB', 1],
1273
+			[72, 'Gambia', 'GM', 'GMB', 1],
1274
+			[73, 'Georgia', 'GE', 'GEO', 1],
1275
+			[74, 'Ghana', 'GH', 'GHA', 1],
1276
+			[75, 'Gibraltar', 'GI', 'GIB', 1],
1277
+			[76, 'Greece', 'GR', 'GRC', 2],
1278
+			[77, 'Grenada', 'GD', 'GRD', 1],
1279
+			[78, 'Greenland', 'GL', 'GRL', 1],
1280
+			[79, 'Guadeloupe', 'GP', 'GLP', 1],
1281
+			[80, 'Guam', 'GU', 'GUM', 1],
1282
+			[81, 'Guatemala', 'GT', 'GTM', 1],
1283
+			[82, 'Guinea', 'GN', 'GIN', 1],
1284
+			[83, 'Equatorial Guinea', 'GQ', 'GNQ', 1],
1285
+			[84, 'Guinea-Bissau', 'GW', 'GNB', 1],
1286
+			[85, 'Guyana', 'GY', 'GUY', 1],
1287
+			[86, 'Haiti', 'HT', 'HTI', 1],
1288
+			[88, 'Honduras', 'HN', 'HND', 1],
1289
+			[89, 'Hong Kong', 'HK', 'HKG', 1],
1290
+			[90, 'Hungary', 'HU', 'HUN', 1],
1291
+			[91, 'India', 'IN', 'IND', 1],
1292
+			[205, 'British Indian Ocean Territory', 'IO', 'IOT', 1],
1293
+			[92, 'Indonesia', 'ID', 'IDN', 1],
1294
+			[93, 'Iraq', 'IQ', 'IRQ', 1],
1295
+			[94, 'Iran', 'IR', 'IRN', 1],
1296
+			[95, 'Ireland', 'IE', 'IRL', 2],
1297
+			[97, 'Iceland', 'IS', 'ISL', 1],
1298
+			[110, 'Israel', 'IL', 'ISR', 1],
1299
+			[49, 'Ivory Coast ', 'CI', 'CIV', 1],
1300
+			[112, 'Jamaica', 'JM', 'JAM', 1],
1301
+			[113, 'Japan', 'JP', 'JPN', 1],
1302
+			[114, 'Jordan', 'JO', 'JOR', 1],
1303
+			[115, 'Kazakhstan', 'KZ', 'KAZ', 1],
1304
+			[116, 'Kenya', 'KE', 'KEN', 1],
1305
+			[117, 'Kyrgyzstan', 'KG', 'KGZ', 1],
1306
+			[118, 'Kiribati', 'KI', 'KIR', 1],
1307
+			[48, 'South Korea', 'KR', 'KOR', 1],
1308
+			[228, 'Kosovo', 'XK', 'XKV', 2],
1309
+			// there is no official ISO code for Kosovo yet (http://geonames.wordpress.com/2010/03/08/xk-country-code-for-kosovo/) so using a temporary country code and a modified 3 character code for ISO code -- this should be updated if/when Kosovo gets its own ISO code
1310
+			[119, 'Kuwait', 'KW', 'KWT', 1],
1311
+			[120, 'Laos', 'LA', 'LAO', 1],
1312
+			[121, 'Latvia', 'LV', 'LVA', 2],
1313
+			[122, 'Lesotho', 'LS', 'LSO', 1],
1314
+			[123, 'Lebanon', 'LB', 'LBN', 1],
1315
+			[124, 'Liberia', 'LR', 'LBR', 1],
1316
+			[125, 'Libya', 'LY', 'LBY', 1],
1317
+			[126, 'Liechtenstein', 'LI', 'LIE', 1],
1318
+			[127, 'Lithuania', 'LT', 'LTU', 2],
1319
+			[128, 'Luxemburg', 'LU', 'LUX', 2],
1320
+			[129, 'Macao', 'MO', 'MAC', 1],
1321
+			[130, 'Macedonia', 'MK', 'MKD', 1],
1322
+			[131, 'Madagascar', 'MG', 'MDG', 1],
1323
+			[132, 'Malaysia', 'MY', 'MYS', 1],
1324
+			[133, 'Malawi', 'MW', 'MWI', 1],
1325
+			[134, 'Maldivas', 'MV', 'MDV', 1],
1326
+			[135, 'Mali', 'ML', 'MLI', 1],
1327
+			[136, 'Malta', 'MT', 'MLT', 2],
1328
+			[101, 'Northern Marianas', 'MP', 'MNP', 1],
1329
+			[137, 'Morocco', 'MA', 'MAR', 1],
1330
+			[104, 'Marshall islands', 'MH', 'MHL', 1],
1331
+			[138, 'Martinique', 'MQ', 'MTQ', 1],
1332
+			[139, 'Mauritius', 'MU', 'MUS', 1],
1333
+			[140, 'Mauritania', 'MR', 'MRT', 1],
1334
+			[141, 'Mayote', 'YT', 'MYT', 2],
1335
+			[142, 'Mexico', 'MX', 'MEX', 1],
1336
+			[143, 'Micronesia', 'FM', 'FSM', 1],
1337
+			[144, 'Moldova', 'MD', 'MDA', 1],
1338
+			[145, 'Monaco', 'MC', 'MCO', 2],
1339
+			[146, 'Mongolia', 'MN', 'MNG', 1],
1340
+			[147, 'Montserrat', 'MS', 'MSR', 1],
1341
+			[227, 'Montenegro', 'ME', 'MNE', 2],
1342
+			[148, 'Mozambique', 'MZ', 'MOZ', 1],
1343
+			[149, 'Myanmar', 'MM', 'MMR', 1],
1344
+			[150, 'Namibia', 'NA', 'NAM', 1],
1345
+			[151, 'Nauru', 'NR', 'NRU', 1],
1346
+			[152, 'Nepal', 'NP', 'NPL', 1],
1347
+			[9, 'Netherlands Antilles', 'AN', 'ANT', 1],
1348
+			[153, 'Nicaragua', 'NI', 'NIC', 1],
1349
+			[154, 'Niger', 'NE', 'NER', 1],
1350
+			[155, 'Nigeria', 'NG', 'NGA', 1],
1351
+			[156, 'Niue', 'NU', 'NIU', 1],
1352
+			[157, 'Norway', 'NO', 'NOR', 1],
1353
+			[158, 'New Caledonia', 'NC', 'NCL', 1],
1354
+			[159, 'New Zealand', 'NZ', 'NZL', 1],
1355
+			[160, 'Oman', 'OM', 'OMN', 1],
1356
+			[161, 'Pakistan', 'PK', 'PAK', 1],
1357
+			[162, 'Palau', 'PW', 'PLW', 1],
1358
+			[163, 'Panama', 'PA', 'PAN', 1],
1359
+			[164, 'Papua New Guinea', 'PG', 'PNG', 1],
1360
+			[165, 'Paraguay', 'PY', 'PRY', 1],
1361
+			[166, 'Peru', 'PE', 'PER', 1],
1362
+			[68, 'Philippines', 'PH', 'PHL', 1],
1363
+			[167, 'Poland', 'PL', 'POL', 1],
1364
+			[168, 'Portugal', 'PT', 'PRT', 2],
1365
+			[169, 'Puerto Rico', 'PR', 'PRI', 1],
1366
+			[170, 'Qatar', 'QA', 'QAT', 1],
1367
+			[176, 'Rwanda', 'RW', 'RWA', 1],
1368
+			[177, 'Romania', 'RO', 'ROM', 2],
1369
+			[178, 'Russia', 'RU', 'RUS', 1],
1370
+			[229, 'Saint Pierre and Miquelon', 'PM', 'SPM', 2],
1371
+			[180, 'Samoa', 'WS', 'WSM', 1],
1372
+			[181, 'American Samoa', 'AS', 'ASM', 1],
1373
+			[183, 'San Marino', 'SM', 'SMR', 2],
1374
+			[184, 'Saint Vincent and the Grenadines', 'VC', 'VCT', 1],
1375
+			[185, 'Saint Helena', 'SH', 'SHN', 1],
1376
+			[186, 'Saint Lucia', 'LC', 'LCA', 1],
1377
+			[188, 'Senegal', 'SN', 'SEN', 1],
1378
+			[189, 'Seychelles', 'SC', 'SYC', 1],
1379
+			[190, 'Sierra Leona', 'SL', 'SLE', 1],
1380
+			[191, 'Singapore', 'SG', 'SGP', 1],
1381
+			[192, 'Syria', 'SY', 'SYR', 1],
1382
+			[193, 'Somalia', 'SO', 'SOM', 1],
1383
+			[194, 'Sri Lanka', 'LK', 'LKA', 1],
1384
+			[195, 'South Africa', 'ZA', 'ZAF', 1],
1385
+			[196, 'Sudan', 'SD', 'SDN', 1],
1386
+			[199, 'Suriname', 'SR', 'SUR', 1],
1387
+			[200, 'Swaziland', 'SZ', 'SWZ', 1],
1388
+			[201, 'Thailand', 'TH', 'THA', 1],
1389
+			[202, 'Taiwan', 'TW', 'TWN', 1],
1390
+			[203, 'Tanzania', 'TZ', 'TZA', 1],
1391
+			[204, 'Tajikistan', 'TJ', 'TJK', 1],
1392
+			[206, 'Timor-Leste', 'TL', 'TLS', 1],
1393
+			[207, 'Togo', 'TG', 'TGO', 1],
1394
+			[208, 'Tokelau', 'TK', 'TKL', 1],
1395
+			[209, 'Tonga', 'TO', 'TON', 1],
1396
+			[210, 'Trinidad and Tobago', 'TT', 'TTO', 1],
1397
+			[211, 'Tunisia', 'TN', 'TUN', 1],
1398
+			[212, 'Turkmenistan', 'TM', 'TKM', 1],
1399
+			[213, 'Turkey', 'TR', 'TUR', 1],
1400
+			[214, 'Tuvalu', 'TV', 'TUV', 1],
1401
+			[215, 'Ukraine', 'UA', 'UKR', 1],
1402
+			[216, 'Uganda', 'UG', 'UGA', 1],
1403
+			[59, 'United Arab Emirates', 'AE', 'ARE', 1],
1404
+			[217, 'Uruguay', 'UY', 'URY', 1],
1405
+			[218, 'Uzbekistan', 'UZ', 'UZB', 1],
1406
+			[219, 'Vanuatu', 'VU', 'VUT', 1],
1407
+			[220, 'Vatican City', 'VA', 'VAT', 2],
1408
+			[221, 'Venezuela', 'VE', 'VEN', 1],
1409
+			[222, 'Vietnam', 'VN', 'VNM', 1],
1410
+			[108, 'Virgin Islands', 'VI', 'VIR', 1],
1411
+			[223, 'Yemen', 'YE', 'YEM', 1],
1412
+			[225, 'Zambia', 'ZM', 'ZMB', 1],
1413
+			[226, 'Zimbabwe', 'ZW', 'ZWE', 1],
1414
+		];
1415
+		$country_iso   = 'US';
1416
+		foreach ($old_countries as $country_array) {
1417
+			// note: index 0 is the 3.1 country ID
1418
+			if ($country_array[0] == $country_id) {
1419
+				// note: index 2 is the ISO
1420
+				$country_iso = $country_array[2];
1421
+				break;
1422
+			}
1423
+		}
1424
+		return $country_iso;
1425
+	}
1426
+
1427
+
1428
+	/**
1429
+	 * Gets the ISO3 for the
1430
+	 *
1431
+	 * @return string
1432
+	 */
1433
+	public function get_default_country_iso(): string
1434
+	{
1435
+		$old_org_options = get_option('events_organization_settings');
1436
+		return $this->get_iso_from_3_1_country_id($old_org_options['organization_country']);
1437
+	}
1438
+
1439
+
1440
+	/**
1441
+	 * Converts a 3.1 payment status to its equivalent 4.1 registration status
1442
+	 *
1443
+	 * @param string  $payment_status                   possible value for 3.1's evens_attendee.payment_status
1444
+	 * @param boolean $this_thing_required_pre_approval whether the thing we're considering (the general setting's
1445
+	 *                                                  default payment status, the event's default payment status, or
1446
+	 *                                                  the attendee's payment status) required pre-approval.
1447
+	 * @return string STS_ID for use in 4.1
1448
+	 */
1449
+	public function convert_3_1_payment_status_to_4_1_STS_ID(
1450
+		string $payment_status,
1451
+		bool $this_thing_required_pre_approval = false
1452
+	): string {
1453
+		// EE team can read the related discussion: https://app.asana.com/0/2400967562914/9418495544455
1454
+		if ($this_thing_required_pre_approval) {
1455
+			return 'RNA';
1456
+		} else {
1457
+			$mapping = [
1458
+				'Completed'        => 'RAP',
1459
+				''                 => 'RPP',
1460
+				'Incomplete'       => 'RPP',
1461
+				'Pending'          => 'RAP',
1462
+				// stati that only occurred on 3.1 attendees:
1463
+				'Payment Declined' => 'RPP',
1464
+				'Not Completed'    => 'RPP',
1465
+				'Cancelled'        => 'RPP',
1466
+				'Declined'         => 'RPP',
1467
+			];
1468
+		}
1469
+		return $mapping[ $payment_status ] ?? 'RNA';
1470
+	}
1471
+
1472
+
1473
+	/**
1474
+	 * Makes sure the 3.1's image url is converted to an image attachment post to the 4.1 CPT event
1475
+	 * and sets it as the featured image on the CPT event
1476
+	 *
1477
+	 * @param string                         $guid
1478
+	 * @param int                            $new_cpt_id
1479
+	 * @param EE_Data_Migration_Script_Stage $migration_stage the stage which called this, where errors should be added
1480
+	 * @return boolean whether we had to do the big job of creating an image attachment
1481
+	 */
1482
+	public function convert_image_url_to_attachment_and_attach_to_post(
1483
+		string $guid,
1484
+		int $new_cpt_id,
1485
+		EE_Data_Migration_Script_Stage $migration_stage
1486
+	): bool {
1487
+		$created_attachment_post = false;
1488
+		$guid                    = $this->_get_original_guid($guid);
1489
+		if ($guid) {
1490
+			// check for an existing attachment post with this guid
1491
+			$attachment_post_id = $this->_get_image_attachment_id_by_GUID($guid);
1492
+			if (! $attachment_post_id) {
1493
+				// post thumbnail with that GUID doesn't exist, we should create one
1494
+				$attachment_post_id      = $this->_create_image_attachment_from_GUID($guid, $migration_stage);
1495
+				$created_attachment_post = true;
1496
+			}
1497
+			// double-check we actually have an attachment post
1498
+			if ($attachment_post_id) {
1499
+				update_post_meta($new_cpt_id, '_thumbnail_id', $attachment_post_id);
1500
+			} else {
1501
+				$migration_stage->add_error(
1502
+					sprintf(
1503
+						esc_html__(
1504
+							"Could not update event image %s for CPT with ID %d, but attachments post ID is %d",
1505
+							"event_espresso"
1506
+						),
1507
+						$guid,
1508
+						$new_cpt_id,
1509
+						$attachment_post_id
1510
+					)
1511
+				);
1512
+			}
1513
+		}
1514
+		return $created_attachment_post;
1515
+	}
1516
+
1517
+
1518
+	/**
1519
+	 * In 3.1, the event thumbnail image DOESN'T point to the original image, but instead
1520
+	 * to a large thumbnail (which has nearly the same GUID, except it adds "-{width}x{height}" before the filetype,
1521
+	 * or whatever dimensions it is. Eg 'http://mysite.com/image1-300x400.jpg' instead of
1522
+	 * 'http://mysite.com/image1.jpg' ). This function attempts to strip that off and get the original file, if it
1523
+	 * exists
1524
+	 *
1525
+	 * @param string $guid_in_old_event
1526
+	 * @return string either the original guid, or $guid_in_old_event if we couldn't figure out what the original was
1527
+	 */
1528
+	private function _get_original_guid(string $guid_in_old_event): string
1529
+	{
1530
+		$original_guid = preg_replace('~-\d*x\d*\.~', '.', $guid_in_old_event, 1);
1531
+		// do a head request to verify the file exists
1532
+		$head_response = wp_remote_head($original_guid);
1533
+		if (! $head_response instanceof WP_Error && $head_response['response']['message'] == 'OK') {
1534
+			return $original_guid;
1535
+		}
1536
+		return $guid_in_old_event;
1537
+	}
1538
+
1539
+
1540
+	/**
1541
+	 * Creates an image attachment post for the GUID. If the GUID points to a remote image,
1542
+	 * we download it to our uploads directory so that it can be properly processed (eg, creates different sizes of
1543
+	 * thumbnails)
1544
+	 *
1545
+	 * @param string                         $guid
1546
+	 * @param EE_Data_Migration_Script_Stage $migration_stage
1547
+	 * @return int
1548
+	 */
1549
+	private function _create_image_attachment_from_GUID(string $guid, EE_Data_Migration_Script_Stage $migration_stage)
1550
+	{
1551
+		if (! $guid) {
1552
+			$migration_stage->add_error(
1553
+				esc_html__(
1554
+					"Cannot create image attachment for a blank GUID!",
1555
+					"event_espresso"
1556
+				)
1557
+			);
1558
+			return 0;
1559
+		}
1560
+		$wp_filetype   = wp_check_filetype(basename($guid));
1561
+		$wp_upload_dir = wp_upload_dir();
1562
+		// if the file is located remotely, download it to our uploads DIR, because wp_generate_attachment_metadata
1563
+		// needs the file to be local
1564
+		if (strpos($guid, $wp_upload_dir['url']) === false) {
1565
+			// image is located remotely. download it and place it in the uploads directory
1566
+			if (! is_readable($guid)) {
1567
+				$migration_stage->add_error(
1568
+					sprintf(
1569
+						esc_html__(
1570
+							"Could not create image attachment from non-existent file: %s",
1571
+							"event_espresso"
1572
+						),
1573
+						$guid
1574
+					)
1575
+				);
1576
+				return 0;
1577
+			}
1578
+			$contents = file_get_contents($guid);
1579
+			if ($contents === false) {
1580
+				$migration_stage->add_error(
1581
+					sprintf(
1582
+						esc_html__(
1583
+							"Could not read image at %s, and therefore couldn't create an attachment post for it.",
1584
+							"event_espresso"
1585
+						),
1586
+						$guid
1587
+					)
1588
+				);
1589
+				return false;
1590
+			}
1591
+			$local_filepath = $wp_upload_dir['path'] . '/' . basename($guid);
1592
+			$save_file      = fopen($local_filepath, 'w');
1593
+			fwrite($save_file, $contents);
1594
+			fclose($save_file);
1595
+			$guid = str_replace($wp_upload_dir['path'], $wp_upload_dir['url'], $local_filepath);
1596
+		} else {
1597
+			$local_filepath = str_replace($wp_upload_dir['url'], $wp_upload_dir['path'], $guid);
1598
+		}
1599
+		$attachment = [
1600
+			'guid'           => $guid,
1601
+			'post_mime_type' => $wp_filetype['type'],
1602
+			'post_title'     => preg_replace('/\.[^.]+$/', '', basename($guid)),
1603
+			'post_content'   => '',
1604
+			'post_status'    => 'inherit',
1605
+		];
1606
+		$attach_id  = wp_insert_attachment($attachment, $guid);
1607
+		if (! $attach_id) {
1608
+			$migration_stage->add_error(
1609
+				sprintf(
1610
+					esc_html__(
1611
+						"Could not create image attachment post from image '%s'. Attachment data was %s.",
1612
+						"event_espresso"
1613
+					),
1614
+					$guid,
1615
+					$this->_json_encode($attachment)
1616
+				)
1617
+			);
1618
+			return $attach_id;
1619
+		}
1620
+		// you must first include the image.php file
1621
+		// for the function wp_generate_attachment_metadata() to work
1622
+		require_once(ABSPATH . 'wp-admin/includes/image.php');
1623
+		$attach_data = wp_generate_attachment_metadata($attach_id, $local_filepath);
1624
+		if (! $attach_data) {
1625
+			$migration_stage->add_error(
1626
+				sprintf(
1627
+					esc_html__(
1628
+						"Could not generate attachment metadata for attachment post %d with filepath %s and GUID %s. Please check the file was downloaded properly.",
1629
+						"event_espresso"
1630
+					),
1631
+					$attach_id,
1632
+					$local_filepath,
1633
+					$guid
1634
+				)
1635
+			);
1636
+			return $attach_id;
1637
+		}
1638
+		$metadata_save_result = wp_update_attachment_metadata($attach_id, $attach_data);
1639
+		if (! $metadata_save_result) {
1640
+			$migration_stage->add_error(
1641
+				sprintf(
1642
+					esc_html__(
1643
+						"Could not update attachment metadata for attachment %d with data %s",
1644
+						"event_espresso"
1645
+					),
1646
+					$attach_id,
1647
+					$this->_json_encode($attach_data)
1648
+				)
1649
+			);
1650
+		}
1651
+		return $attach_id;
1652
+	}
1653
+
1654
+
1655
+	/**
1656
+	 * Finds the attachment post containing info about an image attachment given the GUID (link to the image itself),
1657
+	 * and returns its ID.
1658
+	 *
1659
+	 * @param string $guid
1660
+	 * @return int
1661
+	 * @global wpdb  $wpdb
1662
+	 */
1663
+	private function _get_image_attachment_id_by_GUID(string $guid): int
1664
+	{
1665
+		global $wpdb;
1666
+		return (int) $wpdb->get_var($wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE guid=%s LIMIT 1", $guid));
1667
+	}
1668
+
1669
+
1670
+	/**
1671
+	 * Returns a mysql-formatted DATETIME in UTC time, given a $DATETIME_string
1672
+	 * (and optionally a timezone; if none is given, the wp default is used)
1673
+	 *
1674
+	 * @param EE_Data_Migration_Script_Stage $stage
1675
+	 * @param array                          $row_of_data , the row from the DB (as an array) we're trying to find the
1676
+	 *                                                    UTC time for
1677
+	 * @param string                         $DATETIME_string
1678
+	 * @param string|null                    $timezone
1679
+	 * @return string
1680
+	 */
1681
+	public function convert_date_string_to_utc(
1682
+		EE_Data_Migration_Script_Stage $stage,
1683
+		array $row_of_data,
1684
+		string $DATETIME_string,
1685
+		?string $timezone = null
1686
+	): string {
1687
+		$original_tz = $timezone;
1688
+		if (! $timezone) {
1689
+			$timezone = $this->_get_wp_timezone();
1690
+		}
1691
+		if (! $timezone) {
1692
+			$stage->add_error(
1693
+				sprintf(
1694
+					esc_html__("Could not find timezone given %s for %s", "event_espresso"),
1695
+					$original_tz,
1696
+					$row_of_data
1697
+				)
1698
+			);
1699
+			$timezone = 'UTC';
1700
+		}
1701
+		try {
1702
+			$date_obj = new DateTime($DATETIME_string, new DateTimeZone($timezone));
1703
+			EEH_DTT_Helper::setTimezone($date_obj, new DateTimeZone('UTC'));
1704
+		} catch (Exception $e) {
1705
+			$stage->add_error(
1706
+				sprintf(
1707
+					esc_html__(
1708
+						"Could not convert time string '%s' using timezone '%s' into a proper DATETIME. Using current time instead.",
1709
+						"event_espresso"
1710
+					),
1711
+					$DATETIME_string,
1712
+					$timezone
1713
+				)
1714
+			);
1715
+			$date_obj = new DateTime();
1716
+		}
1717
+		return $date_obj->format('Y-m-d H:i:s');
1718
+	}
1719
+
1720
+
1721
+	/**
1722
+	 * Gets the default timezone string from wordpress (even if they set a gmt offset)
1723
+	 *
1724
+	 * @return string
1725
+	 */
1726
+	private function _get_wp_timezone()
1727
+	{
1728
+		$timezone = empty($timezone) ? get_option('timezone_string') : $timezone;
1729
+		// if timezone is STILL empty then let's get the GMT offset and then set the timezone_string using our converter
1730
+		if (empty($timezone)) {
1731
+			// let's get a the WordPress UTC offset
1732
+			$offset   = (int) get_option('gmt_offset');
1733
+			$timezone = $this->timezone_convert_to_string_from_offset($offset);
1734
+		}
1735
+		return $timezone;
1736
+	}
1737
+
1738
+
1739
+	/**
1740
+	 * Gets the wordpress timezone string from a UTC offset
1741
+	 *
1742
+	 * @param int $offset
1743
+	 * @return boolean
1744
+	 */
1745
+	private function timezone_convert_to_string_from_offset(int $offset): bool
1746
+	{
1747
+		// shamelessly taken from bottom comment at http://ca1.php.net/manual/en/function.timezone-name-from-abbr.php because timezone_name_from_abbr() did not work as expected - its not reliable
1748
+		$offset        *= 3600; // convert hour offset to seconds
1749
+		$abbreviations = timezone_abbreviations_list();
1750
+		foreach ($abbreviations as $abbreviation) {
1751
+			foreach ($abbreviation as $city) {
1752
+				if ($city['offset'] == $offset) {
1753
+					return $city['timezone_id'];
1754
+				}
1755
+			}
1756
+		}
1757
+		return false;
1758
+	}
1759
+
1760
+
1761
+	public function migration_page_hooks()
1762
+	{
1763
+		add_filter(
1764
+			'FHEE__ee_migration_page__header',
1765
+			[$this, '_migrate_page_hook_simplify_version_strings'],
1766
+			10,
1767
+			3
1768
+		);
1769
+		add_filter(
1770
+			'FHEE__ee_migration_page__p_after_header',
1771
+			[$this, '_migration_page_hook_simplify_next_db_state'],
1772
+			10,
1773
+			2
1774
+		);
1775
+		add_filter(
1776
+			'FHEE__ee_migration_page__option_1_main',
1777
+			[$this, '_migrate_page_hook_simplify_version_strings'],
1778
+			10,
1779
+			3
1780
+		);
1781
+		add_filter(
1782
+			'FHEE__ee_migration_page__option_1_button_text',
1783
+			[$this, '_migrate_page_hook_simplify_version_strings'],
1784
+			10,
1785
+			3
1786
+		);
1787
+		add_action(
1788
+			'AHEE__ee_migration_page__option_1_extra_details',
1789
+			[$this, '_migration_page_hook_option_1_extra_details'],
1790
+			10,
1791
+			3
1792
+		);
1793
+		add_filter(
1794
+			'FHEE__ee_migration_page__option_2_main',
1795
+			[$this, '_migrate_page_hook_simplify_version_strings'],
1796
+			10,
1797
+			4
1798
+		);
1799
+		add_filter(
1800
+			'FHEE__ee_migration_page__option_2_button_text',
1801
+			[$this, '_migration_page_hook_simplify_next_db_state'],
1802
+			10,
1803
+			2
1804
+		);
1805
+		add_filter(
1806
+			'FHEE__ee_migration_page__option_2_details',
1807
+			[$this, '_migration_page_hook_simplify_next_db_state'],
1808
+			10,
1809
+			2
1810
+		);
1811
+		add_action(
1812
+			'AHEE__ee_migration_page__after_migration_options_table',
1813
+			[$this, '_migration_page_hook_after_migration_options_table']
1814
+		);
1815
+		add_filter(
1816
+			'FHEE__ee_migration_page__done_migration_header',
1817
+			[$this, '_migration_page_hook_simplify_next_db_state'],
1818
+			10,
1819
+			2
1820
+		);
1821
+		add_filter(
1822
+			'FHEE__ee_migration_page__p_after_done_migration_header',
1823
+			[$this, '_migration_page_hook_simplify_next_db_state'],
1824
+			10,
1825
+			2
1826
+		);
1827
+		add_filter(
1828
+			'FHEE__ee_migration_page__migration_options_template',
1829
+			[$this, 'use_migration_options_from_ee3_template']
1830
+		);
1831
+	}
1832
+
1833
+
1834
+	public function _migrate_page_hook_simplify_version_strings(
1835
+		$old_content,
1836
+		$current_db_state,
1837
+		$next_db_state,
1838
+		$ultimate_db_state = null
1839
+	) {
1840
+		return str_replace(
1841
+			[$current_db_state, $next_db_state, $ultimate_db_state],
1842
+			[
1843
+				esc_html__('EE3', 'event_espresso'),
1844
+				esc_html__('EE4', 'event_espresso'),
1845
+				esc_html__("EE4", 'event_espresso'),
1846
+			],
1847
+			$old_content
1848
+		);
1849
+	}
1850
+
1851
+
1852
+	public function _migration_page_hook_simplify_next_db_state($old_content, $next_db_state)
1853
+	{
1854
+		return str_replace($next_db_state, esc_html__("EE4", 'event_espresso'), $old_content);
1855
+	}
1856
+
1857
+
1858
+	public function _migration_page_hook_option_1_extra_details()
1859
+	{
1860
+		?>
1861 1861
         <p><?php
1862
-        printf(
1863
-            esc_html__(
1864
-                "Note: many of your EE3 shortcodes will be changed to EE4 shortcodes during this migration (among many other things). Should you revert to EE3, then you should restore to your backup or manually change the EE4 shortcodes back to their EE3 equivalents",
1865
-                "event_espresso"
1866
-            )
1867
-        ); ?></p><?php
1868
-    }
1869
-
1870
-
1871
-    public function _migration_page_hook_after_migration_options_table()
1872
-    {
1873
-        ?><p class="ee-attention">
1862
+		printf(
1863
+			esc_html__(
1864
+				"Note: many of your EE3 shortcodes will be changed to EE4 shortcodes during this migration (among many other things). Should you revert to EE3, then you should restore to your backup or manually change the EE4 shortcodes back to their EE3 equivalents",
1865
+				"event_espresso"
1866
+			)
1867
+		); ?></p><?php
1868
+	}
1869
+
1870
+
1871
+	public function _migration_page_hook_after_migration_options_table()
1872
+	{
1873
+		?><p class="ee-attention">
1874 1874
         <strong><span class="reminder-spn">
1875 1875
                 <?php
1876
-                esc_html_e(
1877
-                    "Important note to those using Event Espresso 3 addons: ",
1878
-                    "event_espresso"
1879
-                ); ?></span></strong>
1876
+				esc_html_e(
1877
+					"Important note to those using Event Espresso 3 addons: ",
1878
+					"event_espresso"
1879
+				); ?></span></strong>
1880 1880
         <br/>
1881 1881
         <?php
1882
-        esc_html_e(
1883
-            "Unless an addon's description on our website explicitly states that it is compatible with EE4, you should consider it incompatible and know that it WILL NOT WORK correctly with this new version of Event Espresso 4 (EE4). As well, any data for incompatible addons will NOT BE MIGRATED until an updated EE4 compatible version of the addon is available. If you want, or need to keep using your EE3 addons, you should simply continue using EE3 until EE4 compatible versions of your addons become available. To continue using EE3 for now, just deactivate EE4 and reactivate EE3.",
1884
-            "event_espresso"
1885
-        ); ?>
1882
+		esc_html_e(
1883
+			"Unless an addon's description on our website explicitly states that it is compatible with EE4, you should consider it incompatible and know that it WILL NOT WORK correctly with this new version of Event Espresso 4 (EE4). As well, any data for incompatible addons will NOT BE MIGRATED until an updated EE4 compatible version of the addon is available. If you want, or need to keep using your EE3 addons, you should simply continue using EE3 until EE4 compatible versions of your addons become available. To continue using EE3 for now, just deactivate EE4 and reactivate EE3.",
1884
+			"event_espresso"
1885
+		); ?>
1886 1886
         </p><?php
1887
-    }
1888
-
1889
-
1890
-    /**
1891
-     * When showing the migration options, show more options and info than normal (ie, give folks the option
1892
-     * to start using EE4 without migrating. From EE3 that's fine, because it doesn't actually remove any data, because
1893
-     * EE4 doesn't have any yet. But when migrating from EE4 it would remove old data, so its not a great idea).
1894
-     *
1895
-     * @param $template_filepath
1896
-     * @return string
1897
-     */
1898
-    public function use_migration_options_from_ee3_template($template_filepath): string
1899
-    {
1900
-        return EE_MAINTENANCE_TEMPLATE_PATH . 'migration_options_from_ee3.template.php';
1901
-    }
1887
+	}
1888
+
1889
+
1890
+	/**
1891
+	 * When showing the migration options, show more options and info than normal (ie, give folks the option
1892
+	 * to start using EE4 without migrating. From EE3 that's fine, because it doesn't actually remove any data, because
1893
+	 * EE4 doesn't have any yet. But when migrating from EE4 it would remove old data, so its not a great idea).
1894
+	 *
1895
+	 * @param $template_filepath
1896
+	 * @return string
1897
+	 */
1898
+	public function use_migration_options_from_ee3_template($template_filepath): string
1899
+	{
1900
+		return EE_MAINTENANCE_TEMPLATE_PATH . 'migration_options_from_ee3.template.php';
1901
+	}
1902 1902
 }
Please login to merge, or discard this patch.
core/data_migration_scripts/EE_DMS_Core_4_3_0.dms.php 1 patch
Indentation   +206 added lines, -206 removed lines patch added patch discarded remove patch
@@ -10,11 +10,11 @@  discard block
 block discarded – undo
10 10
 $stages            = glob(EE_CORE . 'data_migration_scripts/4_3_0_stages/*');
11 11
 $class_to_filepath = [];
12 12
 if (! empty($stages)) {
13
-    foreach ($stages as $filepath) {
14
-        $matches = [];
15
-        preg_match('~4_3_0_stages/(.*).dmsstage.php~', $filepath, $matches);
16
-        $class_to_filepath[ $matches[1] ] = $filepath;
17
-    }
13
+	foreach ($stages as $filepath) {
14
+		$matches = [];
15
+		preg_match('~4_3_0_stages/(.*).dmsstage.php~', $filepath, $matches);
16
+		$class_to_filepath[ $matches[1] ] = $filepath;
17
+	}
18 18
 }
19 19
 // give addons a chance to autoload their stages too
20 20
 $class_to_filepath = apply_filters('FHEE__EE_DMS_4_3_0__autoloaded_stages', $class_to_filepath);
@@ -30,63 +30,63 @@  discard block
 block discarded – undo
30 30
  */
31 31
 class EE_DMS_Core_4_3_0 extends EE_Data_Migration_Script_Base
32 32
 {
33
-    /**
34
-     * EE_DMS_Core_4_3_0 constructor.
35
-     *
36
-     * @param TableManager|null  $table_manager
37
-     * @param TableAnalysis|null $table_analysis
38
-     */
39
-    public function __construct(TableManager $table_manager = null, TableAnalysis $table_analysis = null)
40
-    {
41
-        $this->_pretty_name      = esc_html__("Data Update to Event Espresso 4.3.0", "event_espresso");
42
-        $this->_priority         = 10;
43
-        $this->_migration_stages = [
44
-            new EE_DMS_4_3_0_question_option_order(),
45
-            new EE_DMS_4_3_0_event_message_templates(),
46
-        ];
47
-        parent::__construct($table_manager, $table_analysis);
48
-    }
49
-
50
-
51
-    public function can_migrate_from_version($version_array)
52
-    {
53
-        $version_string = $version_array['Core'];
54
-        if (
55
-            version_compare($version_string, '4.3.0.decaf', '<') &&
56
-            version_compare($version_string, '4.2.0.decaf', '>=')
57
-        ) {
58
-            //          echo "$version_string can be migrated fro";
59
-            return true;
60
-        } elseif (! $version_string) {
61
-            //          echo "no version string provided: $version_string";
62
-            // no version string provided... this must be pre 4.2
63
-            return false;// changed mind. dont want people thinking they should migrate yet because they cant
64
-        } else {
65
-            //          echo "$version_string doesnt apply";
66
-            return false;
67
-        }
68
-    }
69
-
70
-
71
-    /**
72
-     * @throws EE_Error
73
-     * @throws ReflectionException
74
-     */
75
-    public function schema_changes_before_migration()
76
-    {
77
-        // relies on 4.1's EEH_Activation::create_table
78
-        require_once(EE_HELPERS . 'EEH_Activation.helper.php');
79
-
80
-        $table_name = 'esp_answer';
81
-        $sql        = "ANS_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
33
+	/**
34
+	 * EE_DMS_Core_4_3_0 constructor.
35
+	 *
36
+	 * @param TableManager|null  $table_manager
37
+	 * @param TableAnalysis|null $table_analysis
38
+	 */
39
+	public function __construct(TableManager $table_manager = null, TableAnalysis $table_analysis = null)
40
+	{
41
+		$this->_pretty_name      = esc_html__("Data Update to Event Espresso 4.3.0", "event_espresso");
42
+		$this->_priority         = 10;
43
+		$this->_migration_stages = [
44
+			new EE_DMS_4_3_0_question_option_order(),
45
+			new EE_DMS_4_3_0_event_message_templates(),
46
+		];
47
+		parent::__construct($table_manager, $table_analysis);
48
+	}
49
+
50
+
51
+	public function can_migrate_from_version($version_array)
52
+	{
53
+		$version_string = $version_array['Core'];
54
+		if (
55
+			version_compare($version_string, '4.3.0.decaf', '<') &&
56
+			version_compare($version_string, '4.2.0.decaf', '>=')
57
+		) {
58
+			//          echo "$version_string can be migrated fro";
59
+			return true;
60
+		} elseif (! $version_string) {
61
+			//          echo "no version string provided: $version_string";
62
+			// no version string provided... this must be pre 4.2
63
+			return false;// changed mind. dont want people thinking they should migrate yet because they cant
64
+		} else {
65
+			//          echo "$version_string doesnt apply";
66
+			return false;
67
+		}
68
+	}
69
+
70
+
71
+	/**
72
+	 * @throws EE_Error
73
+	 * @throws ReflectionException
74
+	 */
75
+	public function schema_changes_before_migration()
76
+	{
77
+		// relies on 4.1's EEH_Activation::create_table
78
+		require_once(EE_HELPERS . 'EEH_Activation.helper.php');
79
+
80
+		$table_name = 'esp_answer';
81
+		$sql        = "ANS_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
82 82
 					REG_ID int(10) unsigned NOT NULL,
83 83
 					QST_ID int(10) unsigned NOT NULL,
84 84
 					ANS_value text NOT NULL,
85 85
 					PRIMARY KEY  (ANS_ID)";
86
-        $this->_table_should_exist_previously($table_name, $sql);
86
+		$this->_table_should_exist_previously($table_name, $sql);
87 87
 
88
-        $table_name = 'esp_attendee_meta';
89
-        $sql        = "ATTM_ID int(10) unsigned NOT	NULL AUTO_INCREMENT,
88
+		$table_name = 'esp_attendee_meta';
89
+		$sql        = "ATTM_ID int(10) unsigned NOT	NULL AUTO_INCREMENT,
90 90
 						ATT_ID bigint(20) unsigned NOT NULL,
91 91
 						ATT_fname varchar(45) NOT NULL,
92 92
 						ATT_lname varchar(45) NOT	NULL,
@@ -102,10 +102,10 @@  discard block
 block discarded – undo
102 102
 								KEY ATT_fname (ATT_fname),
103 103
 								KEY ATT_lname (ATT_lname),
104 104
 								KEY ATT_email (ATT_email(191))";
105
-        $this->_table_should_exist_previously($table_name, $sql, 'ENGINE=InnoDB');
105
+		$this->_table_should_exist_previously($table_name, $sql, 'ENGINE=InnoDB');
106 106
 
107
-        $table_name = 'esp_country';
108
-        $sql        = "CNT_ISO varchar(2) COLLATE utf8_bin NOT NULL,
107
+		$table_name = 'esp_country';
108
+		$sql        = "CNT_ISO varchar(2) COLLATE utf8_bin NOT NULL,
109 109
 					  CNT_ISO3 varchar(3) COLLATE utf8_bin NOT NULL,
110 110
 					  RGN_ID tinyint(3) unsigned DEFAULT NULL,
111 111
 					  CNT_name varchar(45) COLLATE utf8_bin NOT NULL,
@@ -121,10 +121,10 @@  discard block
 block discarded – undo
121 121
 					  CNT_is_EU tinyint(1) DEFAULT '0',
122 122
 					  CNT_active tinyint(1) DEFAULT '0',
123 123
 					  PRIMARY KEY  (CNT_ISO)";
124
-        $this->_table_should_exist_previously($table_name, $sql);
124
+		$this->_table_should_exist_previously($table_name, $sql);
125 125
 
126
-        $table_name = 'esp_datetime';
127
-        $sql        = "DTT_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
126
+		$table_name = 'esp_datetime';
127
+		$sql        = "DTT_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
128 128
 				  EVT_ID bigint(20) unsigned NOT NULL,
129 129
 				  DTT_name varchar(255) NOT NULL DEFAULT '',
130 130
 				  DTT_description text NOT NULL,
@@ -139,10 +139,10 @@  discard block
 block discarded – undo
139 139
 						PRIMARY KEY  (DTT_ID),
140 140
 						KEY EVT_ID (EVT_ID),
141 141
 						KEY DTT_is_primary (DTT_is_primary)";
142
-        $this->_table_should_exist_previously($table_name, $sql);
142
+		$this->_table_should_exist_previously($table_name, $sql);
143 143
 
144
-        $table_name = 'esp_event_meta';
145
-        $sql        = "
144
+		$table_name = 'esp_event_meta';
145
+		$sql        = "
146 146
 			EVTM_ID int(10) NOT NULL AUTO_INCREMENT,
147 147
 			EVT_ID bigint(20) unsigned NOT NULL,
148 148
 			EVT_display_desc tinyint(1) unsigned NOT NULL DEFAULT 1,
@@ -157,35 +157,35 @@  discard block
 block discarded – undo
157 157
 			EVT_external_URL varchar(200) NULL,
158 158
 			EVT_donations tinyint(1) NULL,
159 159
 			PRIMARY KEY  (EVTM_ID)";
160
-        $this->_table_should_exist_previously($table_name, $sql);
160
+		$this->_table_should_exist_previously($table_name, $sql);
161 161
 
162
-        $table_name = 'esp_event_question_group';
163
-        $sql        = "EQG_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
162
+		$table_name = 'esp_event_question_group';
163
+		$sql        = "EQG_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
164 164
 					EVT_ID bigint(20) unsigned NOT NULL,
165 165
 					QSG_ID int(10) unsigned NOT NULL,
166 166
 					EQG_primary tinyint(1) unsigned NOT NULL DEFAULT 0,
167 167
 					PRIMARY KEY  (EQG_ID)";
168
-        $this->_table_should_exist_previously($table_name, $sql);
168
+		$this->_table_should_exist_previously($table_name, $sql);
169 169
 
170
-        $table_name = 'esp_event_venue';
171
-        $sql        = "EVV_ID int(11) NOT NULL AUTO_INCREMENT,
170
+		$table_name = 'esp_event_venue';
171
+		$sql        = "EVV_ID int(11) NOT NULL AUTO_INCREMENT,
172 172
 				EVT_ID bigint(20) unsigned NOT NULL,
173 173
 				VNU_ID bigint(20) unsigned NOT NULL,
174 174
 				EVV_primary tinyint(1) unsigned NOT NULL DEFAULT 0,
175 175
 				PRIMARY KEY  (EVV_ID)";
176
-        $this->_table_should_exist_previously($table_name, $sql);
176
+		$this->_table_should_exist_previously($table_name, $sql);
177 177
 
178
-        $table_name = 'esp_extra_meta';
179
-        $sql        = "EXM_ID int(11) NOT NULL AUTO_INCREMENT,
178
+		$table_name = 'esp_extra_meta';
179
+		$sql        = "EXM_ID int(11) NOT NULL AUTO_INCREMENT,
180 180
 				OBJ_ID int(11) DEFAULT NULL,
181 181
 				EXM_type varchar(45) DEFAULT NULL,
182 182
 				EXM_key varchar(45) DEFAULT NULL,
183 183
 				EXM_value text,
184 184
 				PRIMARY KEY  (EXM_ID)";
185
-        $this->_table_should_exist_previously($table_name, $sql);
185
+		$this->_table_should_exist_previously($table_name, $sql);
186 186
 
187
-        $table_name = 'esp_line_item';
188
-        $sql        = "LIN_ID int(11) NOT NULL AUTO_INCREMENT,
187
+		$table_name = 'esp_line_item';
188
+		$sql        = "LIN_ID int(11) NOT NULL AUTO_INCREMENT,
189 189
 				LIN_code varchar(245) NOT NULL DEFAULT '',
190 190
 				TXN_ID int(11) DEFAULT NULL,
191 191
 				LIN_name varchar(245) NOT NULL DEFAULT '',
@@ -201,21 +201,21 @@  discard block
 block discarded – undo
201 201
 				OBJ_ID int(11) DEFAULT NULL,
202 202
 				OBJ_type varchar(45)DEFAULT NULL,
203 203
 				PRIMARY KEY  (LIN_ID)";
204
-        $this->_table_should_exist_previously($table_name, $sql);
204
+		$this->_table_should_exist_previously($table_name, $sql);
205 205
 
206
-        $table_name = 'esp_message_template';
207
-        $sql        = "MTP_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
206
+		$table_name = 'esp_message_template';
207
+		$sql        = "MTP_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
208 208
 					GRP_ID int(10) unsigned NOT NULL,
209 209
 					MTP_context varchar(50) NOT NULL,
210 210
 					MTP_template_field varchar(30) NOT NULL,
211 211
 					MTP_content text NOT NULL,
212 212
 					PRIMARY KEY  (MTP_ID),
213 213
 					KEY GRP_ID (GRP_ID)";
214
-        $this->_table_should_exist_previously($table_name, $sql);
215
-        $this->_get_table_manager()->dropIndex('esp_message_template_group', 'EVT_ID');
214
+		$this->_table_should_exist_previously($table_name, $sql);
215
+		$this->_get_table_manager()->dropIndex('esp_message_template_group', 'EVT_ID');
216 216
 
217
-        $table_name = 'esp_message_template_group';
218
-        $sql        = "GRP_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
217
+		$table_name = 'esp_message_template_group';
218
+		$sql        = "GRP_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
219 219
 					MTP_user_id int(10) NOT NULL DEFAULT '1',
220 220
 					MTP_name varchar(245) NOT NULL DEFAULT '',
221 221
 					MTP_description varchar(245) NOT NULL DEFAULT '',
@@ -227,19 +227,19 @@  discard block
 block discarded – undo
227 227
 					MTP_is_active tinyint(1) NOT NULL DEFAULT '1',
228 228
 					PRIMARY KEY  (GRP_ID),
229 229
 					KEY MTP_user_id (MTP_user_id)";
230
-        $this->_table_should_exist_previously($table_name, $sql);
230
+		$this->_table_should_exist_previously($table_name, $sql);
231 231
 
232
-        $table_name = 'esp_event_message_template';
233
-        $sql        = "EMT_ID bigint(20) unsigned NOT NULL AUTO_INCREMENT,
232
+		$table_name = 'esp_event_message_template';
233
+		$sql        = "EMT_ID bigint(20) unsigned NOT NULL AUTO_INCREMENT,
234 234
 					EVT_ID bigint(20) unsigned NOT NULL DEFAULT 0,
235 235
 					GRP_ID int(10) unsigned NOT NULL DEFAULT 0,
236 236
 					PRIMARY KEY  (EMT_ID),
237 237
 					KEY EVT_ID (EVT_ID),
238 238
 					KEY GRP_ID (GRP_ID)";
239
-        $this->_table_is_new_in_this_version($table_name, $sql);
239
+		$this->_table_is_new_in_this_version($table_name, $sql);
240 240
 
241
-        $table_name = 'esp_payment';
242
-        $sql        = "PAY_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
241
+		$table_name = 'esp_payment';
242
+		$sql        = "PAY_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
243 243
 					TXN_ID int(10) unsigned DEFAULT NULL,
244 244
 					STS_ID varchar(3) COLLATE utf8_bin DEFAULT NULL,
245 245
 					PAY_timestamp datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
@@ -255,10 +255,10 @@  discard block
 block discarded – undo
255 255
 					PRIMARY KEY  (PAY_ID),
256 256
 					KEY TXN_ID (TXN_ID),
257 257
 					KEY PAY_timestamp (PAY_timestamp)";
258
-        $this->_table_should_exist_previously($table_name, $sql, 'ENGINE=InnoDB');
258
+		$this->_table_should_exist_previously($table_name, $sql, 'ENGINE=InnoDB');
259 259
 
260
-        $table_name = "esp_ticket";
261
-        $sql        = "TKT_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
260
+		$table_name = "esp_ticket";
261
+		$sql        = "TKT_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
262 262
 					  TTM_ID int(10) unsigned NOT NULL,
263 263
 					  TKT_name varchar(245) NOT NULL DEFAULT '',
264 264
 					  TKT_description text NOT NULL,
@@ -278,32 +278,32 @@  discard block
 block discarded – undo
278 278
 					  TKT_parent int(10) unsigned DEFAULT '0',
279 279
 					  TKT_deleted tinyint(1) NOT NULL DEFAULT '0',
280 280
 					  PRIMARY KEY  (TKT_ID)";
281
-        $this->_table_should_exist_previously($table_name, $sql);
281
+		$this->_table_should_exist_previously($table_name, $sql);
282 282
 
283
-        $table_name = "esp_ticket_price";
284
-        $sql        = "TKP_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
283
+		$table_name = "esp_ticket_price";
284
+		$sql        = "TKP_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
285 285
 					  TKT_ID int(10) unsigned NOT NULL,
286 286
 					  PRC_ID int(10) unsigned NOT NULL,
287 287
 					  PRIMARY KEY  (TKP_ID)";
288
-        $this->_table_should_exist_previously($table_name, $sql);
288
+		$this->_table_should_exist_previously($table_name, $sql);
289 289
 
290
-        $table_name = "esp_datetime_ticket";
291
-        $sql        = "DTK_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
290
+		$table_name = "esp_datetime_ticket";
291
+		$sql        = "DTK_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
292 292
 					  DTT_ID int(10) unsigned NOT NULL,
293 293
 					  TKT_ID int(10) unsigned NOT NULL,
294 294
 					  PRIMARY KEY  (DTK_ID)";
295
-        $this->_table_should_exist_previously($table_name, $sql);
295
+		$this->_table_should_exist_previously($table_name, $sql);
296 296
 
297
-        $table_name = "esp_ticket_template";
298
-        $sql        = "TTM_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
297
+		$table_name = "esp_ticket_template";
298
+		$sql        = "TTM_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
299 299
 					  TTM_name varchar(45) NOT NULL,
300 300
 					  TTM_description text,
301 301
 					  TTM_file varchar(45),
302 302
 					  PRIMARY KEY  (TTM_ID)";
303
-        $this->_table_should_exist_previously($table_name, $sql);
303
+		$this->_table_should_exist_previously($table_name, $sql);
304 304
 
305
-        $table_name = "esp_price";
306
-        $sql        = "PRC_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
305
+		$table_name = "esp_price";
306
+		$sql        = "PRC_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
307 307
 					  PRT_ID tinyint(3) unsigned NOT NULL,
308 308
 					  PRC_amount decimal(10,3) NOT NULL DEFAULT '0.00',
309 309
 					  PRC_name varchar(245) NOT NULL,
@@ -314,10 +314,10 @@  discard block
 block discarded – undo
314 314
 					  PRC_order tinyint(3) unsigned NOT NULL DEFAULT '0',
315 315
 					  PRC_parent int(10) unsigned DEFAULT 0,
316 316
 					  PRIMARY KEY  (PRC_ID)";
317
-        $this->_table_should_exist_previously($table_name, $sql);
317
+		$this->_table_should_exist_previously($table_name, $sql);
318 318
 
319
-        $table_name = "esp_price_type";
320
-        $sql        = "PRT_ID tinyint(3) unsigned NOT NULL AUTO_INCREMENT,
319
+		$table_name = "esp_price_type";
320
+		$sql        = "PRT_ID tinyint(3) unsigned NOT NULL AUTO_INCREMENT,
321 321
 				  PRT_name varchar(45) NOT NULL,
322 322
 				  PBT_ID tinyint(3) unsigned NOT NULL DEFAULT '1',
323 323
 				  PRT_is_percent tinyint(1) NOT NULL DEFAULT '0',
@@ -325,10 +325,10 @@  discard block
 block discarded – undo
325 325
 				  PRT_deleted tinyint(1) NOT NULL DEFAULT '0',
326 326
 				  UNIQUE KEY PRT_name_UNIQUE (PRT_name),
327 327
 				  PRIMARY KEY  (PRT_ID)";
328
-        $this->_table_should_exist_previously($table_name, $sql);
328
+		$this->_table_should_exist_previously($table_name, $sql);
329 329
 
330
-        $table_name = 'esp_question';
331
-        $sql        = 'QST_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
330
+		$table_name = 'esp_question';
331
+		$sql        = 'QST_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
332 332
 					QST_display_text text NOT NULL,
333 333
 					QST_admin_label varchar(255) NOT NULL,
334 334
 					QST_system varchar(25) DEFAULT NULL,
@@ -340,11 +340,11 @@  discard block
 block discarded – undo
340 340
 					QST_wp_user bigint(20) unsigned NULL,
341 341
 					QST_deleted tinyint(1) unsigned NOT NULL DEFAULT 0,
342 342
 					PRIMARY KEY  (QST_ID)';
343
-        $this->_table_should_exist_previously($table_name, $sql);
344
-        $this->_get_table_manager()->dropIndex('esp_question_group', 'QSG_identifier_UNIQUE');
343
+		$this->_table_should_exist_previously($table_name, $sql);
344
+		$this->_get_table_manager()->dropIndex('esp_question_group', 'QSG_identifier_UNIQUE');
345 345
 
346
-        $table_name = 'esp_question_group';
347
-        $sql        = 'QSG_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
346
+		$table_name = 'esp_question_group';
347
+		$sql        = 'QSG_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
348 348
 					QSG_name varchar(255) NOT NULL,
349 349
 					QSG_identifier varchar(100) NOT NULL,
350 350
 					QSG_desc text NULL,
@@ -355,28 +355,28 @@  discard block
 block discarded – undo
355 355
 					QSG_deleted tinyint(1) unsigned NOT NULL DEFAULT 0,
356 356
 					PRIMARY KEY  (QSG_ID),
357 357
 					UNIQUE KEY QSG_identifier_UNIQUE (QSG_identifier ASC)';
358
-        $this->_table_should_exist_previously($table_name, $sql);
358
+		$this->_table_should_exist_previously($table_name, $sql);
359 359
 
360
-        $table_name = 'esp_question_group_question';
361
-        $sql        = "QGQ_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
360
+		$table_name = 'esp_question_group_question';
361
+		$sql        = "QGQ_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
362 362
 					QSG_ID int(10) unsigned NOT NULL,
363 363
 					QST_ID int(10) unsigned NOT NULL,
364 364
 					QGQ_order int(10) unsigned NOT NULL DEFAULT 0,
365 365
 					PRIMARY KEY  (QGQ_ID) ";
366
-        $this->_table_should_exist_previously($table_name, $sql);
366
+		$this->_table_should_exist_previously($table_name, $sql);
367 367
 
368
-        $table_name = 'esp_question_option';
369
-        $sql        = "QSO_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
368
+		$table_name = 'esp_question_option';
369
+		$sql        = "QSO_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
370 370
 					QSO_value varchar(255) NOT NULL,
371 371
 					QSO_desc text NOT NULL,
372 372
 					QST_ID int(10) unsigned NOT NULL,
373 373
 					QSO_order int(10) unsigned NOT NULL DEFAULT 0,
374 374
 					QSO_deleted tinyint(1) unsigned NOT NULL DEFAULT 0,
375 375
 					PRIMARY KEY  (QSO_ID)";
376
-        $this->_table_should_exist_previously($table_name, $sql);
376
+		$this->_table_should_exist_previously($table_name, $sql);
377 377
 
378
-        $table_name = 'esp_registration';
379
-        $sql        = "REG_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
378
+		$table_name = 'esp_registration';
379
+		$sql        = "REG_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
380 380
 					  EVT_ID bigint(20) unsigned NOT NULL,
381 381
 					  ATT_ID bigint(20) unsigned NOT NULL,
382 382
 					  TXN_ID int(10) unsigned NOT NULL,
@@ -399,28 +399,28 @@  discard block
 block discarded – undo
399 399
 					  KEY STS_ID (STS_ID),
400 400
 					  KEY REG_url_link (REG_url_link),
401 401
 					  KEY REG_code (REG_code)";
402
-        $this->_table_should_exist_previously($table_name, $sql, 'ENGINE=InnoDB');
402
+		$this->_table_should_exist_previously($table_name, $sql, 'ENGINE=InnoDB');
403 403
 
404
-        $table_name = 'esp_checkin';
405
-        $sql        = "CHK_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
404
+		$table_name = 'esp_checkin';
405
+		$sql        = "CHK_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
406 406
 					REG_ID int(10) unsigned NOT NULL,
407 407
 					DTT_ID int(10) unsigned NOT NULL,
408 408
 					CHK_in tinyint(1) unsigned NOT NULL DEFAULT 1,
409 409
 					CHK_timestamp datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
410 410
 					PRIMARY KEY  (CHK_ID)";
411
-        $this->_table_should_exist_previously($table_name, $sql);
411
+		$this->_table_should_exist_previously($table_name, $sql);
412 412
 
413
-        $table_name = 'esp_state';
414
-        $sql        = "STA_ID smallint(5) unsigned NOT NULL AUTO_INCREMENT,
413
+		$table_name = 'esp_state';
414
+		$sql        = "STA_ID smallint(5) unsigned NOT NULL AUTO_INCREMENT,
415 415
 					  CNT_ISO varchar(2) COLLATE utf8_bin NOT NULL,
416 416
 					  STA_abbrev varchar(6) COLLATE utf8_bin NOT NULL,
417 417
 					  STA_name varchar(100) COLLATE utf8_bin NOT NULL,
418 418
 					  STA_active tinyint(1) DEFAULT '1',
419 419
 					  PRIMARY KEY  (STA_ID)";
420
-        $this->_table_should_exist_previously($table_name, $sql);
420
+		$this->_table_should_exist_previously($table_name, $sql);
421 421
 
422
-        $table_name = 'esp_status';
423
-        $sql        = "STS_ID varchar(3) COLLATE utf8_bin NOT NULL,
422
+		$table_name = 'esp_status';
423
+		$sql        = "STS_ID varchar(3) COLLATE utf8_bin NOT NULL,
424 424
 					  STS_code varchar(45) COLLATE utf8_bin NOT NULL,
425 425
 					  STS_type set('event','registration','transaction','payment','email') COLLATE utf8_bin NOT NULL,
426 426
 					  STS_can_edit tinyint(1) NOT NULL DEFAULT 0,
@@ -428,10 +428,10 @@  discard block
 block discarded – undo
428 428
 					  STS_open tinyint(1) NOT NULL DEFAULT 1,
429 429
 					  UNIQUE KEY STS_ID_UNIQUE (STS_ID),
430 430
 					  KEY STS_type (STS_type)";
431
-        $this->_table_should_exist_previously($table_name, $sql);
431
+		$this->_table_should_exist_previously($table_name, $sql);
432 432
 
433
-        $table_name = 'esp_transaction';
434
-        $sql        = "TXN_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
433
+		$table_name = 'esp_transaction';
434
+		$sql        = "TXN_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
435 435
 					  TXN_timestamp datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
436 436
 					  TXN_total decimal(10,3) DEFAULT '0.00',
437 437
 					  TXN_paid decimal(10,3) NOT NULL DEFAULT '0.00',
@@ -441,10 +441,10 @@  discard block
 block discarded – undo
441 441
 					  PRIMARY KEY  (TXN_ID),
442 442
 					  KEY TXN_timestamp (TXN_timestamp),
443 443
 					  KEY STS_ID (STS_ID)";
444
-        $this->_table_should_exist_previously($table_name, $sql);
444
+		$this->_table_should_exist_previously($table_name, $sql);
445 445
 
446
-        $table_name = 'esp_venue_meta';
447
-        $sql        = "VNUM_ID int(11) NOT NULL AUTO_INCREMENT,
446
+		$table_name = 'esp_venue_meta';
447
+		$sql        = "VNUM_ID int(11) NOT NULL AUTO_INCREMENT,
448 448
 			VNU_ID bigint(20) unsigned NOT NULL DEFAULT 0,
449 449
 			VNU_address varchar(255) DEFAULT NULL,
450 450
 			VNU_address2 varchar(255) DEFAULT NULL,
@@ -462,75 +462,75 @@  discard block
 block discarded – undo
462 462
 			PRIMARY KEY  (VNUM_ID),
463 463
 			KEY STA_ID (STA_ID),
464 464
 			KEY CNT_ISO (CNT_ISO)";
465
-        $this->_table_should_exist_previously($table_name, $sql);
466
-        $script_with_defaults = EE_Registry::instance()->load_dms('Core_4_1_0');
467
-        // setting up the DEFAULT stats and countries is also essential for the data migrations to run
468
-        // (because many need to convert old string states to foreign keys into the states table)
469
-        $script_with_defaults->insert_default_states();
470
-        $script_with_defaults->insert_default_countries();
471
-        // setting up DEFAULT prices, price types, and tickets is also essential for the price migrations
472
-        $script_with_defaults->insert_default_price_types();
473
-        $script_with_defaults->insert_default_prices();
474
-        // but the schema on the tickets table has changed since 4.1, so use our DEFAULT ticket method instead of 4.1's
475
-        $this->insert_default_tickets();
476
-        // setting up the config wp option pretty well counts as a 'schema change', or at least should happen here
477
-        EE_Config::instance()->update_espresso_config();
478
-        return true;
479
-    }
480
-
481
-
482
-    /**
483
-     * @return boolean
484
-     */
485
-    public function schema_changes_after_migration()
486
-    {
487
-        return true;
488
-    }
489
-
490
-
491
-    public function migration_page_hooks()
492
-    {
493
-    }
494
-
495
-
496
-    /**
497
-     * insert DEFAULT ticket
498
-     * Almost identical to EE_DMS_Core_4_1_0::insert_default_tickets, except is aware of the TKT_required field
499
-     *
500
-     * @access public
501
-     * @static
502
-     * @return void
503
-     * @throws EE_Error
504
-     */
505
-    public function insert_default_tickets()
506
-    {
507
-        global $wpdb;
508
-        $ticket_table = $wpdb->prefix . "esp_ticket";
509
-        if ($this->_get_table_analysis()->tableExists($ticket_table)) {
510
-            $SQL           = 'SELECT COUNT(TKT_ID) FROM ' . $ticket_table;
511
-            $tickets_exist = $wpdb->get_var($SQL);
512
-            if (! $tickets_exist) {
513
-                $SQL = "INSERT INTO $ticket_table
465
+		$this->_table_should_exist_previously($table_name, $sql);
466
+		$script_with_defaults = EE_Registry::instance()->load_dms('Core_4_1_0');
467
+		// setting up the DEFAULT stats and countries is also essential for the data migrations to run
468
+		// (because many need to convert old string states to foreign keys into the states table)
469
+		$script_with_defaults->insert_default_states();
470
+		$script_with_defaults->insert_default_countries();
471
+		// setting up DEFAULT prices, price types, and tickets is also essential for the price migrations
472
+		$script_with_defaults->insert_default_price_types();
473
+		$script_with_defaults->insert_default_prices();
474
+		// but the schema on the tickets table has changed since 4.1, so use our DEFAULT ticket method instead of 4.1's
475
+		$this->insert_default_tickets();
476
+		// setting up the config wp option pretty well counts as a 'schema change', or at least should happen here
477
+		EE_Config::instance()->update_espresso_config();
478
+		return true;
479
+	}
480
+
481
+
482
+	/**
483
+	 * @return boolean
484
+	 */
485
+	public function schema_changes_after_migration()
486
+	{
487
+		return true;
488
+	}
489
+
490
+
491
+	public function migration_page_hooks()
492
+	{
493
+	}
494
+
495
+
496
+	/**
497
+	 * insert DEFAULT ticket
498
+	 * Almost identical to EE_DMS_Core_4_1_0::insert_default_tickets, except is aware of the TKT_required field
499
+	 *
500
+	 * @access public
501
+	 * @static
502
+	 * @return void
503
+	 * @throws EE_Error
504
+	 */
505
+	public function insert_default_tickets()
506
+	{
507
+		global $wpdb;
508
+		$ticket_table = $wpdb->prefix . "esp_ticket";
509
+		if ($this->_get_table_analysis()->tableExists($ticket_table)) {
510
+			$SQL           = 'SELECT COUNT(TKT_ID) FROM ' . $ticket_table;
511
+			$tickets_exist = $wpdb->get_var($SQL);
512
+			if (! $tickets_exist) {
513
+				$SQL = "INSERT INTO $ticket_table
514 514
 					( TKT_ID, TTM_ID, TKT_name, TKT_description, TKT_qty, TKT_sold, TKT_uses, TKT_required, TKT_min, TKT_max, TKT_price, TKT_start_date, TKT_end_date, TKT_taxable, TKT_order, TKT_row, TKT_is_default, TKT_parent, TKT_deleted ) VALUES
515 515
 					( 1, 0, '" .
516
-                       esc_html__("Free Ticket", "event_espresso") .
517
-                       "', '', 100, 0, -1, 0, 0, -1, 0.00, '0000-00-00 00:00:00', '0000-00-00 00:00:00', 0, 0, 1, 1, 0, 0);";
518
-                $SQL = apply_filters('FHEE__EE_DMS_4_1_0__insert_default_tickets__SQL', $SQL);
519
-                $wpdb->query($SQL);
520
-            }
521
-        }
522
-        $ticket_price_table = $wpdb->prefix . "esp_ticket_price";
523
-        if ($this->_get_table_analysis()->tableExists($ticket_price_table)) {
524
-            $SQL              = 'SELECT COUNT(TKP_ID) FROM ' . $ticket_price_table;
525
-            $ticket_prc_exist = $wpdb->get_var($SQL);
526
-            if (! $ticket_prc_exist) {
527
-                $SQL = "INSERT INTO $ticket_price_table
516
+					   esc_html__("Free Ticket", "event_espresso") .
517
+					   "', '', 100, 0, -1, 0, 0, -1, 0.00, '0000-00-00 00:00:00', '0000-00-00 00:00:00', 0, 0, 1, 1, 0, 0);";
518
+				$SQL = apply_filters('FHEE__EE_DMS_4_1_0__insert_default_tickets__SQL', $SQL);
519
+				$wpdb->query($SQL);
520
+			}
521
+		}
522
+		$ticket_price_table = $wpdb->prefix . "esp_ticket_price";
523
+		if ($this->_get_table_analysis()->tableExists($ticket_price_table)) {
524
+			$SQL              = 'SELECT COUNT(TKP_ID) FROM ' . $ticket_price_table;
525
+			$ticket_prc_exist = $wpdb->get_var($SQL);
526
+			if (! $ticket_prc_exist) {
527
+				$SQL = "INSERT INTO $ticket_price_table
528 528
 				( TKP_ID, TKT_ID, PRC_ID ) VALUES
529 529
 				( 1, 1, 1 )
530 530
 				";
531
-                $SQL = apply_filters('FHEE__EE_DMS_4_1_0__insert_default_tickets__SQL__ticket_price', $SQL);
532
-                $wpdb->query($SQL);
533
-            }
534
-        }
535
-    }
531
+				$SQL = apply_filters('FHEE__EE_DMS_4_1_0__insert_default_tickets__SQL__ticket_price', $SQL);
532
+				$wpdb->query($SQL);
533
+			}
534
+		}
535
+	}
536 536
 }
Please login to merge, or discard this patch.
4_2_0_stages/EE_DMS_4_2_0_question_group_questions.dmsstage.php 1 patch
Indentation   +37 added lines, -37 removed lines patch added patch discarded remove patch
@@ -6,45 +6,45 @@
 block discarded – undo
6 6
 
7 7
 class EE_DMS_4_2_0_question_group_questions extends EE_Data_Migration_Script_Stage_Table
8 8
 {
9
-    private string $_qgq_table;
9
+	private string $_qgq_table;
10 10
 
11 11
 
12
-    public function __construct()
13
-    {
14
-        global $wpdb;
15
-        $this->_pretty_name = esc_html__("Question Group Questions", "event_espresso");
16
-        $this->_old_table   = $wpdb->prefix . "esp_question";
17
-        $this->_qgq_table   = $wpdb->prefix . "esp_question_group_question";
18
-        parent::__construct();
19
-    }
12
+	public function __construct()
13
+	{
14
+		global $wpdb;
15
+		$this->_pretty_name = esc_html__("Question Group Questions", "event_espresso");
16
+		$this->_old_table   = $wpdb->prefix . "esp_question";
17
+		$this->_qgq_table   = $wpdb->prefix . "esp_question_group_question";
18
+		parent::__construct();
19
+	}
20 20
 
21 21
 
22
-    protected function _migrate_old_row($old_row)
23
-    {
24
-        // foreach question_group_question entry with this QST_ID, we want to set its
25
-        // QSG_order equal to this question's QST_order
26
-        global $wpdb;
27
-        $updated = $wpdb->update(
28
-            $this->_qgq_table,
29
-            ['QGQ_order' => $old_row['QST_order']],
30
-            ['QST_ID' => $old_row['QST_ID']],
31
-            ['%d'],
32
-            // QGQ_order
33
-            ['%d']                                                                            // QST_ID
34
-        );
35
-        if (false === $updated) {
36
-            $this->add_error(
37
-                sprintf(
38
-                    esc_html__(
39
-                        "Error in updating table %s setting QGQ_order = %d where QST_ID = %d",
40
-                        'event_espresso'
41
-                    ),
42
-                    $this->_qgq_table,
43
-                    $old_row['QST_order'],
44
-                    $old_row['QST_ID']
45
-                )
46
-            );
47
-        }
48
-        // nothing to map really
49
-    }
22
+	protected function _migrate_old_row($old_row)
23
+	{
24
+		// foreach question_group_question entry with this QST_ID, we want to set its
25
+		// QSG_order equal to this question's QST_order
26
+		global $wpdb;
27
+		$updated = $wpdb->update(
28
+			$this->_qgq_table,
29
+			['QGQ_order' => $old_row['QST_order']],
30
+			['QST_ID' => $old_row['QST_ID']],
31
+			['%d'],
32
+			// QGQ_order
33
+			['%d']                                                                            // QST_ID
34
+		);
35
+		if (false === $updated) {
36
+			$this->add_error(
37
+				sprintf(
38
+					esc_html__(
39
+						"Error in updating table %s setting QGQ_order = %d where QST_ID = %d",
40
+						'event_espresso'
41
+					),
42
+					$this->_qgq_table,
43
+					$old_row['QST_order'],
44
+					$old_row['QST_ID']
45
+				)
46
+			);
47
+		}
48
+		// nothing to map really
49
+	}
50 50
 }
Please login to merge, or discard this patch.
4_2_0_stages/EE_DMS_4_2_0_datetime_fields.dmsstage.php 2 patches
Indentation   +43 added lines, -43 removed lines patch added patch discarded remove patch
@@ -8,50 +8,50 @@
 block discarded – undo
8 8
 
9 9
 class EE_DMS_4_2_0_datetime_fields extends EE_Data_Migration_Script_Stage_Table
10 10
 {
11
-    public function __construct()
12
-    {
13
-        global $wpdb;
14
-        $this->_pretty_name = esc_html__("Datetime Fields", "event_espresso");
15
-        $this->_old_table   = $wpdb->prefix . "esp_datetime";
16
-        parent::__construct();
17
-    }
11
+	public function __construct()
12
+	{
13
+		global $wpdb;
14
+		$this->_pretty_name = esc_html__("Datetime Fields", "event_espresso");
15
+		$this->_old_table   = $wpdb->prefix . "esp_datetime";
16
+		parent::__construct();
17
+	}
18 18
 
19 19
 
20
-    protected function _migrate_old_row($old_row)
21
-    {
22
-        // foreach question_group_question entry with this QST_ID, we want to set its
23
-        // QSG_order equal to this question's QST_order
24
-        global $wpdb;
20
+	protected function _migrate_old_row($old_row)
21
+	{
22
+		// foreach question_group_question entry with this QST_ID, we want to set its
23
+		// QSG_order equal to this question's QST_order
24
+		global $wpdb;
25 25
 
26
-        $updated = $wpdb->update(
27
-            $this->_old_table,
28
-            [
29
-                                 'DTT_name' => '',
30
-                                 'DTT_description' => '',
31
-                             ],
32
-            [
33
-                'DTT_ID' => $old_row['DTT_ID'],
34
-            ],
35
-            [
36
-                '%s',// DTT_name,
37
-                '%s',// DTT_description
38
-            ],
39
-            [
40
-                '%d',// DTT_ID
41
-            ]
42
-        );
43
-        if (false === $updated) {
44
-            $this->add_error(
45
-                sprintf(
46
-                    esc_html__(
47
-                        "Error in updating table %s setting DTT_name = '' and DTT_description = '' where DTT_ID = %d",
48
-                        'event_espresso'
49
-                    ),
50
-                    $this->_old_table,
51
-                    $old_row['QST_ID']
52
-                )
53
-            );
54
-        }
55
-        // nothing to map really
56
-    }
26
+		$updated = $wpdb->update(
27
+			$this->_old_table,
28
+			[
29
+								 'DTT_name' => '',
30
+								 'DTT_description' => '',
31
+							 ],
32
+			[
33
+				'DTT_ID' => $old_row['DTT_ID'],
34
+			],
35
+			[
36
+				'%s',// DTT_name,
37
+				'%s',// DTT_description
38
+			],
39
+			[
40
+				'%d',// DTT_ID
41
+			]
42
+		);
43
+		if (false === $updated) {
44
+			$this->add_error(
45
+				sprintf(
46
+					esc_html__(
47
+						"Error in updating table %s setting DTT_name = '' and DTT_description = '' where DTT_ID = %d",
48
+						'event_espresso'
49
+					),
50
+					$this->_old_table,
51
+					$old_row['QST_ID']
52
+				)
53
+			);
54
+		}
55
+		// nothing to map really
56
+	}
57 57
 }
Please login to merge, or discard this patch.
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -12,7 +12,7 @@  discard block
 block discarded – undo
12 12
     {
13 13
         global $wpdb;
14 14
         $this->_pretty_name = esc_html__("Datetime Fields", "event_espresso");
15
-        $this->_old_table   = $wpdb->prefix . "esp_datetime";
15
+        $this->_old_table   = $wpdb->prefix."esp_datetime";
16 16
         parent::__construct();
17 17
     }
18 18
 
@@ -33,11 +33,11 @@  discard block
 block discarded – undo
33 33
                 'DTT_ID' => $old_row['DTT_ID'],
34 34
             ],
35 35
             [
36
-                '%s',// DTT_name,
37
-                '%s',// DTT_description
36
+                '%s', // DTT_name,
37
+                '%s', // DTT_description
38 38
             ],
39 39
             [
40
-                '%d',// DTT_ID
40
+                '%d', // DTT_ID
41 41
             ]
42 42
         );
43 43
         if (false === $updated) {
Please login to merge, or discard this patch.