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